File Coverage

blib/lib/Flexconf.pm
Criterion Covered Total %
statement 81 121 66.9
branch 28 58 48.2
condition 8 17 47.0
subroutine 12 19 63.1
pod 0 13 0.0
total 129 228 56.5


line stmt bran cond sub pod time code
1             package Flexconf;
2 2     2   1579 use 5.008001;
  2         14  
3 2     2   17 use strict;
  2         6  
  2         61  
4 2     2   16 use warnings;
  2         5  
  2         163  
5              
6             our $VERSION = "0.01";
7              
8             =encoding utf-8
9              
10             =head1 NAME
11              
12             Flexconf - Configuration files management library and program
13              
14             =head1 SYNOPSIS
15              
16             use Flexconf;
17              
18             my $conf = Flexconf->new({k=>'v',...} || nothing)
19              
20             # parse or stringify, format: 'json'||'yaml'
21             $conf->parse(format => '{"k":"v"}')
22             $string = $conf->stringify('format')
23              
24             # save or load, format (may be ommitted): 'auto'||'json'||'yaml'
25             $conf->load(format => $filename)
26             $conf->save(firmat => $filename)
27             $conf->load($filename) # autodetect format by file ext
28             $conf->save($filename) # autodetect format by file ext
29              
30             # replace whole tree
31             $conf->data({k=>'v',...})
32              
33             # access to root of conf tree
34             $root = $conf->data
35             $root = $conf->get
36              
37             # access to subtree in depth by path
38             $module_conf = $conf->get('app.module')
39              
40             # assign subtree in depth by path
41             $conf->assign('h', {a=>[]})
42             $conf->assign('h.a.0', [1,2,3])
43             $conf->assign('h.a.0.2', {k=>'v'})
44              
45             # copy subtree to another location
46             $conf->copy('to', 'from')
47             $conf->copy('k.a', 'h.a.0')
48              
49             # remove subtree by path
50             $conf->remove('k.v')
51              
52             =head1 DESCRIPTION
53              
54             Flexconf is base for configuration management
55              
56             =cut
57              
58              
59 2     2   685 use Flexconf::Json;
  2         9  
  2         78  
60 2     2   712 use Flexconf::Yaml;
  2         9  
  2         3960  
61              
62             sub new {
63 5     5 0 1135 my ($package, $data) = @_;
64 5         40 my $self = bless {data => $data}, $package;
65             }
66              
67             sub data {
68 25     25 0 54 my ($self, $data) = @_;
69              
70 25 100       88 return $self->{data} if 1 == scalar @_;
71              
72 3         8 my $prev_data = $self->{data};
73 3         7 $self->{data} = $data;
74 3         12 return $prev_data;
75             }
76              
77              
78             sub _namespace {
79 0     0   0 my ($self, $type) = @_;
80 0 0       0 return 'Flexconf::Json' if 'json' eq $type;
81 0 0       0 return 'Flexconf::Yaml' if 'yaml' eq $type;
82 0         0 die 'wrong conf format'
83             }
84              
85              
86             sub type_by_filename {
87 0     0 0 0 my ($self, $filename) = @_;
88 0 0       0 return 'json' if $filename =~ /\.json$/;
89 0 0       0 return 'yaml' if $filename =~ /\.yaml$/;
90 0 0       0 return 'yaml' if $filename =~ /\.yml$/;
91 0         0 die 'unable to dermine conf format by filename'
92             }
93              
94              
95             sub stringify {
96 0     0 0 0 my ($self, $type) = @_;
97 0         0 my $namespace = $self->_namespace($type);
98 0         0 return (\"$namespace::stringify")->($self->data);
99             }
100              
101              
102             sub parse {
103 0     0 0 0 my ($self, $type, $string) = @_;
104 0         0 my $namespace = $self->_namespace($type);
105 0         0 $self->data((\"$namespace::parse")->(), $string);
106             }
107              
108              
109             sub save {
110 0     0 0 0 my ($self, $type, $filename) = @_;
111 0 0       0 if( 2 == scalar @_ ) {
112 0         0 $filename = $type;
113 0         0 $type = 'auto';
114             }
115 0 0       0 $type = $self->type_by_filename($filename) if $type eq 'auto';
116 0         0 my $namespace = $self->_namespace($type);
117 0         0 (\"$namespace::save")->($filename, $self->data);
118             }
119              
120              
121             sub load {
122 0     0 0 0 my ($self, $type, $filename) = @_;
123 0 0       0 if( 2 == scalar @_ ) {
124 0         0 $filename = $type;
125 0         0 $type = 'auto';
126             }
127 0 0       0 $type = $self->type_by_filename($filename) if $type eq 'auto';
128 0         0 my $namespace = $self->type_by_filename($filename);
129 0         0 $self->data( (\"$namespace::load")->($filename) );
130             }
131              
132              
133             sub path_to_array {
134 31     31 0 70 my ($self, $path) = @_;
135 31 100       90 $path = $self if 1 == scalar @_;
136 31   100     169 $path = $path || '';
137 31 100       135 $path = [split(/\./, $path)] if 'ARRAY' ne ref $path;
138 31         88 return $path;
139             }
140              
141              
142             sub path_to_str {
143 0     0 0 0 my ($self, $path) = @_;
144 0 0       0 $path = $self if( 1 == scalar @_ );
145 0 0       0 return 'ARRAY' eq ref $path ? join('.', @$path) : $path
146             }
147              
148              
149             sub get {
150 22     22 0 73 my ($self, $path) = @_;
151 22         52 $path = path_to_array($path);
152 22         64 my $data = $self->data;
153 22         81 for(@$path) {
154 26 100       71 if( 'HASH' eq ref($data) ) {
155 25         50 $data = $data->{$_};
156 25         55 next;
157             }
158 1 50       5 if( 'ARRAY' eq ref($data) ) {
159 1 50       9 unless( /^\d+$/ ) {
160 0         0 die "unable to access to array by index '$_' in path: '".
161             path_to_str($path)."'";
162             }
163 1         5 $data = $data->[$_];
164 1         3 next;
165             }
166 0         0 die "unable to access by key '$_' ".
167             "when data is neither hash nor array for path: ".
168             path_to_str($path)."'";
169             }
170 22         112 return $data;
171             }
172              
173              
174             sub assign {
175 3     3 0 14 my ($self, $path, $data) = @_;
176 3         10 my $path_pre = $self->path_to_array($path);
177 3         8 my $key_pre = pop @$path_pre;
178 3 100 66     20 if( !defined $key_pre || $key_pre eq '' ) {
179 1         4 $self->data($data);
180 1         4 return;
181             }
182 2         9 my $data_pre = $self->get($path_pre);
183 2 100       7 if( 'HASH' eq ref $data_pre ) {
184 1         5 $data_pre->{$key_pre} = $data;
185 1         5 return;
186             }
187 1 50       6 if( 'ARRAY' eq ref $data_pre ) {
188 1 50       9 unless( $key_pre =~ /^\d+$/ ) {
189 0         0 die "unable to assign array item by index '$key_pre' in path: '".
190             path_to_str($path)."'";
191             }
192 1         5 $data_pre->[$key_pre] = $data;
193 1         5 return;
194             }
195 0   0     0 die "unable to assign to '".(ref($data_pre)||'nonref').
196             "' by index '$key_pre' in path: '".path_to_str($path)."'";
197             }
198              
199              
200             sub remove {
201 3     3 0 15 my ($self, $path) = @_;
202 3         10 my $path_pre = $self->path_to_array($path);
203 3         9 my $key_pre = pop @$path_pre;
204 3 100 66     18 if( !defined $key_pre || $key_pre eq '' ) {
205 1         6 $self->data(undef);
206 1         4 return;
207             }
208 2         14 my $data_pre = $self->get($path_pre);
209 2 100       10 if( 'HASH' eq ref $data_pre ) {
210 1         4 delete $data_pre->{$key_pre};
211 1         5 return;
212             }
213 1 50       6 if( 'ARRAY' eq ref $data_pre ) {
214 1 50       10 unless( $key_pre =~ /^\d+$/ ) {
215 0         0 die "unable to remove array item by index '$key_pre' in path: '".
216             path_to_str($path)."'";
217             }
218 1         5 splice @$data_pre, $key_pre, 1;
219 1         4 return;
220             }
221 0   0     0 die "unable to remove from '".(ref($data_pre)||'nonref').
222             "' by index '$key_pre' in path: '".path_to_str($path)."'";
223             }
224              
225              
226             sub copy {
227 3     3 0 18 my ($self, $path_to, $path_from) = @_;
228 3         7 my $path_preto = $self->path_to_array($path_to);
229 3         7 my $key_to = pop @$path_preto;
230 3         11 my $data = $self->get($path_from);
231 3 100 66     19 if( !defined $key_to || $key_to eq '' ) {
232 1         5 $self->data($data);
233 1         4 return;
234             }
235 2         6 my $data_to = $self->get($path_preto);
236 2 100       9 if( 'HASH' eq ref $data_to ) {
237 1         4 $data_to->{$key_to} = $data;
238 1         6 return;
239             }
240 1 50       7 if( 'ARRAY' eq ref $data_to ) {
241 1 50       9 unless( $key_to =~ /^\d+$/ ) {
242 0         0 die "unable to assign to array by index '$key_to' in path: '".
243             path_to_str($path_to)."'";
244             }
245 1         6 $data_to->[$key_to] = $data;
246 1         5 return;
247             }
248 0   0       die "unable to assign to '".(ref($data_to)||'nonref').
249             "' by index '$key_to' in path: '".path_to_str($path_to)."'";
250             }
251              
252              
253             1;
254             __END__