File Coverage

blib/lib/Config/FromHash.pm
Criterion Covered Total %
statement 65 80 81.2
branch 16 32 50.0
condition 6 13 46.1
subroutine 10 13 76.9
pod 0 7 0.0
total 97 145 66.9


line stmt bran cond sub pod time code
1 1     1   37940 use strict;
  1         2  
  1         58  
2 1     1   5 use warnings;
  1         1  
  1         27  
3 1     1   1107 use 5.10.1;
  1         4  
4              
5             package Config::FromHash;
6              
7             our $VERSION = '0.0800'; # VERSION
8             # ABSTRACT: Read config files containing hashes
9              
10 1     1   4 use File::Basename();
  1         3  
  1         15  
11 1     1   815 use Hash::Merge();
  1         2713  
  1         25  
12 1     1   1262 use Path::Tiny;
  1         10495  
  1         946  
13              
14              
15             sub new {
16 2     2 0 418 my($class, %args) = @_;
17              
18 2   50     8 $args{'data'} ||= {};
19 2   33     16 $args{'sep'} ||= qr{/};
20 2   50     10 $args{'require_all_files'} ||= 0;
21 2         5 $args{'config_files'} = [];
22              
23 2 50 66     10 if(exists $args{'filename'} && exists $args{'filenames'}) {
24 0         0 die "Don't use both 'filename' and 'filenames'.";
25             }
26 2 0 33     7 if(exists $args{'environment'} && exists $args{'environments'}) {
27 0         0 die "Don't use both 'environment' and 'environments'.";
28             }
29              
30 2 100       6 $args{'filenames'} = $args{'filename'} if exists $args{'filename'};
31 2 50       6 $args{'environments'} = $args{'environment'} if exists $args{'environment'};
32              
33              
34 2 100       6 if(exists $args{'filenames'}) {
35 1 50       5 if(ref $args{'filenames'} ne 'ARRAY') {
36 0         0 $args{'filenames'} = [ $args{'filenames'} ];
37             }
38             }
39             else {
40 1         2 $args{'filenames'} = [];
41             }
42              
43 2 50       6 if(exists $args{'environments'}) {
44 0 0       0 if(ref $args{'environments'} ne 'ARRAY') {
45 0         0 $args{'environments'} = [ $args{'environments'} ];
46             }
47             }
48             else {
49 2         5 $args{'environments'} = [ undef ];
50             }
51              
52 2         5 my $self = bless \%args => $class;
53              
54 2         8 Hash::Merge::set_behavior('LEFT_PRECEDENT');
55              
56 2 100       33 if(scalar @{ $args{'filenames'} }) {
  2         8  
57              
58 1         2 foreach my $environment (reverse @{ $args{'environments'} }) {
  1         3  
59              
60             FILE:
61 1         1 foreach my $config_file (reverse @{ $args{'filenames'} }) {
  1         3  
62 1         63 my($filename, $directory, $extension) = File::Basename::fileparse($config_file, qr{\.[^.]+$});
63 1 50       22 my $new_filename = $directory . $filename . (defined $environment ? ".$environment" : '') . $extension;
64              
65 1 50       40 if(!-e $new_filename) {
66 0 0       0 die "$new_filename does not exist" if $self->require_all_files;
67 0         0 next FILE;
68             }
69              
70 1         2 push @{ $args{'config_files'} } => $new_filename;
  1         3  
71 1         4 $args{'data'} = Hash::Merge::merge($self->parse($new_filename, $args{'data'}));
72              
73             }
74             }
75             }
76              
77 2         3839 return $self;
78              
79             }
80              
81             sub data {
82 0     0 0 0 return shift->{'data'};
83             }
84              
85             sub get {
86 5     5 0 776 my $self = shift;
87 5         10 my $path = shift;
88              
89 5 50       13 if(!defined $path) {
90 0         0 warn "No path defined - nothing to return";
91 0         0 return;
92             }
93              
94 5         26 my @parts = split $self->{'sep'} => $path;
95 5         9 my $hash = $self->{'data'};
96              
97 5         9 foreach my $part (@parts) {
98 8 50       19 if(ref $hash eq 'HASH') {
99 8         18 $hash = $hash->{ $part };
100             }
101             else {
102 0         0 die "Can't resolve path '$path' to '$part'";
103             }
104             }
105 5         27 return $hash;
106             }
107              
108             sub config_files {
109 0     0 0 0 my $self = shift;
110 0         0 return @{ $self->{'config_files'} };
  0         0  
111             }
112              
113             sub parse {
114 1     1 0 2 my $self = shift;
115 1         2 my $file = shift;
116              
117 1         5 my $contents = path($file)->slurp_utf8;
118 1         1569 my($parsed, $error) = $self->eval($contents);
119              
120 1 50       5 die "Can't parse <$file>: $error" if $error;
121 1 50       5 die "<$file> doesn't contain hash" if ref $parsed ne 'HASH';
122              
123 1         5 return $parsed;
124              
125             }
126              
127             sub eval {
128 1     1 0 2 my $self = shift;
129 1         1 my $contents = shift;
130              
131 1         55 return (eval $contents, $@);
132             }
133              
134             sub require_all_files {
135 0     0 0   return shift->{'require_all_files'};
136             }
137              
138              
139             1;
140              
141             __END__