File Coverage

blib/lib/Basset/Object/Conf.pm
Criterion Covered Total %
statement 47 67 70.1
branch 24 48 50.0
condition 12 25 48.0
subroutine 6 6 100.0
pod 2 4 50.0
total 91 150 60.6


line stmt bran cond sub pod time code
1             package Basset::Object::Conf;
2              
3             #Basset::Object::Conf Copyright and (c) 2002, 2003, 2004, 2005, 2006 James A Thomason III
4             #Basset::Object::Conf is distributed under the terms of the Perl Artistic License.
5              
6             =pod
7              
8             =head1 NAME
9              
10             Basset::Object::Conf - used to read conf files
11              
12             =head1 AUTHOR
13              
14             Jim Thomason, jim@jimandkoka.com
15              
16             =head1 DESCRIPTION
17              
18             It's good not to set up default values inside of your module. Believe me, I know. Lord knows I've gotten chewed out enough for Carp::Notify
19             having the defaults in the module. Anyway, this module includes instructions for the conf file format, how the read_conf_file method works,
20             and some bits of interaction with the rest of the system. See Basset::Object for more information.
21              
22             =cut
23              
24              
25             $VERSION = '1.03';
26              
27             #
28             # Basset::Object::Conf isa Basset::Object, but there are circular inheritance reasons. So, instead,
29             # @ISA is set from within the read_conf_file method
30             #
31             #
32             #use Basset::Object;
33             #@ISA = qw(Basset::Object);
34              
35 8     8   45 use strict;
  8         15  
  8         613  
36 8     8   46 use warnings;
  8         16  
  8         12244  
37              
38             =pod
39              
40             =head1 SET-UP
41              
42             You'll need to specify your conf files. There is the @conf_files array, toss in as many conf files as you'd like
43              
44             my @conf_files = qw(
45             /etc/mail.bulkmail.cfg
46             /etc/mail.bulkmail.cf2
47             );
48            
49             It'll just silently ignore any conf files that aren't present, so don't expect any errors. That's to allow you
50             to place multiple conf files in for use on multiple servers and then not worry about them.
51              
52             Multiple conf files are in significance order. So if mail.bulkmail.cfg and mail.bulkmail.cf2 both define a value
53             for 'foo', then the one in mail.bulkmail.cfg is used. And so on, conf files listed earlier are more important.
54             There is no way for a program to later look at a less significant conf value.
55              
56             =cut
57              
58             our @conf_files = (qw(
59             /etc/basset.conf
60             ./basset.conf
61             Basset/Object/basset.conf
62             lib/Basset/Object/basset.conf
63             ),
64             );
65             our %conf_files = ();
66              
67             sub conf_files {
68 706     706 0 1302 my $class = shift;
69 706         2655 foreach (reverse @_) {
70 0 0       0 unshift @conf_files, $_ unless $conf_files{$_}++;
71             }
72              
73 706         7088 return @conf_files;
74            
75             }
76              
77             our $default_package = 'Basset::Object';
78              
79             =pod
80              
81             =over
82              
83             =item read_conf_file
84              
85             read_conf_file will read in the conf files specified in the @conf_files array up at the top.
86              
87             You can also pass in a list of conf files to read, in most to least significant order, same as the @conf_files array.
88              
89             my $conf = Mail::Bulkmail::Object->read_conf_file();
90             or
91             my $conf = Mail::Bulkmail::Object->read_conf_file('conf_files' => '/other/conf.file');
92             or
93             my $conf = Mail::Bulkmail::Object->read_conf_file('conf_files' => ['/other/conf.file', '/additional/conf.file']);
94            
95             If you pass in a list of conf files, then the internal @conf_files array is bypassed.
96              
97             $conf is a hashref of hashrefs. the main keys are the package names, the values are the hashes of the values
98             for that object.
99              
100             Example:
101              
102             #conf file
103             define package Mail::Bulkmail
104            
105             use_envelope = 1
106             safe_banned = 0
107            
108             define package Mail::Bulkmail::Server
109            
110             Smtp = your.smtp.com
111             Port = 25
112            
113             $conf = {
114             'Mail::Bulkmail' => {
115             'use_envelope' => 1,
116             'safe_banned' => 1
117             },
118             'Mail::Bulkmail::Server' => {
119             'Smtp' => 'your.smtp.com',
120             'safe_banned' => 1
121             }
122             };
123            
124             read_conf_file is called at object initialization. Any defaults for your object are read in at this time.
125             You'll rarely need to read the conf file yourself, since at object creation it is read and parsed and the values passed
126             on.
127              
128             Note that it will combine the conf file in with an existing conf hash. To get a fresh one, pass in the conf_hash parameter.
129              
130             Basset::Object->read_conf_file('conf_hash' => {});
131              
132             B
133              
134             The conf file is only re-read if it has been modified since the last time it was read.
135              
136             =cut
137              
138             our $conf = {};
139             our $loaded = {};
140              
141             sub conf {
142 711     711 1 3088 return $conf;
143             }
144              
145             sub loaded {
146 1420     1420 0 18924 return $loaded;
147             }
148            
149             sub read_conf_file {
150 706     706 1 1166 my $class = shift;
151            
152             #this is a major league hack. Since Basset::Object::Conf isa Basset::Object, we wait
153             #until now to set its inheritance. Basset::Object::Conf should never be instantiated, so it's
154             #not an issue. The first time read_conf_file is called, we set this to be a Basset::Object.
155             #
156             #This way, we can successfully compile this module first, and have Basset::Object use it.
157 706 100       1692 unless (@Basset::Object::Conf::ISA) {
158 8         61 require Basset::Object;
159 8         211 @Basset::Object::Conf::ISA = qw(Basset::Object);
160             }
161              
162 706         1286 my %init = @_;
163            
164 706 50 33     3141 if (defined $init{'conf_files'} && ! ref $init{'conf_files'}) {
165 0         0 $init{'conf_files'} = [$init{'conf_files'}];
166             }
167              
168 706 50       2492 my @confs = reverse($init{'conf_files'} ? @{$init{'conf_files'}} : $class->conf_files);
  0         0  
169 706 50       2372 my $conf = $init{'conf_hash'} ? $init{'conf_hash'} : $class->conf;
170              
171 706         1987 $conf->{$default_package}->{'types'}->{'conf'} = $class;
172              
173 706         1476 foreach my $conf_file (@confs){
174 2824 100       38790 next unless -e $conf_file ;
175              
176 706 50 66     3198 if (! $class->loaded->{$conf_file} || -M $conf_file < $class->loaded->{$conf_file} || @_){
      66        
177              
178 8         16 my $pkg = $default_package;
179              
180 8         89 my $handle = $class->gen_handle;
181              
182 8 50       381 open ($handle, $conf_file) || next;
183 8         248 while (my $line = <$handle>) {
184              
185 336 100 66     5333 next if ! defined $line || $line =~ /^\s*#/ || $line =~ /^\s*$/;
      100        
186            
187 112 100       437 if ($line =~ /^define package\s+(\S+)/){
188 32         80 $pkg = $1;
189 32         281 next;
190             };
191            
192 80 50       362 if ($line =~ /^include file\s+(\S+)/) {
193 0         0 my $subconf = $class->read_conf_file($1);
194 0         0 foreach my $pkg (keys %$subconf) {
195 0         0 my $pkgconf = $conf->{$pkg};
196 0         0 my $subpkgconf = $subconf->{$pkg};
197 0         0 @$pkgconf{keys %$subpkgconf} = values %$subpkgconf;
198             };
199 0         0 next;
200             };
201            
202 80         1591 $line =~ s/(?:^\s+|\s+$)//g;
203 80 50       611 $line =~ /^(?:\s*(\d+)\s*:)?\s*([-+]?\w+)\s*([@%]?)=\s*(.+)/
204             or return $class->error("Invalid conf file : $line", "BOC-02");
205              
206 80         1343 my ($user, $key, $ref, $val) = ($1, $2, $3, $4);
207              
208 80 50       214 unless (defined $val){
209 0         0 ($user, $key, $ref, $val) = ($user, $key, undef, $ref);
210             };
211            
212 80 50       147 unless (defined $ref){
213 0         0 ($user, $key, $ref, $val) = (undef, $user, $ref, $key);
214             };
215              
216 80 50       504 ($user, $key, $val) = (undef, $user, $key) unless defined $val;
217            
218 80 50 33     245 next if defined $user && $user != $>;
219            
220 80 50       165 $val = undef if $val eq 'undef';
221              
222 80 50 33     795 $val = eval qq{return "$val"} if defined $val && $val =~ /^\\/;
223            
224 80 50       173 if ($ref) {
225 0 0       0 if ($ref eq '@') {
    0          
226 0   0     0 $conf->{$pkg}->{$key} ||= [];
227 0         0 push @{$conf->{$pkg}->{$key}}, $val;
  0         0  
228             } elsif ($ref eq '%') {
229 0   0     0 $conf->{$pkg}->{$key} ||= {};
230 0         0 my ($k, $v) = split(/\s*=\s*/, $val);
231 0         0 $conf->{$pkg}->{$key}->{$k} = $v;
232             }
233             }
234             else {
235 80         997 $conf->{$pkg}->{$key} = $val;
236             };
237             }; #end while
238 8         326 close $handle;
239            
240             #this is an irritating hack. In order to notify, types needs to be defined
241             #and chances are, this is the first place we'd define it due to circular inheritance
242             #issues.
243            
244 8 50       58 unless (! $class->loaded->{$conf_file}) {
245 0 0       0 Basset::Object->add_trickle_class_attr('types')
246             unless Basset::Object->can('types');
247 0         0 $class->notify('ConfFileReRead', $conf_file);
248             }
249              
250 8 50       161 $class->loaded->{$conf_file} = -M $conf_file unless @_;
251             }; #end if
252             }; #end foreach
253 706         3879 return $conf;
254            
255             }; #end sub
256              
257             1;
258              
259             __END__