File Coverage

blib/lib/Config/ENV/Multi.pm
Criterion Covered Total %
statement 156 166 93.9
branch 39 52 75.0
condition 7 8 87.5
subroutine 35 37 94.5
pod 0 9 0.0
total 237 272 87.1


line stmt bran cond sub pod time code
1             package Config::ENV::Multi;
2 12     12   196359 use 5.008001;
  12         95  
3 12     12   52 use strict;
  12         17  
  12         230  
4 12     12   64 use warnings;
  12         25  
  12         312  
5 12     12   53 use Carp qw/croak/;
  12         22  
  12         930  
6              
7             our $VERSION = "0.05";
8              
9 12     12   66 use constant DELIMITER => '@#%@#';
  12         23  
  12         1414  
10              
11             sub import {
12 15     15   62547 my $class = shift;
13 15         31 my $package = caller(0);
14              
15 12     12   76 no strict 'refs';
  12         23  
  12         1806  
16 15 100       50 if (__PACKAGE__ eq $class) {
17 13         21 my $envs = shift;
18 13         30 my %opts = @_;
19             #
20             # rule => '{ENV}_{REGION}',
21             # any => '*',
22             # unset => '&';
23             #
24              
25 13         21 push @{"$package\::ISA"}, __PACKAGE__;
  13         119  
26              
27 13         44 for my $method (qw/common config any unset parent load/) {
28 78         106 *{"$package\::$method"} = \&{__PACKAGE__ . "::" . $method}
  78         275  
  78         178  
29             }
30              
31 13         41 my %wildcard = (
32             any => '*',
33             unset => '!',
34             );
35 13 100       45 $wildcard{any} = $opts{any} if $opts{any};
36 13 100       40 $wildcard{unset} = $opts{unset} if $opts{unset};
37              
38 13 100       41 $envs = [$envs] unless ref $envs;
39 13 100       33 my $mode = $opts{rule} ? 'rule': 'env';
40              
41 12     12   83 no warnings 'once';
  12         17  
  12         7256  
42 13         4738 ${"$package\::data"} = +{
43             configs => {},
44             mode => $mode, # env or rule
45             envs => $envs,
46             rule => $opts{rule},
47             wildcard => \%wildcard,
48             cache => {},
49             local => [],
50             export => $opts{export},
51 13         65 };
52             } else {
53 2         6 my %opts = @_;
54 2         6 my $data = _data($class);
55 2 100 66     49 if (my $export = $opts{export} || $data->{export}) {
56 1         99 constant->import("$package\::$export", $class);
57             }
58             }
59             }
60              
61             # copy from Config::ENV
62             sub load ($) { ## no critic
63 0     0 0 0 my $filename = shift;
64 0         0 my $hash = do "$filename";
65              
66 0 0       0 croak $@ if $@;
67 0 0       0 croak $^E unless defined $hash;
68 0 0       0 unless (ref($hash) eq 'HASH') {
69 0         0 croak "$filename does not return HashRef.";
70             }
71              
72 0 0       0 wantarray ? %$hash : $hash;
73             }
74              
75             sub parent ($) { ## no critic
76 1     1 0 6 my $package = caller(0);
77 1         2 my $e_or_r = shift;
78              
79 1         1 my $target;
80 1         2 my $data = _data($package);
81 1 50       3 if ($data->{mode} eq 'env') {
82 1         3 $target = __envs2key($e_or_r);
83             } else {
84 0         0 $target = __envs2key(__clip_rule($data->{rule}, $e_or_r));
85             }
86 1 50       1 %{ $data->{configs}{$target}->as_hashref || {} };
  1         4  
87             }
88              
89             sub any {
90 1     1 0 5 my $package = caller(0);
91 1         2 _data($package)->{wildcard}{any};
92             }
93              
94             sub unset {
95 2     2 0 4 my $package = caller(0);
96 2         3 _data($package)->{wildcard}{unset};
97             }
98              
99             # {ENV}_{REGION}
100             # => ['ENV', 'REGION]
101             sub __parse_rule {
102 3     3   5379 my $rule = shift;
103             return [
104 11 100       31 grep { defined && length }
105             map {
106 11 100       36 /^\{(.+?)\}$/ ? $1 : undef
107             }
108 3 50       20 grep { defined && length }
  14         37  
109             split /(\{.+?\})/, $rule
110             ];
111             }
112              
113             # {ENV}_{REGION} + 'prod_jp'
114             # => ['prod', 'jp']
115             sub __clip_rule {
116 6     6   5341 my ($template, $rule) = @_;
117             my $spliter = [
118 20 100       48 grep { defined && length }
119             map {
120 20 100       55 /^\{(.+?)\}$/ ? undef : $_
121             }
122 6 50       38 grep { defined && length }
  26         67  
123             split /(\{.+?\})/, $template
124             ];
125 6         11 my $pattern = '(.*)' . ( join '(.*)', @{$spliter} ) . '(.*)';
  6         15  
126 6         61 my @clip = ( $rule =~ /$pattern/g );
127 6         20 return \@clip;
128             }
129              
130             sub _data {
131 160     160   193 my $package = shift;
132 12     12   83 no strict 'refs';
  12         30  
  12         408  
133 12     12   61 no warnings 'once';
  12         24  
  12         8536  
134 160         168 ${"$package\::data"};
  160         367  
135             }
136              
137             sub common {
138 8     8 0 531 my $package = caller(0);
139 8         16 my $hash = shift;
140 8         25 my $data = _data($package);
141 8         20 my $envs = $data->{envs};
142 8 50       28 $envs = [$envs] unless ref $envs;
143 8         22 my $any = $data->{wildcard}{any};
144 8         13 _config_env($package, [ map { "$any" } @{$envs} ], $hash);
  16         48  
  8         20  
145             }
146              
147             sub config {
148 25     25 0 189 my $package = caller(0);
149 25 100       39 if (_data($package)->{mode} eq 'env') {
150 22         43 return _config_env($package, @_);
151             } else {
152 3         6 return _config_rule($package, @_);
153             }
154             }
155              
156             sub _config_env {
157 33     33   61 my ($package, $envs, $hash) = @_;
158              
159 33         47 my $data = _data($package);
160 33         45 my $wildcard = $data->{wildcard};
161 33 100       72 $envs = [ $envs ] unless ref $envs;
162              
163             $data->{configs}{__envs2key($envs)} = Config::ENV::Multi::ConfigInstance->new(
164 33         56 order => 0 + ( grep { $_ ne $wildcard->{any} } @$envs ),
  64         184  
165             pattern => $envs,
166             hash => $hash,
167             wildcard => $wildcard,
168             );
169             }
170              
171             sub _config_rule {
172 3     3   5 my ($package, $rule, $hash) = @_;
173 3         5 _config_env($package, __clip_rule(_data($package)->{rule}, $rule), $hash);
174             }
175              
176             sub current {
177 40     40 0 23143 my $package = shift;
178 40         69 my $data = _data($package);
179              
180 40         57 my $target_env = [ map { $ENV{$_} } @{ $data->{envs} } ];
  76         161  
  40         76  
181              
182             my $vals = $data->{cache}->{__envs2key($target_env)} ||= +{
183 40   100     95 %{ _match($package, $target_env) }
  38         77  
184             };
185             }
186              
187             sub local :method {
188 8     8 0 38 my ($package, %hash) = @_;
189 8 100       159 not defined wantarray and croak "local returns guard object; Can't use in void context.";
190              
191 7         10 my $data = _data($package);
192 7         7 push @{ $data->{local} }, \%hash;
  7         15  
193 7         8 %{ $data->{cache} } = ();
  7         13  
194              
195             bless sub {
196 7     7   9 @{ $data->{local} } = grep { $_ != \%hash } @{ $data->{local} };
  7         11  
  12         29  
  7         13  
197 7         8 %{ $data->{cache} } = ();
  7         39  
198 7         35 }, 'Config::ENV::Multi::Local';
199             }
200              
201             sub param {
202 14     14 0 98 my ($package, $name) = @_;
203 14         31 $package->current->{$name};
204             }
205              
206             sub __envs2key {
207 77     77   5466 my $v = shift;
208 77 100       155 $v = [$v] unless ref $v;
209 77 100       88 join DELIMITER(), map { defined $_ ? $_ : '' } @{$v};
  149         492  
  77         107  
210             }
211              
212             sub __key2envs {
213 0     0   0 my $f = shift;
214 0         0 [split DELIMITER(), $f];
215             }
216              
217             sub _match {
218 38     38   73 my ( $package, $target_envs ) = @_;
219              
220 38         59 my $data = _data($package);
221              
222             return +{
223 75         83 (map { %{ $_->as_hashref } }
  75         116  
224 163         272 grep { $_->match($target_envs) }
225 223         330 sort { $a->{order} - $b->{order} }
226 38         129 values %{ $data->{configs} }),
227 38         51 (map { %$_ } @{ $data->{local} })
  17         117  
  38         304  
228             };
229             }
230              
231             1;
232              
233             package Config::ENV::Multi::ConfigInstance;
234 12     12   76 use strict;
  12         19  
  12         264  
235 12     12   50 use warnings;
  12         22  
  12         389  
236              
237 12     12   5733 use List::MoreUtils qw/ all pairwise /;
  12         121018  
  12         63  
238              
239             sub new {
240 33     33   97 my ( $class, %args ) = @_;
241              
242             bless +{
243             order => $args{order},
244             pattern => $args{pattern},
245             hash => $args{hash},
246             wildcard => $args{wildcard},
247 33         147 }, $class;
248             }
249              
250             sub match {
251 163     163   212 my ( $self, $target ) = @_;
252              
253 245     245   658 return all { $_ } pairwise {
254             $a eq $self->{wildcard}{any} ? 1 :
255 319 100 100 319   944 $a eq $self->{wildcard}{unset} ? !defined $b :
    100          
256             defined $b && $b eq $a;
257 163         417 } @{ $self->{pattern} }, @{ $target };
  163         219  
  163         468  
258             }
259              
260 76     76   203 sub as_hashref { $_[0]->{hash} }
261              
262             package # to hide from pause
263             Config::ENV::Multi::Local;
264              
265             sub DESTROY {
266 7     7   1454 my $self = shift;
267 7         13 $self->();
268             }
269              
270             1;
271              
272             __END__