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   230874 use strict;
  12         32  
  12         357  
4 12     12   61 use warnings;
  12         24  
  12         280  
5 12     12   206 use 5.008004;
  12         43  
6              
7             # ABSTRACT: Advanced interpolation engine for Alien builds
8             our $VERSION = '2.46'; # VERSION
9              
10              
11             sub new
12             {
13 75     75 1 18423 my($class) = @_;
14 75         333 my $self = bless {
15             helper => {},
16             classes => {},
17             }, $class;
18 75         209 $self;
19             }
20              
21              
22             sub add_helper
23             {
24 1650     1650 1 4120 my $self = shift;
25 1650         2324 my $name = shift;
26 1650         2025 my $code = shift;
27              
28 1650 100       3361 if(defined $self->{helper}->{$name})
29             {
30 1         6 require Carp;
31 1         223 Carp::croak("duplicate implementation for interpolated key $name");
32             }
33              
34 1649         2097 my $require;
35              
36 1649 100       2870 if(ref $_[0] eq 'CODE')
37             {
38 485         727 $require = shift;
39             }
40             else
41             {
42 1164         1708 $require = [];
43 1164         2228 while(@_)
44             {
45 906         1218 my $module = shift;
46 906         1192 my $version = shift;
47 906   100     2415 $version ||= 0;
48 906         2323 push @$require, $module => $version;
49             }
50             }
51              
52 1649         3032 $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 651 my $self = shift;
63 34         69 my($name) = @_;
64 34         145 delete $self->{helper}->{$name};
65 34         78 $self->add_helper(@_);
66             }
67              
68              
69             sub has_helper
70             {
71 54     54 1 130 my($self, $name) = @_;
72              
73 54 100       174 return unless defined $self->{helper}->{$name};
74              
75 49         161 my @require = $self->{helper}->{$name}->require;
76              
77 49         146 while(@require)
78             {
79 9         19 my $module = shift @require;
80 9         16 my $version = shift @require;
81              
82             {
83 9         16 my $pm = "$module.pm";
  9         23  
84 9         38 $pm =~ s/::/\//g;
85 9         1309 require $pm;
86 8 50       149 $module->VERSION($version) if $version;
87             }
88              
89 7 100       45 unless($self->{classes}->{$module})
90             {
91 4 100       40 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         6 $self->{helper}->{$k}->code($helpers->{$k});
97             }
98             }
99 4         18 $self->{classes}->{$module} = 1;
100             }
101             }
102              
103 47         142 my $code = $self->{helper}->{$name}->code;
104              
105 47 50       115 return unless defined $code;
106              
107 47 100       126 if(ref($code) ne 'CODE')
108             {
109 7         14 my $perl = $code;
110             package Alien::Build::Interpolate::Helper;
111             $code = sub {
112             ## no critic
113 4     4   1393 my $value = eval $perl;
114             ## use critic
115 4 50       18 die $@ if $@;
116 4         22 $value;
117 7         39 };
118             }
119              
120 47         107 $code;
121             }
122              
123              
124             sub execute_helper
125             {
126 44     44 1 170 my($self, $name) = @_;
127              
128 44         158 my $code = $self->has_helper($name);
129 42 100       132 die "no helper defined for $name" unless defined $code;
130              
131 39         121 $code->();
132             }
133              
134              
135             sub _get_prop
136             {
137 16     16   45 my($name, $prop, $orig) = @_;
138              
139 16         39 $name =~ s/^\./alien./;
140              
141 16 100       74 if($name =~ /^(.*?)\.(.*)$/)
    100          
142             {
143 10         37 my($key,$rest) = ($1,$2);
144 10         42 return _get_prop($rest, $prop->{$key}, $orig);
145             }
146             elsif(exists $prop->{$name})
147             {
148 5         23 return $prop->{$name};
149             }
150             else
151             {
152 1         6 require Carp;
153 1         95 Carp::croak("No property $orig is defined");
154             }
155             }
156              
157             sub interpolate
158             {
159 89     89 1 2412 my($self, $string, $prop) = @_;
160 89   100     331 $prop ||= {};
161              
162 89         480 $string =~ s{(?execute_helper($1)}eg;
  44         176  
163 84         243 $string =~ s{(?
  6         21  
164 83         171 $string =~ s/\%(?=\%)//g;
165 83         346 $string;
166             }
167              
168              
169             sub requires
170             {
171 205     205 1 382 my($self, $string) = @_;
172             map {
173 205         1344 my $helper = $self->{helper}->{$_};
  46         97  
174 46 100       156 $helper ? $helper->require : ();
175             } $string =~ m{(?
176             }
177              
178              
179             sub clone
180             {
181 1     1 1 6 my($self) = @_;
182              
183 1         635 require Storable;
184              
185 1         3324 my %helper;
186 1         3 foreach my $name (keys %{ $self->{helper} })
  1         6  
187             {
188 1         5 $helper{$name} = $self->{helper}->{$name}->clone;
189             }
190              
191             my $new = bless {
192             helper => \%helper,
193 1         80 classes => Storable::dclone($self->{classes}),
194             }, ref $self;
195             }
196              
197             package Alien::Build::Helper;
198              
199             sub new
200             {
201 1650     1650   2930 my($class, $name, $code, $require) = @_;
202 1650         7226 bless {
203             name => $name,
204             code => $code,
205             require => $require,
206             }, $class;
207             }
208              
209 1     1   4 sub name { shift->{name} }
210              
211             sub code
212             {
213 52     52   112 my($self, $code) = @_;
214 52 100       135 $self->{code} = $code if $code;
215 52         119 $self->{code};
216             }
217              
218             sub require
219             {
220 95     95   179 my($self) = @_;
221 95 100       329 if(ref $self->{require} eq 'CODE')
222             {
223 4         13 $self->{require} = [ $self->{require}->($self) ];
224             }
225 95         184 @{ $self->{require} };
  95         387  
226             }
227              
228             sub clone
229             {
230 1     1   3 my($self) = @_;
231 1         3 my $class = ref $self;
232 1         4 $class->new(
233             $self->name,
234             $self->code,
235             [ $self->require ],
236             );
237             }
238              
239             1;
240              
241             __END__