File Coverage

blib/lib/Config/Setting.pm
Criterion Covered Total %
statement 74 76 97.3
branch 11 16 68.7
condition 6 15 40.0
subroutine 16 17 94.1
pod 9 9 100.0
total 116 133 87.2


line stmt bran cond sub pod time code
1             # Copyright (C) 2004 by Dominic Mitchell. All rights reserved.
2             #
3             # Redistribution and use in source and binary forms, with or without
4             # modification, are permitted provided that the following conditions
5             # are met:
6             # 1. Redistributions of source code must retain the above copyright
7             # notice, this list of conditions and the following disclaimer.
8             # 2. Redistributions in binary form must reproduce the above copyright
9             # notice, this list of conditions and the following disclaimer in the
10             # documentation and/or other materials provided with the distribution.
11             #
12             # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13             # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15             # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
16             # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17             # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18             # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19             # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20             # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21             # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22             # SUCH DAMAGE.
23              
24             =pod
25              
26             =head1 NAME
27              
28             Config::Setting - Perl extension for configuration files.
29              
30             =head1 SYNOPSIS
31              
32             use Config::Setting;
33             my $stg = Config::Setting->new;
34             $stg->get("section", "key");
35              
36             =head1 DESCRIPTION
37              
38             This module provides an OO interface to a file full of settings.
39             Settings are assumed to be contained in collections (known as
40             "sections"). Each setting has a key and a value. The value of a
41             setting may refer to other settings using a similiar syntax to
42             variables in perl.
43              
44             Whilst this module can be used directly it is anticipated that it will
45             be subclassed. This way policy regarding the location and layout of
46             the settings can be determined for your project.
47              
48             =head1 METHODS
49              
50             =over 4
51              
52             =item new ( )
53              
54             The constructor. Takes no arguments.
55              
56             =item is_configured ( )
57              
58             Returns true if more than one configuration file has been found and
59             read.
60              
61             =item provider ( )
62              
63             Returns an object which can be used to collect the contents of files.
64             The default returns a L object. You
65             probably want to override this method when you set up your subclass, in
66             order to set the policy for file locations.
67              
68             =item parser ( )
69              
70             Returns a parser object. The default is the
71             L object. You may want to override this in
72             a subclass if you wish to use an alternative format for your
73             configuration files.
74              
75             =item sections ( )
76              
77             Return a list of which sections are available from this object.
78              
79             =item keylist ( SECTION )
80              
81             Return a list of keys that SECTION contains.
82              
83             =item has ( SECTION, KEY )
84              
85             Returns true if SECTION contains KEY.
86              
87             =item expand ( )
88              
89             Internal use only.
90              
91             =item get ( SECTION, KEY )
92              
93             Return the value of KEY in SECTION. If the value contains any
94             variables of the form ${word}, they will be fully expanded in the
95             return value.
96              
97             When trying to replace a variable "word", first, "word" will be looked
98             up as a key in the current section. If not found, it will then be
99             looked up sequentially in all the other sections. If still not found,
100             it will be replaced with an empty string.
101              
102             Expansion is recursive, so an expanded variable can contain other
103             variables.
104              
105             =back
106              
107             =head1 TODO
108              
109             It would be useful to know where each setting derived from, in order to
110             help debugging.
111              
112             =head1 AUTHOR
113              
114             Dominic Mitchell, Ecpan (at) happygiraffe.netE
115              
116             =head1 SEE ALSO
117              
118             L,
119             L,
120             L.
121              
122             =cut
123              
124             package Config::Setting;
125              
126 2     2   1487 use strict;
  2         4  
  2         73  
127 2     2   10 use vars qw($VERSION $rcsid);
  2         2  
  2         194  
128              
129 2     2   22 use Carp;
  2         4  
  2         115  
130 2     2   1281 use Config::Setting::IniParser;
  2         5  
  2         57  
131 2     2   548 use Config::Setting::FileProvider;
  2         5  
  2         1912  
132              
133             $VERSION = '0.04';
134             $rcsid = '@(#) $Id: Setting.pm 765 2005-08-31 20:05:59Z dom $ ';
135              
136             sub new {
137 1     1 1 18 my $class = shift;
138 1         4 my $self = {
139             Config => { },
140             };
141              
142 1         2 bless $self, $class;
143 1         8 return $self->_init;
144             }
145              
146             #---------------------------------------------------------------------
147             # These two functions are defaults and may be overridden
148              
149             sub provider {
150 0     0 1 0 my $self = shift;
151 0         0 return Config::Setting::FileProvider->new(@_);
152             }
153              
154             sub parser {
155 1     1 1 2 my $self = shift;
156 1         10 return Config::Setting::IniParser->new(@_);
157             }
158              
159             #---------------------------------------------------------------------
160              
161             sub _init {
162 1     1   2 my $self = shift;
163 1         5 my $provider = $self->provider;
164              
165 1         6 my @txts = $provider->provide();
166 1         2 my @configs;
167 1         3 foreach my $s (@txts) {
168 1         8 my $p = $self->parser();
169 1         5 push @configs, $p->parse_string( $s );
170             }
171 1         8 $self->{ is_configured } = @configs > 0;
172              
173 1         9 return $self->_merge(@configs);
174             }
175              
176             # Make up a combined configuration from all the ones provided.
177             # NB: Must maintain order of sections!
178             sub _merge {
179 1     1   2 my $self = shift;
180 1         2 my @configs = @_;
181 1         2 my %cf; # Combined config.
182             my @sections;
183              
184 1         4 my $chunk = Config::Setting::Chunk->new;
185 1         2 foreach my $c (@configs) {
186 1         5 foreach my $s ($c->sections) {
187 2         6 $chunk->add_section( $s );
188 2         8 foreach my $k ($c->section_keys($s)) {
189 6         18 my $v = $c->get_item($s, $k);
190 6         19 $chunk->set_item( $s, $k, $v );
191             }
192             }
193             }
194 1         10 $self->_chunk( $chunk );
195 1         27 return $self;
196             }
197              
198             #---------------------------------------------------------------------
199             # Data access...
200              
201             sub sections {
202 6     6 1 9 my $self = shift;
203 6         13 return $self->_chunk->sections;
204             }
205              
206             sub keylist {
207 1     1 1 990 my $self = shift;
208 1         3 my ($section) = @_;
209 1 50       13 croak "usage: Config::Setting->keylist(section)"
210             unless $section;
211 1         49 return $self->_chunk->section_keys( $section );
212             }
213              
214             sub has {
215 6     6 1 7 my $self = shift;
216 6         10 my ($section, $key) = @_;
217 6 50 33     63 croak "usage: Config::Setting->get(section,key)"
218             unless $section && $key;
219              
220 6         15 return defined $self->_chunk->get_item( $section, $key );
221             }
222              
223             # Get the value of a setting, searching all sections, but starting in
224             # the section specified. May also specify a key that cannot be expanded.
225             # Internal.
226             sub expand {
227 5     5 1 8 my $self = shift;
228 5         13 my ($section, $key, $origkey) = @_;
229 5 50 33     36 croak "usage: expand(section,key,origkey)"
      33        
230             unless $section && $key && $origkey;
231              
232             # Move our section to the top of the list.
233 5         12 my @sections = ($section, grep { $_ ne $section} $self->sections);
  10         28  
234              
235             return undef
236 5 50       15 if $key eq $origkey;
237              
238 5         8 foreach my $s (@sections) {
239 6 100       17 return $self->get($s, $key)
240             if $self->has($s, $key);
241             }
242              
243 1         15 return undef;
244             }
245              
246             # Return the value of a setting, fully expanded.
247             sub get {
248 7     7 1 2366 my $self = shift;
249 7         12 my ($section, $key) = @_;
250 7 50 33     75 croak "usage: Config::Setting->get(section,key)"
251             unless $section && $key;
252              
253 7         16 my $val = $self->_chunk->get_item( $section, $key );
254 7   66     90 while ($val && $val =~ m/\$/) {
255 3         17 $val =~ s{ \$ \{ (\w+) \} }{
256 5 100       20 $self->expand($section, $1, $key) || "";
257             }exg;
258             }
259 7         46 return $val;
260             }
261              
262             sub _chunk {
263 21     21   30 my $self = shift;
264 21 100       47 $self->{ _chunk } = $_[0] if @_;
265 21         87 return $self->{ _chunk };
266             }
267              
268             sub is_configured {
269 1     1 1 1322 my $self = shift;
270 1         7 return $self->{ is_configured };
271             }
272              
273             1;
274             __END__