File Coverage

blib/lib/Config/Context.pm
Criterion Covered Total %
statement 181 192 94.2
branch 78 94 82.9
condition 23 34 67.6
subroutine 20 20 100.0
pod 6 6 100.0
total 308 346 89.0


line stmt bran cond sub pod time code
1             package Config::Context;
2              
3 17     17   379923 use warnings;
  17         46  
  17         561  
4 17     17   104 use strict;
  17         34  
  17         564  
5              
6 17     17   91 use Carp;
  17         45  
  17         2622  
7 17     17   18133 use Hash::Merge ();
  17         55671  
  17         4893  
8 17     17   14331 use Clone ();
  17         59196  
  17         425  
9 17     17   135 use Cwd;
  17         30  
  17         37462  
10              
11             =head1 NAME
12              
13             Config::Context - Add C<< >> and C<< >> style context matching to hierarchical configfile formats such as Config::General, XML::Simple and Config::Scoped
14              
15             =head1 VERSION
16              
17             Version 0.10
18              
19             =cut
20              
21             our $VERSION = '0.10';
22              
23             =head1 SYNOPSIS
24              
25             =head2 Apache-style configs (via Config::General)
26              
27             use Config::Context;
28              
29             my $config_text = '
30              
31            
32             title = "User Area"
33            
34              
35            
36             image_file = 1
37            
38              
39             ';
40              
41             my $conf = Config::Context->new(
42             string => $config_text,
43             driver => 'ConfigGeneral',
44             match_sections => [
45             {
46             name => 'Location',
47             match_type => 'path',
48             },
49             {
50             name => 'LocationMatch',
51             match_type => 'regex',
52             },
53             ],
54             );
55              
56             my %config = $conf->context('/users/~mary/index.html');
57              
58             use Data::Dumper;
59             print Dumper(\%config);
60             --------
61             $VAR1 = {
62             'title' => 'User Area',
63             'image_file' => undef,
64             };
65              
66             my %config = $conf->context('/users/~biff/images/flaming_logo.gif');
67             print Dumper(\%config);
68             --------
69             $VAR1 = {
70             'title' => 'User Area',
71             'image_file' => 1,
72             };
73              
74             =head2 XML configs (via XML::Simple)
75              
76             use Config::Context;
77              
78             my $config_text = '
79            
80              
81            
82             User Area
83            
84              
85            
86             1
87            
88              
89            
90             ';
91              
92             my $conf = Config::Context->new(
93             string => $config_text,
94             driver => 'XMLSimple',
95             match_sections => [
96             {
97             name => 'Location',
98             match_type => 'path',
99             },
100             {
101             name => 'LocationMatch',
102             match_type => 'regex',
103             },
104             ],
105             );
106              
107             my %config = $conf->context('/users/~mary/index.html');
108              
109             use Data::Dumper;
110             print Dumper(\%config);
111             --------
112             $VAR1 = {
113             'title' => 'User Area',
114             'image_file' => undef,
115             };
116              
117             my %config = $conf->context('/users/~biff/images/flaming_logo.gif');
118             print Dumper(\%config);
119             --------
120             $VAR1 = {
121             'title' => 'User Area',
122             'image_file' => 1,
123             };
124              
125             =head2 Config::Scoped style configs
126              
127             use Config::Context;
128              
129             my $config_text = '
130             Location /users {
131             user_area = 1
132             }
133              
134             LocationMatch '\.*(jpg|gif|png)$' {
135             image_file = 1
136             }
137             ';
138              
139             my $conf = Config::Context->new(
140             string => $config_text,
141             driver => 'ConfigScoped',
142             match_sections => [
143             {
144             name => 'Location',
145             match_type => 'path',
146             },
147             {
148             name => 'LocationMatch',
149             match_type => 'regex',
150             },
151             ],
152             );
153              
154             my %config = $conf->context('/users/~mary/index.html');
155              
156             use Data::Dumper;
157             print Dumper(\%config);
158             --------
159             $VAR1 = {
160             'title' => 'User Area',
161             'image_file' => undef,
162             };
163              
164             my %config = $conf->context('/users/~biff/images/flaming_logo.gif');
165             print Dumper(\%config);
166             --------
167             $VAR1 = {
168             'title' => 'User Area',
169             'image_file' => 1,
170             };
171              
172              
173             =head1 DESCRIPTION
174              
175             =head2 Introduction
176              
177             This module provides a consistent interface to many hierarchical
178             configuration file formats such as L, L
179             and L.
180              
181             It also provides Apache-style context matching. You can include blocks
182             of configuration that match or not based on run-time parameters.
183              
184             For instance (using L syntax):
185              
186             company_name = ACME
187             in_the_users_area = 0
188              
189            
190             in_the_users_area = 1
191            
192              
193             At runtime, if C is within C, then the configuration
194             within the C<< >> block is merged into the top level.
195             Otherwise, the block is ignored.
196              
197             So if C is C, the configuration is reduced to:
198              
199             {
200             company_name => 'ACME',
201             in_the_users_area => 1,
202             }
203              
204             But if C is outside of the C area (e.g.
205             C), the configuration is reduced to:
206              
207             {
208             company_name => 'ACME',
209             in_the_users_area => 0,
210             }
211              
212             The exact mechanics of how C matches C is extensively
213             customizable. You can configure a particular block to match based on
214             exact string matches, a substring, a path, or a regex.
215              
216             This kind of context-based matching was inspired by Apache's
217             context-based configuration files.
218              
219             L works with Apache-style config files (via
220             L), XML documents (via L), and
221             L config files. You select the type config file with
222             the L option to L.
223              
224             The examples in this document use L (Apache-style)
225             syntax. For details on other configuration formats, see the
226             documentation for the appropriate driver.
227              
228             For a real world example of L in action, see
229             L, which determines
230             configurations based on the URL of the request, the name of the Perl
231             Module, and the virtual host handling the web request.
232              
233             =head2 The Default Section
234              
235             Config values that appear outside of any block act like defaults.
236             Values in matching sections are merged with the default values. For
237             instance:
238              
239             private_area = 0
240             client_area = 0
241              
242            
243             private_area = 1
244            
245              
246            
247             client_area = 1
248            
249              
250             # Admin Area URL
251             my %config = $conf->context('/admin/index.html');
252             use Data::Dumper;
253             print Dumper(\%config);
254             $VAR1 = {
255             'private_area' => 1,
256             'client_area' => 0,
257             };
258              
259             # Client Area URL
260             my %config = $conf->context('/clients/index.html');
261             print Dumper(\%config);
262             $VAR1 = {
263             'private_area' => 0,
264             'client_area' => 1,
265             };
266              
267             # Neither Client nor Admin
268             my %config = $conf->context('/public/index.html');
269             print Dumper(\%config);
270             $VAR1 = {
271             'private_area' => 0,
272             'client_area' => 0,
273             };
274              
275             When using the L driver, you must be
276             careful with the use of the default section, since L
277             does its own inheritance from the global scope into named sections. See
278             the documentation for L for more
279             information.
280              
281             =head2 Subsections are preserved
282              
283             When a block matches, and its configuration is merged into the top level,
284             any subsections that it contained are preserved along with single
285             values. For instance:
286              
287             # Default config
288             private_area = 0
289             client_area = 0
290            
291             title = "The Widget Emporium"
292             logo = logo.gif
293             advanced_ui = 0
294            
295              
296             # Admin config
297            
298             private_area = 1
299            
300             title = "The Widget Emporium - Admin Area"
301             logo = admin_logo.gif
302             advanced_ui = 1
303            
304            
305              
306             # Client config
307            
308             client_area = 1
309            
310             title = "The Widget Emporium - Wholesalers"
311             logo = client_logo.gif
312            
313            
314              
315             # Admin Area URL
316             my %config = $conf->context('/admin/index.html');
317              
318             use Data::Dumper;
319             print Dumper(\%config);
320             --------
321             $VAR1 = {
322             'page_settings' => {
323             'advanced_ui' => '1',
324             'title' => 'The Widget Emporium - Admin Area',
325             'logo' => 'admin_logo.gif'
326             },
327             'private_area' => '1',
328             'client_area' => '0'
329             };
330              
331             # Client Area URL
332             my %config = $conf->context('/clients/index.html');
333              
334             print Dumper(\%config);
335             --------
336             $VAR1 = {
337             'page_settings' => {
338             'advanced_ui' => '0',
339             'title' => 'The Widget Emporium - Wholesalers',
340             'logo' => 'client_logo.gif'
341             },
342             'client_area' => '1',
343             'private_area' => '0'
344             };
345              
346             # Neither Client nor Admin
347             my %config = $conf->context('/public/index.html');
348              
349             print Dumper(\%config);
350             --------
351             $VAR1 = {
352              
353             'page_settings' => {
354             'advanced_ui' => '0',
355             'title' => 'The Widget Emporium',
356             'logo' => 'logo.gif'
357             },
358             'client_area' => '0',
359             'private_area' => '0'
360              
361             };
362              
363              
364              
365             =head2 Multiple Sections Matching
366              
367             Often more than one section will match the target string. When this
368             happens, the matching sections are merged together using the
369             L module. Typically this means that sections that are
370             merged later override the values set in earlier sections. (But you can
371             change this behaviour. See L below.)
372              
373             The order of merging matters. The sections are merged first according
374             to each section's L value (lowest values are merged
375             first), and second by the length of the substring that matched (shortest
376             matches are merged first). If you don't specify L for
377             any section, they all default to a priority of C<0> which means all
378             sections are treated equally and matches are prioritized based soley on
379             the length of the matching strings.
380              
381             When two sections have the same priority, the section with the shorter
382             match is merged first. The idea is that longer matches are more
383             specific, and should have precidence.
384              
385             The order of sections in the config file is ignored.
386              
387             For instance, if your config file looks like this:
388              
389            
390             # section 1
391            
392              
393            
394             # section 2
395            
396              
397            
398             # section 3
399            
400              
401            
402             # section 4
403            
404              
405             ...and you construct your $conf object like this:
406              
407             my $conf = Config::Context->new(
408             driver => 'ConfigGeneral',
409             match_sections => [
410             { name => 'Directory', match_type => 'path' merge_priority => 1 },
411             { name => 'Dir', match_type => 'path' merge_priority => 1 },
412             { name => 'Path', match_type => 'path' merge_priority => 2 },
413             ],
414             );
415              
416             ...then the target string '/foo/bar/baz/bam/boom' would match all sections
417             the order of 1, 3, 4, 2.
418              
419             =head2 Matching Context based on More than one String
420              
421             You have different sections match against different run time values.
422             For instance, you could match some sections against the day of the week
423             and other sections against weather:
424              
425             my $config = '
426              
427             weekend = 0
428             background = ''
429              
430            
431             weekend = 1
432            
433              
434            
435             weekend = 1
436            
437              
438            
439             sky = blue
440            
441              
442            
443             sky = grey
444            
445             ';
446              
447             my $conf = Config::Context->new(
448             driver => 'ConfigGeneral',
449             match_sections => [
450             { name => 'Day', section_type => 'day', match_type => 'path' },
451             { name => 'Weekday', section_type => 'day', match_type => 'path' },
452             { name => 'Weather', section_type => 'weather', match_type => 'regex' },
453             ],
454             );
455              
456             my %config = $conf->context(day => 'Friday', weather => 'sunny');
457              
458             print Dumper(\%config);
459             --------
460             $VAR1 = {
461             'weekend' => 0,
462             'sky' => 'blue',
463             };
464              
465             my %config = $conf->context(day => 'Sunday', weather => 'partially cloudy');
466              
467             print Dumper(\%config);
468             --------
469             $VAR1 = {
470              
471             'weekend' => 1,
472             'sky' => 'grey',
473             };
474              
475              
476              
477             =head2 Matching other path-like strings
478              
479             You can use L to match other hierarchical strings
480             besides paths and URLs. For instance you could specify a
481             L of C<::> and use the path feature to match against Perl
482             modules:
483              
484             my $config_text = "
485              
486             is_core_module 0
487            
488             is_core_module 1
489             author Nathan Torkington
490            
491              
492            
493             author Richard Jone
494            
495              
496             ";
497              
498             my $conf = Config::Context->new(
499             driver => 'ConfigGeneral',
500             string => $config_text,
501             match_sections => [
502             {
503             name => 'Module',
504             path_separator => '::',
505             match_type => 'path',
506             },
507             ],
508             );
509              
510             my %config = $conf->context('Net::FTP');
511              
512             use Data::Dumper;
513             print Dumper(\%config);
514             --------
515             $VAR1 = {
516             'is_core_module' => 1,
517             'author' => 'Nathan Torkington',
518             };
519              
520              
521              
522              
523             =head2 Nested Matching
524              
525             You can have matching sections within matching sections:
526              
527            
528            
529             admin_area = 1
530            
531            
532            
533            
534             admin_area = 1
535            
536            
537              
538             Enable this feature by setting L parameter to L,
539             or by calling C<< $conf->nesting_depth($some_value) >>.
540              
541             B see the documentation of L for
542             the limitations of nesting with L files.
543              
544             =head1 CONSTRUCTOR
545              
546             =head2 new(...)
547              
548             Creates and returns a new L object.
549              
550             The configuration can be read from a file, parsed from a string, or can
551             be generated from a perl data struture.
552              
553             To read from a config file:
554              
555             my $conf = Config::Context->new(
556             file => 'somefile.conf',
557             driver => 'ConfigGeneral',
558             match_sections => [
559             { name => 'Directory', match_type => 'path' },
560             ],
561             );
562              
563             To parse from a string:
564              
565             my $text = '
566             in_the_users_area = 0
567            
568             in_the_users_area = 1
569            
570             ';
571              
572             my $conf = Config::Context->new(
573             string => $text,
574             driver => 'ConfigGeneral',
575             match_sections => [
576             { name => 'Directory', match_type => 'path' },
577             ],
578             );
579              
580             To generate from an existing Perl data structure:
581              
582             my %config = (
583             'in_the_user_area' => '0'
584             'Location' => {
585             '/users' => {
586             'in_the_user_area' => '1'
587             },
588             },
589             );
590              
591             my $conf = Config::Context->new(
592             config => \%config,
593             driver => 'ConfigGeneral',
594             match_sections => [
595             { name => 'Directory', match_type => 'path' },
596             ],
597             );
598              
599              
600             The parameters to new are described below:
601              
602             =head3 file
603              
604             The config file.
605              
606             =head3 string
607              
608             A string containing the configuration to be parsed. If L is
609             specified then L is ignored.
610              
611             =head3 config
612              
613             A Perl multi-level data structure containing the configuration. If
614             L is specified, then both L and L are ignored.
615              
616             =head3 driver
617              
618             Which L driver should parse the config. Currently
619             supported drivers are:
620              
621             driver module name
622             ------ -----------
623             ConfigGeneral Config::Context::ConfigGeneral
624             ConfigScoped Config::Context::ConfigScoped
625             XMLSimple Config::Context::XMLSimple
626              
627             =head3 driver_options
628              
629             Options to pass directly on to the driver. This is a multi-level hash,
630             where the top level keys are the driver names:
631              
632             my $conf = Config::Context->new(
633             driver => 'ConfigScoped',
634             driver_options => {
635             ConfigGeneral => {
636             -AutoLaunder => 1,
637             },
638             ConfigScoped = > {
639             warnings => {
640             permissions => 'off',
641             }
642             },
643             },
644             );
645              
646             In this example the options under C will be passed to the
647             C driver. (The options under C will be
648             ignored because C is not set to C<'ConfigGeneral'>.)
649              
650             =head3 match_sections
651              
652             The L parameter defines how L matches
653             runtime values against configuration sections.
654              
655             L takes a list of specification hashrefs. Each
656             specification has the following fields:
657              
658             =over 4
659              
660             =item B
661              
662             The name of the section. For a name of 'Location', the section would look like:
663              
664            
665            
666              
667             =item B
668              
669             Specifies the method by which the section strings should match the
670             target string.
671              
672             The valid types of matches are 'exact', 'substring', 'regex', 'path',
673             and 'hierarchical'
674              
675             =over 4
676              
677             =item exact
678              
679             The config section string matches only if it is equal to the target
680             string. For instance:
681              
682             # somefile.conf
683            
684             ...
685            
686             ...
687              
688             my $conf = Config::Context->new(
689             driver => 'ConfigGeneral'
690             match_sections => [
691             {
692             name => 'Site',
693             match_type => 'exact',
694             },
695             ],
696             file => 'somefile.conf',
697             );
698              
699             In this case, only the exact string C would match the section.
700              
701             =item substring
702              
703             The config section string is tested to see if it is a substring of the
704             target string. For instance:
705              
706             # somefile.conf
707            
708             ...
709            
710              
711             ...
712              
713             my $conf = Config::Context->new(
714             driver => 'ConfigGeneral'
715             match_sections => [
716             {
717             name => 'LocationMatch',
718             match_type => 'substring',
719             },
720             ],
721             file => 'somefile.conf',
722             );
723              
724             In this case, the following target strings would all match:
725              
726             /foo
727             big_foo.html
728             /hotfood
729              
730             =item regex
731              
732             The config section string is treated as a regular expression against
733             which the target string is matched. For instance:
734              
735             # somefile.conf
736            
737             Image = 1
738            
739              
740             ...
741              
742             my $conf = Config::Context->new(
743             driver => 'ConfigGeneral'
744             match_sections => [
745             {
746             name => 'LocationMatch',
747             match_type => 'regex',
748             },
749             ],
750             file => 'somefile.conf',
751             );
752              
753             my %config = $conf->context('banner.jpg');
754              
755             The regex can contain any valid Perl regular expression. So to match
756             case-insensitively you can use the C<(?i:)> syntax:
757              
758            
759             UserDir = 1
760            
761              
762             Also note that the regex is not tied to the beginning of the target
763             string by default. So for regexes involving paths you will probably
764             want to do so explicitly:
765              
766            
767             UserDir = 1
768            
769              
770             =item path
771              
772             This method is useful for matching paths, URLs, Perl Modules and other
773             hierarchical strings.
774              
775             The config section string is tested against the the target string.
776             It matches if the following are all true:
777              
778             =over 4
779              
780             =item *
781              
782             The section string is a substring of the target string
783              
784             =item *
785              
786             The section string starts at the first character of the target string
787              
788             =item *
789              
790             In the target string, the section string is followed immediately by
791             L or the end-of-string.
792              
793             =back
794              
795             For instance:
796              
797             # somefile.conf
798            
799            
800              
801             ...
802              
803             my $conf = Config::Context->new(
804             driver => 'ConfigGeneral'
805             match_sections => [
806             {
807             name => 'LocationMatch',
808             match_Type => 'path',
809             },
810             ],
811             file => 'somefile.conf',
812             );
813              
814             In this case, the following target strings would all match:
815              
816             /foo
817             /foo/
818             /foo/bar
819             /foo/bar.txt
820              
821             But the following strings would B match:
822              
823             /foo.txt
824             /food
825             /food/bar.txt
826             foo.txt
827              
828             =item hierarchical
829              
830             A synonym for 'path'.
831              
832             =back
833              
834             =item B
835              
836             The path separator when matching hierarchical strings (paths, URLs,
837             Module names, etc.). It defaults to '/'.
838              
839             This parameter is ignored unless the L is 'path' or
840             'hierarchical'.
841              
842             =item B
843              
844             Allows you to match certain sections against certain run time values.
845             For instance, you could match some sections against a given filesystem
846             path and some sections against a Perl module name, using the same config
847             file.
848              
849             # somefile.conf
850             # section 1
851            
852             Perl_Module = 1
853             Core_Module = 1
854             Installed_Module = 0
855            
856              
857             # section 2
858            
859             Core_Module = 0
860            
861              
862             # section 3
863             # Note the whitespace at the end of the section name, to prevent File from
864             # being parsed as a stand-alone block by Config::General
865            
866             Installed_Module = 1
867            
868              
869             # section 4
870            
871             FTP_Module = 1
872            
873              
874             my $conf = Config::Context->new(
875             driver => 'ConfigGeneral'
876             match_sections => [
877             {
878             name => 'FileMatch',
879             match_type => 'regex',
880             section_type => 'file',
881             },
882             {
883             name => 'File',
884             match_type => 'path',
885             section_type => 'file',
886             },
887             {
888             name => 'Module',
889             match_type => 'path',
890             separator => '::',
891             section_type => 'module',
892             },
893             ],
894             file => 'somefile.conf',
895              
896             # need to turn off C-style comment parsing because of the
897             # */ in the name of section 2
898             driver_options => {
899             ConfigGeneral => {
900             -CComments => 0,
901             }
902             },
903             );
904              
905             my %config = $conf->context(
906             file => '/usr/lib/perl5/site_perl/5.6.1/NET/FTP/Common.pm',
907             module => 'NET::FTP::Common',
908             );
909              
910             This tests C against
911             sections 1, 2 and 3 (and merging them in the order of shortest to
912             longest match, i.e. 1, 3, 2).
913              
914             Then it tests 'NET::FTP::Common' against section 4 (which also matches).
915             The resulting configuration is:
916              
917             use Data::Dumper;
918             print Dumper(\%config);
919             --------
920             $VAR1 = {
921             'Perl_Module' => 1,
922             'Core_Module' => 0,
923             'FTP_Module' => 1,
924             'Installed_Module' => 1,
925             };
926              
927             Another example:
928              
929             my %config = $conf->context(
930             file => '/var/www/cgi-lib/FTP/FTPServer.pm',
931             module => 'NET::FTPServer',
932             );
933              
934             This tests C against sections 1, 2
935             and 3, and matches only against section 1. Then it matches
936             'NET::FTPServer' against section 4 (which does not match). The
937             result is:
938              
939             use Data::Dumper;
940             print Dumper(\%config);
941             --------
942             $VAR1 = {
943             'Perl_Module' => 1,
944             'Core_Module' => 0,
945             'FTP_Module' => 0,
946             'Installed_Module' => 0,
947             };
948              
949              
950             If a L is not specified in a L block, then
951             target strings of a named type will not match it.
952              
953             For another example, see L, above.
954              
955             Matching by L is used in
956             L to determine configurations
957             based both on the URL of the request and of the name of the Perl Module
958             and runmode handling the request.
959              
960             =item B
961              
962             By default, section names are trimmed of leading and trailing whitespace
963             before they are used to match. This is to allow for sections like:
964              
965            
966            
967              
968             The whitespace at the end of the section name is necessary to prevent
969             L's parser from thinking that the first tag is an empty
970             C<< >> block.
971              
972             # Config::General parses this as
973             # Config::General now considers this to be spurious
974              
975             If leading and trailing whitespace is significant to your matches, you
976             can disable trimming by setting trim_section_names to C<0> or C.
977              
978             =item B
979              
980             Sections with a lower L are merged before sections with
981             a higher L. If two or more sections have the same
982             L they are weighted the same and they are merged
983             according to the "best match" against the target string (i.e. the
984             longest matching substring).
985              
986             See the description above under L.
987              
988             =back
989              
990             =head3 nesting_depth
991              
992             This option alows you to match against nested structures.
993              
994             # stories.conf
995            
996             antagonist = Big Bad Wolf
997             moral = obey the protestant work ethic
998            
999              
1000            
1001            
1002             antagonist = Big Bad Wolf
1003             moral = appearances are deceptive
1004            
1005            
1006              
1007            
1008             antagonist = Big Bad Wolf
1009              
1010            
1011             moral = never talk to strangers
1012            
1013              
1014            
1015             moral = talk to strangers and then chop them up
1016            
1017            
1018              
1019              
1020             my $conf = Config::Context->new(
1021             match_sections => [
1022             {
1023             name => 'Story',
1024             match_type => 'substring',
1025             section_type => 'story',
1026             },
1027             {
1028             name => 'Location',
1029             match_type => 'path',
1030             section_type => 'path',
1031             },
1032             ],
1033             file => 'stories.conf',
1034             nesting_depth => 2,
1035             );
1036              
1037             $config = $conf->context(
1038             story => 'Wolf in Sheep\'s Clothing',
1039             path => '/aesop/wolf-in-sheeps-clothing',
1040             );
1041              
1042             use Data::Dumper;
1043             print Dumper($config);
1044             --------
1045             $VAR1 = {
1046             'antagonist' => 'Big Bad Wolf',
1047             'moral' => 'appearances are deceptive'
1048             };
1049              
1050             You can also change the nesting depth by calling
1051             C<< $self->nesting_depth($depth) >> after you have constructed the
1052             L object.
1053              
1054             =head3 lower_case_names
1055              
1056             Attempts to force all section and key names to lower case. If
1057             L is true, then the following sections would
1058             all match 'location':
1059              
1060            
1061            
1062              
1063            
1064            
1065              
1066            
1067            
1068              
1069             B the C driver does not support this option.
1070              
1071             =head3 cache_config_files
1072              
1073             Whether or not to cache configuration files. Enabled, by default.
1074             This option is useful in a persistent environment such as C.
1075             See L under L, below.
1076              
1077             =head3 stat_config
1078              
1079             If config file caching is enabled, this option controls how often the
1080             config files are checked to see if they have changed. The default is 60
1081             seconds. This option is useful in a persistent environment such as
1082             C. See L under L, below.
1083              
1084             =cut
1085              
1086             sub new {
1087 39     39 1 8950652 my $proto = shift;
1088 39   33     307 my $class = ref $proto || $proto;
1089              
1090 39         105 my $self = {};
1091 39         119 bless $self, $class;
1092              
1093 39         237 my %args = @_;
1094              
1095              
1096 39         121 my $driver_opts = delete $args{'driver_options'};
1097 39         177 my $config = delete $args{'config'};
1098 39         81 my $file = delete $args{'file'};
1099 39         91 my $string = delete $args{'string'};
1100 39   100     200 my $match_sections = delete $args{'match_sections'} || [];
1101 39   100     252 my $nesting_depth = delete $args{'nesting_depth'} || 1;
1102 39         83 my $lower_case_names = delete $args{'lower_case_names'};
1103 39 100       167 my $cache_config_files = exists $args{'cache_config_files'} ? delete $args{'cache_config_files'} : 1;
1104 39 100       132 my $stat_config = exists $args{'stat_config'} ? delete $args{'stat_config'} : 60;
1105 39         94 my $driver_name = delete $args{'driver'};
1106              
1107 39 100       383 if (keys %args) {
1108 1         212 croak __PACKAGE__ . "->new(): unrecognized parameters: ". (join ', ', keys %args);
1109             }
1110              
1111 38         59 my ($raw_config, $files);
1112              
1113 38 100       106 if ($config) {
1114 1         3 $raw_config = $config;
1115             }
1116             else {
1117              
1118 37 100       147 if (!$driver_name) {
1119 1         87 croak __PACKAGE__ . "->new(): 'driver' is required for configurations read from file or string";
1120             }
1121 36 50       307 $driver_name =~ /^\w+$/ or croak __PACKAGE__ . "->new(): 'driver' must only contain word characters";
1122              
1123 36         388 my $driver_package = __PACKAGE__ . '::' . $driver_name;
1124              
1125 36         2420 eval "require $driver_package;";
1126 36 100       159 if ($@) {
1127 1         118 croak __PACKAGE__ . "->new(): Could not load config driver $driver_package: $@\n";
1128             }
1129              
1130 35 100       108 if ($string) {
    100          
1131 15         6392 my $driver = $driver_package->new(
1132             string => $string,
1133             lower_case_names => $lower_case_names,
1134             match_sections => $match_sections,
1135             nesting_depth => $nesting_depth,
1136             options => $driver_opts,
1137             );
1138 15         70 $raw_config = $driver->parse;
1139             }
1140             elsif($file) {
1141             # handle caching
1142 19 100       42 if ($cache_config_files) {
1143 15 100       56 if ($self->_cache_check_valid($file, $stat_config)) {
1144 7         19 $raw_config = $self->_cache_retrieve($file);
1145             }
1146             }
1147 19 100       59 if (!$raw_config) {
1148 12         103 my $driver = $driver_package->new(
1149             file => $file,
1150             lower_case_names => $lower_case_names,
1151             match_sections => $match_sections,
1152             nesting_depth => $nesting_depth,
1153             options => $driver_opts,
1154             );
1155 11         50 $raw_config = $driver->parse;
1156 11         51 $files = $driver->files;
1157              
1158 11 100       63 if ($cache_config_files) {
1159 8         46 $self->_cache_store($file, $raw_config, $files, time);
1160             }
1161             }
1162             }
1163             else {
1164 1         143 croak __PACKAGE__ . "->new(): one of 'file', 'string' or 'config' is required";
1165             }
1166             }
1167              
1168 34         149 $self->{'files'} = $files;
1169 34         84 $self->{'raw_config'} = $raw_config;
1170 34   50     124 $self->{'match_sections'} = $match_sections || [];
1171 34   50     104 $self->{'nesting_depth'} = $nesting_depth || 1;
1172 34         61 $self->{'lower_case_names'} = $lower_case_names;
1173              
1174 34         132 $self->{'reduced_config'} = $self->_reduce_nested;
1175              
1176 34         221 return $self;
1177             }
1178              
1179             =head1 METHODS
1180              
1181             =head2 raw()
1182              
1183             Returns the raw configuration data structure as read by the driver,
1184             before any context matching is performed.
1185              
1186             =cut
1187              
1188             sub raw {
1189 29     29 1 9505 my $self = shift;
1190 29 100       73 return %{ $self->{'raw_config'} } if wantarray;
  2         11  
1191 27         509 return $self->{'raw_config'};
1192             }
1193              
1194             =head2 context( $target_string )
1195              
1196             Returns the merged configuration of all sections matching
1197             C<$target_string>, according to the rules set up in
1198             L in L. All L are included,
1199             regardless of their L.
1200              
1201             =head2 context( $type => $target_string )
1202              
1203             Returns the merged configuration matching C<$target_string>, based only
1204             the Ls that have a L of C<$type>.
1205              
1206             =head2 context( $type1 => $target_string1, $type2 => $target_string2 )
1207              
1208             Returns the merged configuration of all sections of L
1209             C<$type1> matching C<$target_string1> and all sections of
1210             L C<$type2> matching C<$target_string2>.
1211              
1212             The order of the parameters to L is retained, so
1213             C<$type1> sections will be matched first, followed by C<$type2>
1214             sections.
1215              
1216             =head2 context( )
1217              
1218             If you call L without parameters, it will return the same
1219             configuration that was generated by the last call to L.
1220              
1221             If you call L in a scalar context, you will receive a
1222             reference to the config hash:
1223              
1224             my $config = $conf->context($target_string);
1225             my $value = $config->{'somekey'};
1226              
1227             In a list context, L returns a hash:
1228              
1229             my %config = $conf->context($target_string);
1230             my $value = $config{'somekey'};
1231              
1232             =cut
1233              
1234             sub context {
1235 68     68 1 97734 my $self = shift;
1236              
1237 68 50       213 if (@_) {
1238 68         169 $self->_reduce_nested(@_);
1239             }
1240              
1241 68 100       181 return %{ $self->{'reduced_config'} } if wantarray;
  59         385  
1242 9         26 return $self->{'reduced_config'};
1243             }
1244              
1245             =head2 files
1246              
1247             Returns a list of all the config files read, including any config files
1248             included in the main file.
1249              
1250             =cut
1251              
1252             sub files {
1253 1     1 1 5174 my $self = shift;
1254 1   50     7 my $files = $self->{'files'} || [];
1255 1 50       4 return @$files if wantarray;
1256 1         9 return $files;
1257             }
1258              
1259             # _reduce_nested()
1260             # iteratively calls _reduce_with_context $self->{'nesting_depth'} times
1261             # to reduce a nested config structure.
1262             sub _reduce_nested {
1263 102     102   144 my $self = shift;
1264              
1265             # make a copy
1266 102         3225 $self->{'reduced_config'} = Clone::clone( $self->{'raw_config'} );
1267              
1268 102         409 for (1 .. $self->{'nesting_depth'}) {
1269 110         300 $self->{'reduced_config'} = $self->_reduce_with_context($self->{'reduced_config'}, @_);
1270             }
1271             }
1272              
1273             # _reduce_with_context(...)
1274             # matches $config against the runtime values provided as in the pod for context:
1275             # $self->_reduce_with_context($config_hash, $type1 => $target_string1, $type2 => $target_string2);
1276              
1277             sub _reduce_with_context {
1278 110     110   158 my $self = shift;
1279 110         127 my $merged_config = shift;
1280              
1281 110         133 my $target_string;
1282             my $section_type;
1283              
1284 0         0 my @matches;
1285              
1286 110         277 while (@_) {
1287 96 100       248 if (@_ == 1) {
1288 49         64 $target_string = shift;
1289 49         67 $section_type = undef;
1290             }
1291             else {
1292 47         62 $section_type = shift;
1293 47         56 $target_string = shift;
1294             }
1295 96         267 push @matches, $self->_get_matching_sections($merged_config, $target_string, $section_type);
1296             }
1297              
1298             # Now sort the matching sections, first by MergePriority (lowest
1299             # first), second by length of the matching substring (shortest first)
1300             #
1301             # @matches contains a list of array refs whose first element is the
1302             # section's MergePriority, the second element is the number of
1303             # characters that matched, and the third element is the config hash
1304             # of the matching section
1305              
1306 110 50       354 foreach my $match (sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] } @matches) {
  66         196  
1307              
1308 87         8285 my $section_hash = $match->[2];
1309              
1310 87         272 $merged_config = Hash::Merge::merge($section_hash, $merged_config);
1311              
1312             }
1313              
1314 110 50       7549 return %$merged_config if wantarray;
1315 110         524 return $merged_config;
1316             }
1317              
1318             # _get_matching_sections()
1319             # a list the sections that match
1320             # the list contains array refs whose first element is the
1321             # section's merge_priority, the second element is the number of
1322             # characters that matched, and the third element is the config hash
1323             # of the matching section
1324              
1325             sub _get_matching_sections {
1326 96     96   118 my $self = shift;
1327 96         113 my $config = shift;
1328              
1329 96         176 my ($target_string, $target_section_type) = @_;
1330              
1331 96         156 my $match_sections = $self->{'match_sections'};
1332              
1333             # validation of -MatchSections
1334 96 50 33     744 unless ($match_sections and ref $match_sections eq 'ARRAY' and @$match_sections) {
      33        
1335 0         0 croak "Can't run context when no match_sections provided";
1336             }
1337              
1338 96         165 my %allowed_spec_keys = map { $_ => 1 } qw(
  576         1098  
1339             name
1340             match_type
1341             path_separator
1342             section_type
1343             merge_priority
1344             trim_section_names
1345             );
1346              
1347 96         146 my @matches;
1348              
1349             my $count;
1350 96         169 foreach my $spec (@$match_sections) {
1351 230         282 $count++;
1352              
1353 230         453 my @bad_spec_keys = grep { !$allowed_spec_keys{$_} } keys %$spec;
  722         1285  
1354 230 50       490 if (@bad_spec_keys) {
1355 0         0 croak "Unknown spec option(s): ".(join ', ', @bad_spec_keys);
1356             }
1357              
1358             # Must have name and MatchType
1359 230 50       502 my $name = $spec->{'name'} or croak "Spec #$count has no name";
1360 230 50       479 my $match_type = $spec->{'match_type'} or croak "Spec #$count has no match_type";
1361 230   100     727 my $path_sep = $spec->{'path_separator'} || '/';
1362 230   100     642 my $section_priority = $spec->{'merge_priority'} || 0;
1363 230         280 my $this_section_type = $spec->{'section_type'};
1364              
1365 230 100       438 my $trim_section_names = exists $spec->{'trim_section_names'} ? $spec->{'trim_section_names'} : 1;
1366              
1367 230 100       466 if ($self->{'lower_case_names'}) {
1368 2         4 $name = lc $name;
1369 2         20 $this_section_type = lc $this_section_type;
1370             }
1371              
1372             # Skip this section if the section's type does not match the type
1373             # of the target string. But only do so if the target_string has a type.
1374 230 100       409 if ($target_section_type) {
1375              
1376             # If the target_string has a type but the section doesn't then skip
1377 127 50       205 next unless $this_section_type;
1378              
1379             # If the target_string doesn't equal the section string then skip
1380 127 100       235 if ($target_section_type ne $this_section_type) {
1381 71         156 next;
1382             }
1383             }
1384              
1385 159 100       338 next unless exists $config->{$name};
1386              
1387 148         241 my $sections = delete $config->{$name};
1388              
1389              
1390 148         352 foreach my $section_string (keys %$sections) {
1391 237         366 my $section_hash = $sections->{$section_string};
1392              
1393 237 100       391 if ($trim_section_names) {
1394 233         1190 $section_string =~ s/^\s*(.*?)\s*$/$1/;
1395             }
1396              
1397 237 100 66     1093 if ($match_type =~ /^exact$/i) {
    100          
    100          
    50          
1398 34 100       162 if ($target_string eq $section_string) {
1399             # store matches as array ref where first element is
1400             # the section's MergePriority, the second element is
1401             # the length and the third is the config hash of
1402             # matching section
1403              
1404 5         27 push @matches, [
1405             $section_priority,
1406             length($section_string),
1407             $section_hash,
1408             ];
1409             }
1410             }
1411             elsif ($match_type =~ /^substring$/i) {
1412 17 100   17   15126 if ((index $target_string, $section_string) != ($[ - 1)) {
  17         7841  
  17         17088  
  56         311  
1413             # store matches as array ref where first element is
1414             # the section's MergePriority, the second element is
1415             # the length and the third is the config hash of
1416             # matching section
1417              
1418 25         105 push @matches, [
1419             $section_priority,
1420             length($section_string),
1421             $section_hash,
1422             ];
1423             }
1424             }
1425             elsif ($match_type =~ /^regex$/i) {
1426 53         554 my $regex = qr/$section_string/;
1427 53 100       921 if ($target_string =~ qr/($section_string)/) {
1428             # store matches as array ref where first element is
1429             # the section's MergePriority, the second element is
1430             # the length and the third is the config hash of
1431             # matching section
1432              
1433 23         161 push @matches, [
1434             $section_priority,
1435             length($1),
1436             $section_hash,
1437             ];
1438             }
1439             }
1440             elsif ($match_type =~ /^path$/i or $match_type =~ /^hierarchy$/i) {
1441              
1442 94         143 my $regex = quotemeta($section_string);
1443              
1444             # If the section string ends with $path_sep then
1445             # we have only to match the whole string
1446              
1447 94 100 100     2549 if (($section_string =~ /$path_sep$/ and $target_string =~ qr/^($regex)/)
      100        
1448              
1449             # otherwise, we have to find the section_string either at
1450             # the end of target_string or immediately followed by
1451             # $path_sep in target string
1452              
1453             or ($target_string =~ qr/^($regex)(?:$path_sep|$)/)) {
1454             # store matches as array ref where first element is
1455             # the section's MergePriority, the second element is
1456             # the length and the third is the config hash of
1457             # matching section
1458              
1459 34         221 push @matches, [
1460             $section_priority,
1461             length($1),
1462             $section_hash,
1463             ];
1464             }
1465             }
1466             else {
1467 0         0 croak "Bad match_type: $match_type";
1468             }
1469             }
1470             }
1471 96         439 return @matches;
1472             }
1473              
1474             =head2 nesting_depth()
1475              
1476             Changes the default nesting depth, for matching nested structures.
1477             See the L parameter to L.
1478              
1479             =cut
1480              
1481             sub nesting_depth {
1482 1     1 1 5 my $self = shift;
1483 1   50     5 $self->{'nesting_depth'} = shift || 0;
1484             }
1485              
1486             our %CC_Cache;
1487              
1488             # Cache format:
1489             # %CC_Cache = (
1490             # $absolute_filename1 => {
1491             # __CONFIG => $config_hash,
1492             # __CREATION_TIME => $creation_time, # time object was constructed
1493             #
1494             # __FILES => [ # array of fileinfo hashrefs,
1495             # # one per config file included
1496             # # by the primary config file
1497             # {
1498             # __FILENAME => $filename1, # name of file
1499             # __MTIME => $mtime1, # last modified time, in epoch seconds
1500             # __SIZE => $size1, # size, in bytes
1501             # __LASTCHECK => $time1, # last time we checked this file, in epoch seconds
1502             # },
1503             # {
1504             # __FILENAME => $filename2,
1505             # __MTIME => $mtime2,
1506             # __SIZE => $size2,
1507             # __LASTCHECK => $time2,
1508             # },
1509             # ]
1510             # }
1511              
1512             # _cache_retrieve($filename) # returns config_hash
1513             sub _cache_retrieve {
1514 7     7   11 my ($self, $config_file) = @_;
1515              
1516 7         239 my $abs_path = Cwd::abs_path($config_file);
1517              
1518 7         23 return $CC_Cache{$abs_path}->{'__CONFIG'};
1519             }
1520              
1521             # _cache_store($filename, $config, $files, $creation_time) # stores config
1522             sub _cache_store {
1523 8     8   61 my ($self, $config_file, $config, $files, $creation_time) = @_;
1524              
1525 8         375 my $abs_path = Cwd::abs_path($config_file);
1526              
1527 8         14 my @filedata;
1528              
1529 8         21 foreach my $file (@$files) {
1530 11         17 my $time = time;
1531 11         223 my ($size, $mtime) = (stat $file)[7,9];
1532 11         68 my %fileinfo = (
1533             '__FILENAME' => $file,
1534             '__LASTCHECK' => $time,
1535             '__MTIME' => $mtime,
1536             '__SIZE' => $size,
1537             );
1538 11         40 push @filedata, \%fileinfo;
1539             }
1540              
1541 8         170 $CC_Cache{$abs_path} = {
1542             '__CONFIG' => $config,
1543             '__CREATION_TIME' => $creation_time,
1544             '__FILES' => \@filedata,
1545             };
1546              
1547             }
1548              
1549             # _cache_check_valid($config_file, $stat_config)
1550             # - returns true if all config files associated with this file
1551             # are still valid.
1552             # - returns false if any of the configuration files have changed
1553             #
1554             # if a file was checked less than stat_seconds ago, then it is not even
1555             # checked, but assumed to be valid.
1556             # Otherwise it is checked again. If its mtime or size have changed
1557             # then it is assumed to be invalid.
1558             #
1559             # if any file has changed then the configuration is determined to
1560             # be invalid
1561              
1562             sub _cache_check_valid {
1563 15     15   173 my ($self, $config_file, $stat_config) = @_;
1564              
1565 15         775 my $abs_path = Cwd::abs_path($config_file);
1566              
1567 15 100       70 return unless exists $CC_Cache{$abs_path};
1568 11 50       55 return unless ref $CC_Cache{$abs_path}{'__FILES'} eq 'ARRAY';
1569              
1570 11         16 foreach my $fileinfo (@{ $CC_Cache{$abs_path}{'__FILES'} }) {
  11         41  
1571 11         23 my $time = time;
1572              
1573             # Don't stat the file unless our last check was more recent than
1574             # $stat_config seconds ago
1575              
1576             # but, if $stat_config is zero then always stat the file
1577              
1578 11 50       26 if ($stat_config) {
1579 11 100       51 next if ($fileinfo->{'__MTIME'} + $stat_config >= $time);
1580             }
1581              
1582 4         98 my ($size, $mtime) = (stat $fileinfo->{'__FILENAME'})[7,9];
1583              
1584             # return false if any differences
1585 4 100       34 return if $size != $fileinfo->{'__SIZE'};
1586 1 50       11 return if $mtime != $fileinfo->{'__MTIME'};
1587              
1588             # no change, so save the new stat info in the cache
1589 0         0 $fileinfo->{'__SIZE'} = $size;
1590 0         0 $fileinfo->{'__MTIME'} = $mtime;
1591 0         0 $fileinfo->{'__LASTCHECK'} = $time;
1592              
1593             }
1594 7         22 return 1;
1595             }
1596              
1597             =head2 clear_file_cache
1598              
1599             Clears the internal file cache. Class method.
1600              
1601             Config::Context->clear_file_cache;
1602             $conf->clear_file_cache;
1603              
1604             =cut
1605              
1606             sub clear_file_cache {
1607 4     4 1 6098 my $class = shift;
1608 4         22 %CC_Cache = ();
1609             }
1610              
1611             # Utility method for drivers to load their prerequsite modules
1612              
1613             sub _require_prerequisite_modules {
1614 27     27   64 my ($class, $driver_class) = @_;
1615              
1616 27         55 my @missing_modules;
1617              
1618 27         131 foreach my $module ($driver_class->config_modules) {
1619 27         1370 eval "require $module";
1620 27 50       155 if ($@) {
1621 0         0 push @missing_modules, $module;
1622             }
1623             }
1624 27 50       189 if (@missing_modules) {
1625 0           foreach my $module (@missing_modules) {
1626 0           warn "$driver_class: missing prerequisite module: $module\n";
1627             }
1628 0           die "Can't continue loading: $driver_class\n";
1629             }
1630             }
1631              
1632              
1633             =head1 ADVANCED USAGE
1634              
1635             =head2 Config File Caching
1636              
1637             By default each config file is read only once when the conf object is
1638             first initialized. Thereafter, on each init, the cached config is used.
1639              
1640             This means that in a persistent environment like mod_perl, the config
1641             file is parsed on the first request, but not on subsequent requests.
1642              
1643             If enough time has passed (sixty seconds by default) the config file is
1644             checked to see if it has changed. If it has changed, then the file is
1645             reread.
1646              
1647             If the driver supports it, any included files will be checked for
1648             changes along the main file. If you use L, you must
1649             use version 2.28 or greater for this feature to work correctly.
1650              
1651             To disable caching of config files pass a false value to the
1652             L parameter to L, e.g:
1653              
1654             my $conf = Config::Context->new(
1655             cache_config_files => 0,
1656             # ... other options here ...
1657             );
1658              
1659             To change how often config files are checked for changes, change the
1660             value of the L paramter to L, e.g.:
1661              
1662             my $conf = Config::Context->new(
1663             stat_config => 1, # check the config file every second
1664             # ... other options here ...
1665             );
1666              
1667             Internally the configuration cache is implemented by a hash, keyed by
1668             the absolute path of the configuration file. This means that if you
1669             have two applications running in the same process that both use the same
1670             configuration file, they will use the same cache.
1671              
1672             However, matching is performed on the config retrieved from the cache,
1673             so the two applications could each use different matching options
1674             creating different configurations from the same file.
1675              
1676             =head2 Changing Hash::Merge behaviour
1677              
1678             Matching sections are merged together using the L module.
1679             If you want to change how this module does its work you can call
1680             subroutines in the L package directly. For instance, to
1681             change the merge strategy so that earlier sections have precidence over
1682             later sections, you could call:
1683              
1684             # Note American Spelling :)
1685             Hash::Merge::set_behavior('RIGHT_PRECEDENT')
1686              
1687             You should do this before you call L.
1688              
1689             For more information on how to change merge options, see the
1690             L docs.
1691              
1692             =head1 AUTHOR
1693              
1694             Michael Graham, C<< >>
1695              
1696             =head1 BUGS
1697              
1698             Please report any bugs or feature requests to
1699             C, or through the web interface at
1700             L. I will be notified, and then you'll automatically
1701             be notified of progress on your bug as I make changes.
1702              
1703             =head1 COPYRIGHT & LICENSE
1704              
1705             Copyright 2005 Michael Graham, All Rights Reserved.
1706              
1707             This program is free software; you can redistribute it and/or modify it
1708             under the same terms as Perl itself.
1709              
1710             =cut
1711              
1712             1; # End of Config::Context