File Coverage

blib/lib/Macro/Micro.pm
Criterion Covered Total %
statement 89 95 93.6
branch 44 54 81.4
condition 8 12 66.6
subroutine 21 22 95.4
pod 10 10 100.0
total 172 193 89.1


line stmt bran cond sub pod time code
1 6     6   128971 use strict;
  6         17  
  6         226  
2 6     6   30 use warnings;
  6         176  
  6         341  
3             package Macro::Micro;
4             {
5             $Macro::Micro::VERSION = '0.054';
6             }
7             # ABSTRACT: really simple templating for really simple templates
8              
9 6     6   30 use Carp ();
  6         11  
  6         5581  
10              
11              
12             my $DEFAULT_MACRO_FORMAT = qr/(?\]])/x;
13              
14             sub new {
15 6     6 1 96 my ($class, %arg) = @_;
16              
17 6         23 my $self = bless { } => $class;
18              
19 6 100       35 $arg{macro_format} = $DEFAULT_MACRO_FORMAT unless $arg{macro_format};
20              
21 6         36 $self->macro_format($arg{macro_format});
22              
23 6         19 return $self;
24             }
25              
26              
27             sub macro_format {
28 25     25 1 843 my $self = shift;
29              
30 25 100       82 return $self->{macro_format} unless @_;
31              
32 8         15 my $macro_format = shift;
33 8 100       312 Carp::croak "macro format must be a regexp reference"
34             unless ref $macro_format eq 'Regexp';
35              
36 6         46 $self->{macro_format} = $macro_format;
37             }
38              
39              
40             sub register_macros {
41 8     8 1 3440 my ($self, @macros) = @_;
42              
43 8         38 for (my $i = 0; $i < @macros; $i += 2) {
44 27         52 my ($name, $value) = @macros[ $i, $i+1 ];
45 27 100 100     212 Carp::croak "macro value must be a string or code reference"
46             if (ref $value) and (ref $value ne 'CODE');
47              
48 26 100       60 if (not ref $name) {
    100          
49 20         86 $self->{macro}{$name} = $value;
50             } elsif (ref $name eq 'Regexp') {
51 5         31 $self->{macro_regexp}{$name} = [ $name, $value ];
52             } else {
53 1         195 Carp::croak "macro name '$name' must be a string or a regexp";
54             }
55             }
56              
57 6         26 return $self;
58             }
59              
60              
61             sub clear_macros {
62 0     0 1 0 my ($self, @macros) = @_;
63              
64 0 0       0 if (@macros) {
65 0         0 Carp::croak "partial deletion not implemented";
66             } else {
67 0         0 delete @$self{qw(macro macro_regexp)};
68             }
69              
70 0         0 return;
71             }
72              
73              
74             sub get_macro {
75 27     27 1 648 my ($self, $macro_name) = @_;
76              
77 27 100       106 return $self->{macro}{$macro_name} if exists $self->{macro}{$macro_name};
78              
79 9         13 foreach my $regexp (values %{ $self->{macro_regexp} }) {
  9         30  
80 8 100       680 return $regexp->[1] if $macro_name =~ $regexp->[0];
81             }
82              
83 3         16 return;
84             }
85              
86              
87             sub expand_macros {
88 9     9 1 1380 my ($self, $object, $stash) = @_;
89              
90 9 100       15 if (eval { $object->isa('Macro::Micro::Template') }) {
  9         92  
91 1         5 return $self->_expand_template($object, $stash);
92             }
93              
94 8         25 $self->fast_expander($stash)->($object);
95             }
96              
97             sub _expand_template {
98 1     1   3 my ($self, $object, $stash) = @_;
99             # expects to be passed ($whole_macro, $macro_inside_delim, $whole_text)
100             my $expander = sub {
101 8     8   17 my $macro = $self->get_macro($_[1]);
102 8 50       17 return $_[0] unless defined $macro;
103 8 100 50     26 return ref $macro ? $macro->($_[1], $_[2], $stash)||'' : $macro;
104 1         6 };
105              
106 1 50       4 return ${ $object->_text } unless $object->_parts;
  0         0  
107              
108 1 100       504 return join '', map { ref $_ ? $expander->(@$_[0, 1], $object->_text) : $_ }
  16         88  
109             $object->_parts;
110             }
111              
112              
113             sub expand_macros_in {
114 6     6 1 2196 my ($self, $object, $stash) = @_;
115              
116 6 100 100     813 Carp::croak "object of in-place expansion must be a scalar reference"
117             if (not ref $object)
118             or (ref $object ne 'SCALAR');
119              
120 4         14 my $fast_expander = $self->fast_expander($stash);
121              
122 4         13 $$object = $fast_expander->($$object);
123             }
124              
125              
126             sub string_expander {
127 13     13 1 23 my ($self, $stash) = @_;
128              
129 13         36 my $expander = $self->macro_expander($stash);
130 13         35 my $regex = $self->macro_format;
131              
132             my $applicator = sub {
133 13     13   19 my ($object) = @_;
134              
135 13 50       51 return unless defined $object;
136 13 100       167 Carp::croak "object of expansion must not be a reference" if ref $object;
137              
138 12         95 $object =~ s/$regex/$expander->($1,$2)/eg;
  24         48  
139              
140 12         95 return $object;
141             }
142 13         66 }
143              
144 6     6   2979 BEGIN { *fast_expander = \&string_expander }
145              
146              
147             sub macro_expander {
148 13     13 1 19 my ($self, $stash) = @_;
149              
150 13         17 my %cached;
151              
152 13 100       16 if (values %{ $self->{macro_regexp} }) {
  13         50  
153             return sub {
154 17 50   17   92 return $cached{ $_[0] } if defined $cached{ $_[0] };
155              
156 17         614 my $macro = $self->get_macro($_[1]);
157              
158 17 100 50     96 $cached{ $_[0] } = defined $macro
    100          
159             ? ref $macro
160             ? $macro->($_[1], $_[2], $stash)||'' : $macro
161             : $_[0];
162              
163 17         235 return $cached{ $_[0] };
164 11         55 };
165             } else {
166             return sub {
167 7 50   7   18 return $cached{ $_[0] } if defined $cached{ $_[0] };
168              
169 7         14 my $macro = $self->{macro}{ $_[1] };
170              
171 7 50 0     566 $cached{ $_[0] } = defined $macro
    50          
172             ? ref $macro
173             ? $macro->($_[1], $_[2], $stash)||'' : $macro
174             : $_[0];
175              
176 7         27 return $cached{ $_[0] };
177 2         13 };
178             }
179             }
180              
181              
182              
183             sub study {
184 4     4 1 1787 my ($self, $text) = @_;
185              
186 4         11 my $macro_format = $self->macro_format;
187              
188 4         6 my @total;
189              
190             my $pos;
191 4         97 while ($text =~ m/\G(.*?)$macro_format/gsm) {
192 8         24 my ($snippet, $whole, $name) = ($1, $2, $3);
193 8 100       34 push @total, (length $snippet ? $snippet : ()),
    50          
194             ($whole ? [ $whole, $name ] : ());
195 8         60 $pos = pos $text;
196             }
197              
198 4 100       12 push @total, substr $text, $pos if defined $pos;
199              
200 4         13 return Macro::Micro::Template->_new(\$text, \@total);
201             }
202              
203             {
204             package Macro::Micro::Template;
205             {
206             $Macro::Micro::Template::VERSION = '0.054';
207             }
208 4     4   20 sub _new { bless [ $_[1], $_[2] ] => $_[0] }
209 2     2   3 sub _parts { @{ $_[0][1] } }
  2         13  
210 8     8   18 sub _text { $_[0][0] }
211             }
212              
213             "[MAGIC_TRUE_VALUE]";
214              
215             __END__