File Coverage

blib/lib/Config/Simple/Inherit.pm
Criterion Covered Total %
statement 39 40 97.5
branch 5 6 83.3
condition 2 3 66.6
subroutine 7 7 100.0
pod 1 1 100.0
total 54 57 94.7


line stmt bran cond sub pod time code
1             package Config::Simple::Inherit;
2             # package Simple::Inherit;
3              
4 2     2   124789 use warnings;
  2         5  
  2         83  
5 2     2   12 use strict;
  2         5  
  2         81  
6 2     2   12 use base qw( Config::Simple );
  2         15  
  2         1169  
7 2     2   24171 use UNIVERSAL qw( isa can );
  2         30  
  2         11  
8             # use UNIVERSAL qw( isa can VERSION );
9 2     2   2031 use Data::Dumper;
  2         11336  
  2         241  
10              
11             our $VERSION = '0.04';
12              
13             sub inherit {
14 3     3 1 43474 my $class = shift;
15 3         9 my $args = shift;
16             # print STDERR Dumper(\$args);
17 2     2   18 { no strict 'refs';
  2         5  
  2         722  
  3         8  
18 3 100 66     38 unless(defined($args->{'base_config'}) &&
19             UNIVERSAL::isa($args->{'base_config'},'Config::Simple')) {
20             # print STDERR "Now we create the first Config::Simple object using $args->{'filename'}; none already exists.\n";
21             # return "->inherit() has returned with debugging message.";
22 1         7 return Config::Simple->new( filename => $args->{'filename'} );
23             }
24             }
25 2         4 my @cfg_filenames;
26 2         7 my $cfg = $args->{'base_config'};
27 2 100       14 if(defined($cfg->{'_FILE_NAMES'})){
    50          
28 1         2 push @cfg_filenames, @{$cfg->{'_FILE_NAMES'}};
  1         5  
29 1         5 push @cfg_filenames, $args->{'filename'};
30             } elsif(defined($cfg->{'_FILE_NAME'})) {
31 1         3 push @cfg_filenames, $cfg->{'_FILE_NAME'};
32 1         3 push @cfg_filenames, $args->{'filename'};
33             } else {
34 0         0 die "We have a Config::Simple object, without an initial '_FILE_NAME' value.\n";
35             }
36 2         5 $cfg->{'_FILE_NAMES'} = \@cfg_filenames;
37 2         69 my $cfg_overload = Config::Simple->new( filename => $args->{'filename'} );
38              
39 2         4248 foreach my $stanza_key (keys %{$cfg_overload->{'_DATA'}}){
  2         14  
40 2         4 foreach my $param_key (keys %{$cfg_overload->{'_DATA'}->{$stanza_key}}){
  2         11  
41 10         51 $cfg->{'_DATA'}->{$stanza_key}->{$param_key} = $cfg_overload->{'_DATA'}->{$stanza_key}->{$param_key};
42             }
43             }
44              
45 2         18 return $cfg;
46             }
47              
48             =head1 NAME
49              
50             Config::Simple::Inherit - Inherit values from, overwrite a base configuration
51              
52             =head1 VERSION
53              
54             Version 0.04
55              
56             =cut
57              
58             =head1 SYNOPSIS
59              
60             my $installation_cfg = Config::Simple->new(
61             file => '/etc/app_name/app_name.ini' );
62              
63             my $client_cfg = Config::Simple::Inherit->inherit(
64             base_config => $installation_cfg,
65             filename => '/etc/app_name/client_name/app_name.ini',
66             );
67              
68             my $job_cfg = Config::Simple::Inherit->inherit(
69             base_config => $client_cfg,
70             filename => '/etc/app_name/client_name/app_job_id.ini',
71             );
72              
73             =head1 EXAMPLES
74              
75             For details on accessing configuration parameters, read perldoc
76             Config::Simple, which is well documented. In short, even if
77             you wanted to bypass the published methods, everything seems
78             to be found at: $cfg->{'_DATA'}->{$stanza}->{$key}, which then
79             takes an anonymous list of whatever you feed it. The notes
80             below focus on how to set up overloading configuration files
81             How to write a constructor which will use them, how to share
82             configuration hashes among modules in an application, etc.
83              
84             These configuration hashes can be shared around with other
85             objects which need them, like this:
86              
87             my $object = My::New::Module->new({ 'cfg' => $self->{'cfg'} });
88              
89             assuming that you are inside an object method whose constructor
90             stored the configuration hash at its own 'cfg' key, as I tend
91             to do.
92              
93             or to needlessly duplicate the object in your memory overhead,
94             as I did it when I was first digging around in the innards of
95             Config::Simple, and learning how to use it:
96              
97             my $new_object = My::New::Module->new({
98             'config_file' => $self->{'cfg'}->{'_FILE_NAME'} });
99              
100             Now I can write a constructor like this:
101              
102             =over
103              
104             package My::New::Module;
105            
106             sub new {
107             my $class = shift;
108             my $defaults = shift;
109             my $self = {};
110            
111             if(defined($defaults->{'config_file'})){
112             $self->{'cfg'} = Config::Simple::Inherit->new(
113             { filename => $defaults->{'config_file'} } );
114             } elsif(defined($defaults->{'config_files'})){
115             my $cfg;
116             undef($cfg);
117             foreach my $file (@{$defaults->{'config_files'}}){
118             $cfg = Config::Simple::Inherit->inherit({
119             base_config => $cfg,
120             filename => $file });
121             }
122             $self->{'cfg'} = $cfg;
123             } else {
124             die "Constructor invoked with no Confirguration File."
125             }
126            
127             my $db = $self->{'cfg'}->get_block('db');
128             # print STDERR Dumper(\$db);
129             $self->{'dbh'} = My::New::Module::DB->connect($db);
130            
131             bless $self, $class;
132             return $self;
133             }
134              
135             =back
136              
137             Making it possible to use it like so:
138              
139             my $new_object = My::New::Module->new({
140             'config_files' => [ '/etc/my_app/base_configuration.ini',
141             '/etc/my_app/client/client_configuration.ini',
142             '/etc/my_app/client/job_id.ini' ] });
143              
144             with the job config over-writing the client config, over-writing
145             the base config. If you let untrusted users write their
146             own job configuration files, you probably want to reverse
147             the order of the array, so that your base configuration file
148             ultimately overwrites the final object with your sanity checks
149             and security barriers in place.
150              
151             =cut
152              
153             =head1 METHODS
154              
155             =head2 ->inherit()
156              
157             This module only offers this one method, but I trust you'll
158             find it useful. It returns a Config::Simple object, when given
159             a reference to a hash, of which it only recognizes two keys:
160             'base_config' and 'filename'. The 'base_config' ought to be
161             left undefined or set to a 'Config::Simple' object created
162             with either this method or the ->new() method provided by
163             Config::Simple. When 'base_config' is given a Config::Simple
164             object, it walks every configuration parameter defined in the
165             filename, and uses the new value to update the value for the
166             respective parameterin the 'base_config' object, inheriting
167             values from it, but overloading the configuration with the
168             new values.
169              
170             I envision essentially two ways this module might be used:
171              
172             (1) to provide a means for getting more specific with
173             a configuration by first creating an installation-wide
174             configuration, then a client specific configuration, then
175             job specific configuration, each overloading the more general
176             values provided by the configuration before it.
177              
178             (2) to enforce client, and installation security controls and
179             sanity checks on a configuration prepared by an untrusted user.
180             Say you had an application which permitted a local user to
181             create a configuration file for a job. By loading the user
182             created configuration first, then using the installation
183             default configuration to overwrite it, it would be possible
184             to prevent abuse and enforce system wide constraints.
185              
186             =cut
187              
188             =head1 AUTHOR
189              
190             Hugh Esco, C<< >>
191              
192             =head1 BUGS
193              
194             Please report any bugs or feature requests to
195             C, or through the web interface at
196             L.
197             I will be notified, and then you'll automatically be notified of progress on
198             your bug as I make changes.
199              
200             I also do business as CampaignFoundations.com,
201             where we host an issues que, available at:
202             L
203              
204             =head1 SUPPORT
205              
206             You can find documentation for this module with the perldoc command.
207              
208             perldoc Config::Simple::Inherit
209              
210             You can also look for information at:
211              
212             =over 4
213              
214             =item * AnnoCPAN: Annotated CPAN documentation
215              
216             L
217              
218             =item * CPAN Ratings
219              
220             L
221              
222             =item * RT: CPAN's request tracker
223              
224             L
225              
226             I also watch for bug reports at:
227              
228             L
229              
230             =item * Search CPAN
231              
232             L
233              
234             =back
235              
236             =head1 ACKNOWLEDGEMENTS
237              
238             Sherzod B. Ruzmetov, author of Config::Simple, which I've come
239             to rely on as the primary tool I use to manage configuration
240             for the applications I write.
241              
242             =head1 COPYRIGHT & LICENSE
243              
244             Copyright 2008 Hugh Esco, all rights reserved.
245              
246             This program is released under the following license: Gnu
247             Public License.
248              
249             =head1 SEE ALSO
250              
251             Config::Simple which handles ini, html and simple formats.
252             Config::Simple::Inherit returns a Config::Simple object, and
253             the accessors (and other methods) for its configuration are
254             documented by Mr. Ruzmetov in the perldoc for his module.
255              
256             If you need some combination of json, yaml, xml, perl, ini or
257             Config::General formats, take a look at: Config::Merge, which I
258             learned of after releasing version 0.03 of this module to cpan.
259              
260             =cut
261              
262             1; # End of Config::Simple::Inherit