File Coverage

blib/lib/Catmandu/Env.pm
Criterion Covered Total %
statement 93 104 89.4
branch 26 38 68.4
condition 20 29 68.9
subroutine 18 19 94.7
pod 0 9 0.0
total 157 199 78.8


line stmt bran cond sub pod time code
1             package Catmandu::Env;
2              
3 154     154   109299 use Catmandu::Sane;
  154         402  
  154         1031  
4              
5             our $VERSION = '1.2020';
6              
7 154     154   1303 use Catmandu::Util qw(require_package use_lib read_yaml read_json :is :check);
  154         520  
  154         73148  
8 154     154   29714 use Catmandu::Fix;
  154         489  
  154         5242  
9 154     154   75933 use Config::Onion;
  154         2445251  
  154         5780  
10 154     154   1472 use File::Spec;
  154         506  
  154         4314  
11 154     154   1051 use Moo;
  154         466  
  154         905  
12             require Catmandu;
13 154     154   87496 use namespace::clean;
  154         444  
  154         1473  
14              
15             with 'Catmandu::Logger';
16              
17             sub _search_up {
18 0     0   0 my $dir = $_[0];
19 0         0 my @dirs = grep length, File::Spec->splitdir(Catmandu->default_load_path);
20 0         0 for (; @dirs; pop @dirs) {
21 0         0 my $path = File::Spec->catdir(File::Spec->rootdir, @dirs);
22 0 0       0 opendir my $dh, $path or last;
23             return $path
24 0 0       0 if grep {-r File::Spec->catfile($path, $_)}
  0         0  
25             grep /^catmandu.+(?:yaml|yml|json|pl)$/, readdir $dh;
26             }
27 0         0 Catmandu->default_load_path;
28             }
29              
30             has load_paths => (
31             is => 'ro',
32             default => sub {[]},
33             coerce => sub {
34             [
35             map {File::Spec->canonpath($_)}
36             map {$_ eq ':up' ? _search_up($_) : $_} split /,/,
37             join ',',
38             ref $_[0] ? @{$_[0]} : $_[0]
39             ];
40             },
41             );
42              
43             has config => (is => 'rwp', default => sub {+{}});
44              
45             has stores => (is => 'ro', default => sub {+{}});
46             has validators => (is => 'ro', default => sub {+{}});
47             has fixers => (is => 'ro', default => sub {+{}});
48              
49             has default_store => (is => 'ro', default => sub {'default'});
50             has default_importer => (is => 'ro', default => sub {'default'});
51             has default_exporter => (is => 'ro', default => sub {'default'});
52             has default_validator => (is => 'ro', default => sub {'default'});
53             has default_fixer => (is => 'ro', default => sub {'default'});
54              
55             has default_store_package => (is => 'ro');
56             has default_importer_package => (is => 'ro', default => sub {'JSON'});
57             has default_exporter_package => (is => 'ro', default => sub {'JSON'});
58             has default_validator_package => (is => 'ro');
59              
60             has store_namespace => (is => 'ro', default => sub {'Catmandu::Store'});
61             has importer_namespace => (is => 'ro', default => sub {'Catmandu::Importer'});
62             has exporter_namespace => (is => 'ro', default => sub {'Catmandu::Exporter'});
63             has validator_namespace =>
64             (is => 'ro', default => sub {'Catmandu::Validator'});
65              
66             sub BUILD {
67 66     66 0 501 my ($self) = @_;
68              
69 66         152 my @config_dirs = @{$self->load_paths};
  66         373  
70 66         214 my @lib_dirs;
71              
72 66         204 for my $dir (@config_dirs) {
73 66 50       1523 if (!-d $dir) {
74 0         0 Catmandu::Error->throw("load path $dir doesn't exist");
75             }
76              
77 66         771 my $lib_dir = File::Spec->catdir($dir, 'lib');
78              
79 66 50 33     1990 if (-d $lib_dir && -r $lib_dir) {
80 66         321 push @lib_dirs, $lib_dir;
81             }
82             }
83              
84 66 50       226 if (@config_dirs) {
85             my @globs = map {
86 66         206 my $dir = $_;
  66         139  
87 66         156 map {File::Spec->catfile($dir, "catmandu*.$_")}
  264         2248  
88             qw(yaml yml json pl)
89             } reverse @config_dirs;
90              
91 66         1392 my $config = Config::Onion->new(prefix_key => '_prefix');
92 66         59828 $config->load_glob(@globs);
93              
94 66 100       1099048 if ($self->log->is_debug) {
95 154     154   335977 use Data::Dumper;
  154         719  
  154         167847  
96 13         727 $self->log->debug(Dumper($config->get));
97             }
98 66         71515 $self->_set_config($config->get);
99             }
100              
101 66 50       17012 if (@lib_dirs) {
102 66         569 lib->import(@lib_dirs);
103             }
104             }
105              
106             sub load_path {
107 2     2 0 24 $_[0]->load_paths->[0];
108             }
109              
110             sub roots {
111 5     5 0 167 goto &load_paths;
112             }
113              
114             sub root {
115 2     2 0 795 goto &load_path;
116             }
117              
118             sub fixer {
119 12     12 0 3133 my $self = shift;
120              
121             # it's already a fixer
122 12 50       74 if (is_instance($_[0], 'Catmandu::Fix')) {
123 0         0 return $_[0];
124             }
125              
126             # an array ref of fixes
127 12 100       86 if (is_array_ref($_[0])) {
128 2         28 return Catmandu::Fix->new(fixes => $_[0]);
129             }
130              
131             # a single fix
132 10 50       48 if (is_able($_[0], 'fix')) {
133 0         0 return Catmandu::Fix->new(fixes => [$_[0]]);
134             }
135              
136             # try to load from config
137 10   66     48 my $key = $_[0] || $self->default_fixer;
138              
139 10         45 my $fixers = $self->fixers;
140              
141 10 50       61 $fixers->{$key} || do {
142 10 100       72 if (my $fixes = $self->config->{fixer}{$key}) {
143 3         44 return $fixers->{$key} = Catmandu::Fix->new(fixes => $fixes);
144             }
145 7         137 return Catmandu::Fix->new(fixes => [@_]);
146             };
147             }
148              
149             sub store {
150 29     29 0 196 my $self = shift;
151 29         261 $self->_named_package('store', $self->store_namespace,
152             $self->default_store, $self->default_store_package,
153             $self->stores, @_);
154             }
155              
156             sub importer {
157 41     41 0 746 my $self = shift;
158 41         434 $self->_named_package('importer', $self->importer_namespace,
159             $self->default_importer, $self->default_importer_package,
160             undef, @_);
161             }
162              
163             sub exporter {
164 55     55 0 538 my $self = shift;
165 55         424 $self->_named_package('exporter', $self->exporter_namespace,
166             $self->default_exporter, $self->default_exporter_package,
167             undef, @_);
168             }
169              
170             sub validator {
171 2     2 0 5 my $self = shift;
172 2         28 $self->_named_package(
173             'validator', $self->validator_namespace,
174             $self->default_validator, $self->default_validator_package,
175             $self->validators, @_
176             );
177             }
178              
179             sub _named_package {
180 127     127   345 my $self = shift;
181 127         287 my $type = shift;
182 127         222 my $ns = shift;
183 127         253 my $default_name = shift;
184 127         259 my $default_package = shift;
185 127         245 my $cache = shift;
186 127         251 my $name = shift;
187 127   66     383 my $key = $name || $default_name;
188              
189 127 100 66     517 return $name if is_instance($name) && index(ref($name), $ns) == 0;
190              
191             # return cached instance if no arguments are given
192 126 100 100     626 if ($cache && !@_ and my $instance = $cache->{$key}) {
      100        
193 12         70 return $instance;
194             }
195              
196 114 50       507 if (exists $self->config->{$type}) {
197 114 100       584 if (my $c = $self->config->{$type}{$key}) {
198 25         145 check_hash_ref($c);
199 25   33     5592 check_string(my $package = $c->{package} || $default_package);
200 25   100     4395 my $opts = check_hash_ref($c->{options} || {});
201 25 100       733 if (@_ > 1) {
    100          
202 1         6 $opts = {%$opts, @_};
203             }
204             elsif (@_ == 1) {
205 6         24 $opts = {%$opts, %{$_[0]}};
  6         24  
206             }
207 25         117 my $instance = require_package($package, $ns)->new($opts);
208              
209             # cache this instance if no arguments are given
210 25 100 100     285 if ($cache && !@_) {
211 10         109 $cache->{$key} = $instance;
212             }
213              
214 25         330 return $instance;
215             }
216             }
217              
218 89   33     519 check_string(my $package = $name || $default_package);
219 89         9019 require_package($package, $ns)->new(@_);
220             }
221              
222             1;
223              
224             __END__
225              
226             =pod
227              
228             =head1 NAME
229              
230             Catmandu::Env - A catmandu configuration file loader
231              
232             =head1 SYNOPSIS
233              
234             use Catmandu::Env;
235              
236             my $env = Catmandu::Env->new(load_paths => [ '/etc/catmandu '] );
237             my $env = Catmandu::Env->new(load_paths => [ ':up'] );
238              
239             my $store = $env->store('mongodb');
240             my $importer = $env->importer('loc');
241             my $exporter = $env->exporter('europeana');
242             my $fixer = $env->fixer('my_fixes');
243             my $conf = $env->config;
244              
245             =head1 DESCRIPTION
246              
247             This class loads the catmandu.*.pl, catmandu.*.json, catmandu.*.yml and catmandu.*.yaml file from
248             all provided load_paths. Programmers are advised I<not> to use this class directly
249             but use the equivalent functionality provided in the Catmandu package:
250              
251             Catmandu->load('/etc/catmandu');
252             Catmandu->load(':up');
253              
254             my $store = Catmandu->store('mongodb');
255             my $importer = Catmandu->importer('loc');
256             my $exporter = Catmandu->exporter('europeana');
257             my $fixer = Catmandu->fixer('my_fixes');
258             my $conf = Catmandu->config;
259              
260             =head1 SEE ALSO
261              
262             L<Catmandu>
263              
264             =cut