File Coverage

blib/lib/Config/Multi.pm
Criterion Covered Total %
statement 93 93 100.0
branch 17 20 85.0
condition 9 11 81.8
subroutine 13 13 100.0
pod 1 1 100.0
total 133 138 96.3


line stmt bran cond sub pod time code
1             package Config::Multi;
2              
3 9     9   1026788 use strict;
  9         27  
  9         1056  
4 9     9   54 use warnings;
  9         17  
  9         248  
5 9     9   48 use Carp;
  9         21  
  9         854  
6 9     9   18643 use Config::Any;
  9         179493  
  9         390  
7 9     9   9698 use Unicode::RecursiveDowngrade;
  9         12756  
  9         261  
8 9     9   10724 use Encode;
  9         148221  
  9         1903  
9 9     9   11171 use DirHandle;
  9         26944  
  9         287  
10 9     9   71 use File::Spec;
  9         18  
  9         274  
11            
12 9     9   49 use base qw/Class::Accessor/;
  9         15  
  9         2063  
13              
14             our $VERSION = '0.12';
15              
16             __PACKAGE__->mk_accessors(qw/app_name prefix dir files extension unicode/);
17              
18             sub load {
19 11     11 1 129026 my $self = shift;
20 11         37 my @files = ();
21 11   100     279 $self->{extension} ||= 'yml';
22 11 50       67 croak('you must set dir') unless $self->{dir};
23 11 50       71 croak('you must set app_name') unless $self->{app_name};
24              
25 11         32 my $config = {};
26              
27 11         63 my $app_files = $self->_find_files( $self->{app_name} );
28 11         671 my $app = Config::Any->load_files( { use_ext => 1, files => $app_files } );
29 11         161748 for ( @{$app} ) {
  11         45  
30 29         93 my ( $filename, $data ) = %$_;
31 29         58 push @files, $filename;
32 29         37 $config = { %{$config}, %{$data} };
  29         76  
  29         207  
33             }
34              
35 11 100       74 if ( $self->{prefix} ) {
36 7         57 my $prefix_files
37             = $self->_find_files( $self->{prefix} . '_' . $self->{app_name} );
38 7         369 my $prefix = Config::Any->load_files( { use_ext => 1, files => $prefix_files } );
39 7         56811 for ( @{$prefix} ) {
  7         32  
40 15         45 my ( $filename, $data ) = %$_;
41 15         27 push @files, $filename;
42 15         21 $config = { %{$config}, %{$data} };
  15         52  
  15         157  
43             }
44             }
45              
46 11         79 my $local_files = $self->_local_files;
47 11         107 my $local = Config::Any->load_files( { use_ext => 1, files => $local_files } );
48 11         69075 my $local_config = {} ;
49 11         27 for ( @{$local} ) {
  11         36  
50 13         40 my ( $filename, $data ) = %$_;
51 13         29 push @files, $filename;
52 13         39 $local_config->{$filename} = $data;
53             }
54              
55 11         23 for (@{$local_files} ) {
  11         30  
56 13         20 $config = { %{$config}, %{ $local_config->{$_} } };
  13         51  
  13         163  
57             }
58              
59 11         42 $self->{files} = \@files;
60              
61 11 100       71 if ( $self->unicode ) {
62 2         43 my $rd = Unicode::RecursiveDowngrade->new;
63 2     14   23 $rd->filter(sub { Encode::decode('utf8',shift) });
  14         622  
64 2         35 $config = $rd->downgrade($config);
65             }
66              
67 11         311 return $config;
68             }
69              
70             sub _local_files {
71 11     11   111 my $self = shift;
72 11         58 my $env_app_key = 'CONFIG_MULTI_' . uc( $self->{app_name} );
73 11         30 my @files = ();
74 11   66     126 my $app_local = $ENV{$env_app_key}
75             || File::Spec->catfile( $self->dir,
76             $self->{app_name} . '_local.' . $self->extension );
77 11 100       753 push @files, $app_local if -e $app_local;
78              
79 11 100       48 if ( $self->{prefix} ) {
80 7         37 my $env_prefix_key
81             = 'CONFIG_MULTI_'
82             . uc( $self->{prefix} ) . '_'
83             . uc( $self->{app_name} );
84 7   66     56 my $prefix_local = $ENV{$env_prefix_key} || File::Spec->catfile(
85             $self->dir,
86             $self->{prefix} . '_'
87             . $self->{app_name}
88             . '_local.'
89             . $self->extension
90             );
91 7 100       342 push @files, $prefix_local if -e $prefix_local;
92             }
93              
94 11         41 return \@files;
95             }
96              
97             sub _find_files {
98 18     18   44 my $self = shift;
99 18         94 my $path = $self->dir;
100 18         272 my $label = shift;
101 18         76 my $extension = $self->extension;
102              
103 18         162 my @files;
104 18 50       156 my $dh = DirHandle->new($path) or croak "Could not Open " . $path;
105              
106 18         2009 while ( my $file = $dh->read() ) {
107 288 100       3143 next if $file =~ /local\.$extension$/;
108 254 100 100     2877 if ( $file =~ /^$label\.$extension$/
109             || $file =~ /^$label\_(\w+)\.$extension$/ )
110             {
111 44         695 push @files, File::Spec->catfile( $path, $file );
112             }
113             }
114              
115 18         313 return \@files;
116             }
117              
118             1;
119              
120             =head1 NAME
121              
122             Config::Multi - load multiple config files.
123              
124             =head1 SYNOPSIS
125              
126             use Config::Multi;
127             use File::Spec;
128             use FindBin;
129            
130             my $dir = File::Spec->catfile( $FindBin::Bin , 'conf' );
131              
132             # prefix, extension and unicode is optional.
133             my $cm
134             = Config::Multi->new({
135             dir => $dir ,
136             app_name => 'myapp' ,
137             prefix => 'web' ,
138             extension => 'yml' ,
139             unicode => 1 # unicode option
140             });
141             my $config = $cm->load();
142             my $loaded_config_files = $cm->files;
143              
144             =head1 DESCRIPTION
145              
146             This module load multiple config files using L. You can specify directory and put into your config files!
147              
148             I create this module because I want to load not only loading multiple config files but also switch config files depend on interface I am using. like, I want to load web.yml only for web interface configuration and cli.yml for only for client interface configuration. let me explain step by step at EXAMPLE section.
149              
150             =head1 EXAMPLE
151              
152             =head2 your configuration files
153              
154             This is under your ~/myapp/conf/ and have yaml configuration in each files. you can specify the directory using dir option.
155              
156             .
157             |-- env-prefix.yml
158             |-- env.yml
159             |-- myapp.yml
160             |-- myapp_boin.yml
161             |-- myapp_local.yml
162             |-- myapp_oppai.yml
163             |-- never_load.yml
164             |-- web_myapp.yml
165             |-- web_myapp_cat.yml
166             |-- web_myapp_dog.yml
167             `-- web_myapp_local.yml
168              
169             =head2 switchable
170              
171             when you set app_name as 'myapp' and prefix as 'jobqueue' then below files are loaded
172              
173             |-- myapp.yml
174             |-- myapp_boin.yml
175             |-- myapp_local.yml
176             |-- myapp_oppai.yml
177              
178             ${app_name}.yml or ${app_name}_*.yml
179              
180             when you set app_name as 'myapp' and prefix as 'web' then below files are loaded
181              
182             |-- myapp.yml
183             |-- myapp_boin.yml
184             |-- myapp_local.yml
185             |-- myapp_oppai.yml
186             |-- web_myapp.yml
187             |-- web_myapp_cat.yml
188             |-- web_myapp_dog.yml
189             `-- web_myapp_local.yml
190              
191             ${prefix}_${myapp}.yml ${prefix}_${myapp}_*.yml
192              
193             YES! you can switch config files depend on what you set for app_name and prefix.
194              
195             =head2 overwrite rule.
196              
197             there is also overwriting rule. there are three steps for this.
198              
199              
200             _local.yml file overwrite the other config setting
201              
202             ${prefix}_${app_name}_local.yml
203             ${app_name}_local.yml
204              
205             ${prefix}_ files overwrite ${app_name} config setting
206              
207             ${app_name}.yml, ${app_name}_*.yml (not include ${app_name}_local.yml)
208              
209             app config.
210              
211             ${prefix}_${myapp}.yml ${prefix}_${myapp}_*.yml
212              
213             =head2 $ENV setting
214              
215             instead of ${prefix}_${app_name}_local.yml , you can specify the path with $ENV{CONFIG_MULTI_PREFIX_MYAPP}
216              
217             instead of ${app_name}_local.yml , you can specify the path with $ENV{CONFIG_MULTI_MYAPP}
218              
219             note. PREFIX = uc($prefix); MYAPP = uc($app_name)
220              
221             =head2 unicode option
222              
223             if you set true to unicode option, return $config of flagged UTF-8.
224             in the future, this option will also be posiible to default.
225             at least I would hope so.
226              
227             =head1 METHODS
228              
229             =head2 new
230            
231             constructor SEE CONSTRUCTOR ARGUMENT section.
232              
233             =head2 load
234              
235             load config files and return config data.
236              
237             =head2 files
238              
239             get array references of loaded config files. You can use this method after call load() method.
240              
241             =head1 CONSTRUCTOR ARGUMENT
242              
243             =head2 app_name
244              
245             your application name. use [a-z]+ for format.
246              
247             =head2 prefix
248              
249             prefix name . use [a-z]+ for format. this is optional. if you did not set. only application config is loaded(include appname_local.yml if you have. )
250              
251             =head2 dir
252              
253             specify directory where your config files are located.
254              
255             =head2 extension
256              
257             you must specify extension for your config files. default is yml.
258              
259             =head1 SEE ALSO
260              
261             L
262              
263             =head1 AUTHOR
264              
265             Tomohiro Teranishi
266              
267             =head1 THANKS
268              
269             vkgtaro
270              
271             =head1 COPYRIGHT
272              
273             This module is copyright 2008 Tomohiro Teranishi.
274              
275             =head1 LICENSE
276              
277             This library is free software; you can redistribute it and/or modify
278             it under the same terms as Perl itself.
279              
280             =cut
281