File Coverage

blib/lib/Config/Merge/Dynamic.pm
Criterion Covered Total %
statement 62 67 92.5
branch 12 18 66.6
condition 2 6 33.3
subroutine 11 11 100.0
pod 2 2 100.0
total 89 104 85.5


line stmt bran cond sub pod time code
1             package Config::Merge::Dynamic;
2              
3 3     3   97422 use 5.008;
  3         12  
  3         150  
4 3     3   19 use strict;
  3         7  
  3         138  
5 3     3   18 use warnings FATAL => 'all', NONFATAL => 'redefine';
  3         11  
  3         175  
6 3     3   3433 use utf8;
  3         104  
  3         17  
7              
8 3     3   2736 use parent 'Config::Merge';
  3         1074  
  3         19  
9              
10 3     3   76654 use Carp qw/croak/; # die beautiful
  3         9  
  3         2283  
11              
12             # for develop
13             # use Smart::Comments;
14              
15             =head1 NAME
16              
17             Config::Merge::Dynamic - load a configuration directory tree containing
18             YAML, JSON, XML, Perl, INI or Config::General files AND alter it in runtime.
19              
20             =head1 VERSION
21              
22             Version 0.14.1
23              
24             =cut
25              
26             our $VERSION = '0.141';
27             $VERSION = eval $VERSION;
28              
29             =head1 SYNOPSIS
30              
31             Example how to add (or replace, if values exists) values in config object:
32              
33             use Config::Merge::Dynamic;
34             my $config = Config::Merge->new('/path/to/config');
35             my $all_data = $config->inject( 'key_one.key_two.keyn', { foo =>'bar' } );
36             my $new_conf = $config->move( 'user_config', 'system_config' );
37              
38              
39             =head1 DESCRIPTION
40              
41             This module expand L to make available to add/replace config data in config object in runtime.
42            
43             =head1 SUBROUTINES/METHODS
44              
45             L inherits all methods from L and implements
46             the following new ones.
47              
48             =head2 C
49              
50             inject() are insert to object config new data,
51             and context-sensetive returns of all new config data, or nothing if called in void context.
52              
53             First argument - path is optional, second may be scalar or arrayref or hashref.
54              
55             my $all_data = $config->inject( 'key_one.key_two.keyn', { foo =>'bar' } );
56            
57             Or available one-argument calling, without 'path', all data will injected to root:
58              
59             my $all_data2 = $config->inject(
60             {
61             key_one => {
62             key_two => {
63             keyn => {
64             foo => 'bar'
65             }
66             }
67             }
68             }
69             );
70              
71             Also available to change single scalar value
72              
73             my $all_data3 = $config->inject( 'key_one.key_two.keyn.foo', 'bar' );
74              
75             And deal with array like this
76            
77             my $all_data3 = $config->inject( 'key_three.1', 'bar' );
78             # now $all_data3 = { key_three => [ undef, 'bar' ], ... };
79              
80              
81             =cut
82              
83             #===================================
84             sub inject {
85             #===================================
86 4     4 1 7158 my $self = shift;
87 4         9 my $what = pop; # this is for optional arguments, with /where/ and without it
88 4         6 my $where = shift;
89              
90 4 50       32 unless ( defined $what ) { # NOP in void args
91 0         0 return &_context_sensetive_return($self);
92             }
93              
94 4 100       14 if ( defined $where ) {
95 3         13 $what = $self->_prefix_value( $where, $what );
96             }
97              
98             # merge together
99 4         8 my $config = \%{ $self->C() };
  4         16  
100 4         87 $self->_merge_hash( $config, $what );
101 4         304 $self->clear_cache();
102              
103 4         32 return &_context_sensetive_return($self);
104             }
105              
106             =head2 C
107              
108             move() are move one part of config data to another place (in dot-notation),
109             and context-sensetive returns of all new config data, or nothing if called in void context.
110              
111             First argument - source requared, second - destination is optional.
112             If destination is omitted source was move to the `root` of config.
113              
114             my $new_conf = $config->move( 'user_config', 'system_config' );
115             # or move 'user_config' content to `root`
116             $config->move( 'user_config' );
117              
118            
119             =cut
120              
121             #===================================
122             sub move {
123             #===================================
124 2     2 1 8776 my $self = shift;
125 2         5 my $source = shift;
126 2         4 my $destination = shift;
127              
128 2 50       9 unless ( defined $source ) { # NOP in void args
129 0         0 return &_context_sensetive_return($self);
130             }
131              
132 2         5 my $data_to_insert = \%{ $self->($source) };
  2         12  
133 2 100       107 if ( defined $destination ) {
134              
135             # prepend data with destination prefix
136 1         6 $data_to_insert = $self->_prefix_value( $destination, $data_to_insert );
137             }
138              
139             # yap! we are undefing value, not wipe clearly, but who care?
140 2         7 my $data_to_delete = $self->_prefix_value( $source, undef );
141              
142             # append data, then wipe out from old place
143             # we are keep intermediate values for little optimize
144 2         4 my $config = \%{ $self->C() };
  2         8  
145 2         52 $config = $self->_merge_hash( $config, $data_to_insert );
146 2         154 $self->_merge_hash( $config, $data_to_delete );
147              
148 2         47 $self->clear_cache();
149              
150 2         18 return &_context_sensetive_return($self);
151              
152             }
153              
154             =begin comment _prefix_value
155              
156             subroutine prefixing path to value.
157             Now we are create value by self.
158              
159             =end comment
160              
161             =cut
162              
163             #===================================
164             sub _prefix_value {
165             #===================================
166 6     6   9 my $self = shift;
167 6         12 my $destination = shift;
168 6         7 my $result = shift; # yap, its result too
169              
170 6         20 my @data_path = $self->_path_resolution($destination);
171 6 50       25 if ( $#data_path < 0 ) {
172 0         0 croak sprintf qq(path |%s| can`t be resoluted, die ), $destination;
173             }
174              
175             # prexifing result with data_path
176             # its very simple thing - we are rise from root to bottom, autovivifing result
177 6         15 foreach my $key ( reverse @data_path ){
178            
179 9         14 my $temp;
180            
181 9 100       44 ( $key =~ /^\d+$/
182             ? $temp->[$key]
183             : $temp->{$key}
184             ) = $result;
185            
186 9         26 $result = $temp;
187            
188             }
189              
190 6         22 return $result;
191              
192             }
193              
194             =begin comment _path_resolution
195              
196             subroutine resolve path from dot-notation to list for DiveVal.
197             May be laiter you are want to use another one delimetter, so it`s there.
198              
199             =end comment
200              
201             =cut
202              
203             #===================================
204             sub _path_resolution {
205             #===================================
206 6     6   10 my $self = shift;
207 6         11 my $path_string = shift;
208              
209 6         26 return split /\./, $path_string;
210             }
211              
212             =begin comment _context_sensetive_return
213              
214             subroutine for context-sensetive returns
215             any subs use return &_context_sensetive_return to handle caller livel
216             its a little black magic
217              
218             =end comment
219              
220             =cut
221              
222             #===================================
223             sub _context_sensetive_return {
224             #===================================
225 6     6   9 my $self = shift;
226              
227 6 50       20 return unless defined wantarray; # void call
228              
229 6         8 my $config = \%{ $self->C() };
  6         17  
230              
231             return
232 0           wantarray && ref($config) eq 'HASH' ? %{$config}
  0            
233 6 50 33     213 : wantarray && ref($config) eq 'ARRAY' ? @{$config}
    50 33        
234             : $config;
235              
236             }
237              
238             =head1 CAVEAT
239              
240             All may go strange if you inject mismatch type of values in wrong place - handle your data with care.
241              
242             =head1 EXPORT
243              
244             Nothing by default.
245              
246             =head1 AUTHOR
247              
248             Meettya, C<< >>
249              
250             =head1 BUGS
251              
252             Please report any bugs or feature requests to C, or through
253             the web interface at L. I will be notified, and then you'll
254             automatically be notified of progress on your bug as I make changes.
255              
256             =head1 DEVELOPMENT
257              
258             =head2 Repository
259              
260             https://github.com/Meettya/Config-Merge-Dynamic
261            
262             =head1 SUPPORT
263              
264             You can find documentation for this module with the perldoc command.
265              
266             perldoc Config::Merge::Dynamic
267              
268              
269             You can also look for information at:
270              
271             =over 4
272              
273             =item * RT: CPAN's request tracker (report bugs here)
274              
275             L
276              
277             =item * AnnoCPAN: Annotated CPAN documentation
278              
279             L
280              
281             =item * CPAN Ratings
282              
283             L
284              
285             =item * Search CPAN
286              
287             L
288              
289             =back
290              
291              
292             =head1 ACKNOWLEDGEMENTS
293              
294             Thanks to Clinton Gormley, Eclinton@traveljury.comE for original Config::Merge.
295              
296             =head1 LICENSE AND COPYRIGHT
297              
298             Copyright 2011 Meettya.
299              
300             This program is free software; you can redistribute it and/or modify it
301             under the terms of either: the GNU General Public License as published
302             by the Free Software Foundation; or the Artistic License.
303              
304             See http://dev.perl.org/licenses/ for more information.
305              
306              
307             =cut
308              
309             1; # End of Config::Merge::Dynamic