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