File Coverage

blib/lib/Config/ENV/Multi.pm
Criterion Covered Total %
statement 139 150 92.6
branch 36 50 72.0
condition 6 8 75.0
subroutine 32 35 91.4
pod 0 8 0.0
total 213 251 84.8


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