File Coverage

blib/lib/Alien/Build/Interpolate.pm
Criterion Covered Total %
statement 102 102 100.0
branch 27 30 90.0
condition 4 4 100.0
subroutine 18 18 100.0
pod 8 8 100.0
total 159 162 98.1


line stmt bran cond sub pod time code
1             package Alien::Build::Interpolate;
2              
3 12     12   259268 use strict;
  12         41  
  12         381  
4 12     12   64 use warnings;
  12         27  
  12         279  
5 12     12   196 use 5.008004;
  12         43  
6              
7             # ABSTRACT: Advanced interpolation engine for Alien builds
8             our $VERSION = '2.45'; # VERSION
9              
10              
11             sub new
12             {
13 75     75 1 21316 my($class) = @_;
14 75         399 my $self = bless {
15             helper => {},
16             classes => {},
17             }, $class;
18 75         243 $self;
19             }
20              
21              
22             sub add_helper
23             {
24 1650     1650 1 4462 my $self = shift;
25 1650         2247 my $name = shift;
26 1650         2189 my $code = shift;
27              
28 1650 100       3498 if(defined $self->{helper}->{$name})
29             {
30 1         11 require Carp;
31 1         220 Carp::croak("duplicate implementation for interpolated key $name");
32             }
33              
34 1649         2026 my $require;
35              
36 1649 100       3025 if(ref $_[0] eq 'CODE')
37             {
38 485         735 $require = shift;
39             }
40             else
41             {
42 1164         1690 $require = [];
43 1164         3415 while(@_)
44             {
45 906         1388 my $module = shift;
46 906         1169 my $version = shift;
47 906   100     2461 $version ||= 0;
48 906         2390 push @$require, $module => $version;
49             }
50             }
51              
52 1649         3123 $self->{helper}->{$name} = Alien::Build::Helper->new(
53             $name,
54             $code,
55             $require,
56             );
57             }
58              
59              
60             sub replace_helper
61             {
62 34     34 1 696 my $self = shift;
63 34         77 my($name) = @_;
64 34         169 delete $self->{helper}->{$name};
65 34         84 $self->add_helper(@_);
66             }
67              
68              
69             sub has_helper
70             {
71 54     54 1 158 my($self, $name) = @_;
72              
73 54 100       213 return unless defined $self->{helper}->{$name};
74              
75 49         223 my @require = $self->{helper}->{$name}->require;
76              
77 49         203 while(@require)
78             {
79 9         21 my $module = shift @require;
80 9         19 my $version = shift @require;
81              
82             {
83 9         19 my $pm = "$module.pm";
  9         26  
84 9         42 $pm =~ s/::/\//g;
85 9         2025 require $pm;
86 8 50       192 $module->VERSION($version) if $version;
87             }
88              
89 7 100       51 unless($self->{classes}->{$module})
90             {
91 4 100       39 if($module->can('alien_helper'))
92             {
93 1         4 my $helpers = $module->alien_helper;
94 1         6 foreach my $k (keys %$helpers)
95             {
96 2         8 $self->{helper}->{$k}->code($helpers->{$k});
97             }
98             }
99 4         22 $self->{classes}->{$module} = 1;
100             }
101             }
102              
103 47         185 my $code = $self->{helper}->{$name}->code;
104              
105 47 50       146 return unless defined $code;
106              
107 47 100       152 if(ref($code) ne 'CODE')
108             {
109 7         16 my $perl = $code;
110             package Alien::Build::Interpolate::Helper;
111             $code = sub {
112             ## no critic
113 4     4   1581 my $value = eval $perl;
114             ## use critic
115 4 50       21 die $@ if $@;
116 4         23 $value;
117 7         41 };
118             }
119              
120 47         115 $code;
121             }
122              
123              
124             sub execute_helper
125             {
126 44     44 1 195 my($self, $name) = @_;
127              
128 44         175 my $code = $self->has_helper($name);
129 42 100       182 die "no helper defined for $name" unless defined $code;
130              
131 39         147 $code->();
132             }
133              
134              
135             sub _get_prop
136             {
137 16     16   45 my($name, $prop, $orig) = @_;
138              
139 16         37 $name =~ s/^\./alien./;
140              
141 16 100       80 if($name =~ /^(.*?)\.(.*)$/)
    100          
142             {
143 10         35 my($key,$rest) = ($1,$2);
144 10         46 return _get_prop($rest, $prop->{$key}, $orig);
145             }
146             elsif(exists $prop->{$name})
147             {
148 5         33 return $prop->{$name};
149             }
150             else
151             {
152 1         16 require Carp;
153 1         238 Carp::croak("No property $orig is defined");
154             }
155             }
156              
157             sub interpolate
158             {
159 89     89 1 2818 my($self, $string, $prop) = @_;
160 89   100     377 $prop ||= {};
161              
162 89         655 $string =~ s{(?execute_helper($1)}eg;
  44         213  
163 84         334 $string =~ s{(?
  6         25  
164 83         188 $string =~ s/\%(?=\%)//g;
165 83         414 $string;
166             }
167              
168              
169             sub requires
170             {
171 205     205 1 374 my($self, $string) = @_;
172             map {
173 205         1342 my $helper = $self->{helper}->{$_};
  46         118  
174 46 100       223 $helper ? $helper->require : ();
175             } $string =~ m{(?
176             }
177              
178              
179             sub clone
180             {
181 1     1 1 9 my($self) = @_;
182              
183 1         923 require Storable;
184              
185 1         3798 my %helper;
186 1         3 foreach my $name (keys %{ $self->{helper} })
  1         10  
187             {
188 1         8 $helper{$name} = $self->{helper}->{$name}->clone;
189             }
190              
191             my $new = bless {
192             helper => \%helper,
193 1         142 classes => Storable::dclone($self->{classes}),
194             }, ref $self;
195             }
196              
197             package Alien::Build::Helper;
198              
199             sub new
200             {
201 1650     1650   2923 my($class, $name, $code, $require) = @_;
202 1650         7365 bless {
203             name => $name,
204             code => $code,
205             require => $require,
206             }, $class;
207             }
208              
209 1     1   7 sub name { shift->{name} }
210              
211             sub code
212             {
213 52     52   150 my($self, $code) = @_;
214 52 100       145 $self->{code} = $code if $code;
215 52         143 $self->{code};
216             }
217              
218             sub require
219             {
220 95     95   194 my($self) = @_;
221 95 100       361 if(ref $self->{require} eq 'CODE')
222             {
223 4         18 $self->{require} = [ $self->{require}->($self) ];
224             }
225 95         163 @{ $self->{require} };
  95         453  
226             }
227              
228             sub clone
229             {
230 1     1   5 my($self) = @_;
231 1         4 my $class = ref $self;
232 1         6 $class->new(
233             $self->name,
234             $self->code,
235             [ $self->require ],
236             );
237             }
238              
239             1;
240              
241             __END__