File Coverage

blib/lib/Text/Placeholder.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package Text::Placeholder;
2              
3 7     7   122332 use strict;
  7         19  
  7         289  
4 7     7   41 use warnings;
  7         14  
  7         361  
5 7     7   41 use Carp qw();
  7         17  
  7         143  
6 7         38 use parent qw(
7 7     7   6676 Object::By::Array);
  7         2303  
8              
9             our $VERSION = '0.04';
10              
11             sub P_PLACEHOLDER_RE() { 0 }
12             sub build_parser($) {
13             my $placeholder_re = $_[P_PLACEHOLDER_RE];
14             $placeholder_re =~ s,/,\\/,sg;
15             my $parser = eval "sub {
16             return unless(\$_[0] =~ s/$placeholder_re//s);
17             return(\$1, \$2);
18             };";
19             Carp::confess($@) if ($@);
20             return($parser);
21             }
22             my $default_parser = build_parser('^(.*?)\[=([^=\]]+)=\]');
23              
24             sub THIS() { 0 }
25              
26             sub ATR_PARSER() { 0 }
27             sub ATR_GROUPS() { 1 }
28             sub ATR_COLLECTOR() { 2 }
29              
30             sub _init {
31             my $this = shift;
32              
33             if (ref($_[0]) eq 'CODE') {
34             $this->[ATR_PARSER] = shift;
35             # } elsif ($_[0] =~ m,[^\w\:],s) {
36             # $this->[ATR_PARSER] = build_parser(shift);
37             } else {
38             $this->[ATR_PARSER] = $default_parser;
39             }
40             $this->[ATR_GROUPS] = [];
41             $this->[ATR_COLLECTOR] = undef;
42             $this->add_group(@_);
43              
44             return;
45             }
46              
47             sub P_PARSER() { 1 }
48             sub parser {
49             if(exists($_[P_PARSER])) {
50             $_[THIS][ATR_PARSER] = (ref($_[P_PARSER]) eq '')
51             ? build_parser($_[P_PARSER])
52             : $_[P_PARSER];
53             return;
54             } else {
55             return($_[THIS][ATR_PARSER]);
56             }
57             }
58              
59             sub default_parser {
60             if(exists($_[P_PARSER])) {
61             $default_parser = (ref($_[P_PARSER]) eq '')
62             ? build_parser($_[P_PARSER])
63             : $_[P_PARSER];
64             return;
65             } else {
66             return($default_parser);
67             }
68             }
69              
70             sub add_group {
71             my $this = shift;
72              
73             foreach my $group (@_) {
74             if(ref($group) eq '') {
75             unless($group =~ m,^((|::)(\w+))+$,) {
76             Carp::confess("Invalid package name '$group'.");
77             }
78             if(substr($group, 0, 2) eq '::') {
79             $group = __PACKAGE__."::Group$group";
80             }
81             eval "use $group;";
82             Carp::confess($@) if ($@);
83             $group = $group->new;
84             }
85             push(@{$this->[ATR_GROUPS]}, $group);
86             }
87             return;
88             }
89              
90             sub compile {
91             my ($this, $format) = @_;
92              
93             my @parts = ();
94             my @dynamic_values = ();
95             while (my ($text, $placeholder) = $this->[ATR_PARSER]->($format)) {
96             push(@parts, $text, '');
97             foreach my $group (@{$this->[ATR_GROUPS]}) {
98             next unless(defined(my $collector = $group->lookup($placeholder)));
99             push(@dynamic_values, [$collector, $#parts]);
100             last;
101             }
102             }
103             push(@parts, $format);
104              
105             $this->[ATR_COLLECTOR] = sub {
106             foreach my $value (@dynamic_values) {
107             my ($collector, $offset) = @$value;
108             $parts[$offset] = $collector->[0]->($collector->[1]);
109             }
110             return(\join(q{}, @parts));
111             };
112              
113             return;
114             }
115              
116             sub execute {
117             return(shift->[ATR_COLLECTOR]->(@_));
118             }
119              
120             1;