File Coverage

lib/Badger/Config/Item.pm
Criterion Covered Total %
statement 78 115 67.8
branch 29 54 53.7
condition 13 47 27.6
subroutine 6 12 50.0
pod 0 10 0.0
total 126 238 52.9


line stmt bran cond sub pod time code
1             package Badger::Config::Item;
2              
3 7     7   43 use Badger::Debug ':dump';
  7         17  
  7         42  
4             use Badger::Class
5 7         135 version => 0.01,
6             debug => 0,
7             base => 'Badger::Base',
8             import => 'class CLASS',
9             utils => 'blessed',
10             accessors => 'name arity',
11             constants => 'DELIMITER ARRAY HASH',
12             constant => {
13             ARITY_ITEM => 1,
14             ARITY_LIST => 2,
15             ARITY_HASH => 3,
16             },
17             alias => {
18             init => \&init_item,
19             },
20             messages => {
21             bad_type => 'Invalid type prefix specified for %s: %s',
22             bad_method => 'Missing method for the %s %s configuration item: %s',
23             dup_item => 'Duplicate specification for scheme item: %s',
24             bad_fallback => 'Invalid fallback item specified for %s: %s',
25             no_value => 'No value specified for the %s configuration item',
26             no_key_value => 'No value specified for the <2> key of the <1> configuration item',
27 7     7   47 };
  7         12  
28              
29             our $ARITY = {
30             '$' => ARITY_ITEM,
31             '@' => ARITY_LIST,
32             '%' => ARITY_HASH,
33             };
34              
35             sub init_item {
36 60     60 0 93 my ($self, $config) = @_;
37 60         72 my ($name, @aka, $alias, $fallback, $test);
38              
39 60   33     130 my $fall = delete $config->{ fallback_provider } || $self;
40              
41 60         62 $self->debug("Generating config item: ", $self->dump_data($config))
42             if DEBUG;
43              
44             $name = $config->{ name }
45 60   50     106 || return $self->error_msg( missing => 'name' );
46              
47             # A '!' at the end of the name indicates it's mandatory.
48             # A '=value' at the end indicates a default value.
49 60 100       213 $self->{ required } = ($name =~ s/!$//) ? 1 : $config->{ required };
50 60 100       180 $self->{ default } = ($name =~ s/=(\w\S*)$//) ? $1 : $config->{ default };
51              
52             # Alternately, '=$XXX', '=@XXX' or '=%XXX' can be used to indicate that
53             # the options takes one 'XXX' argument, multiple 'XXX' arguments or key
54             # values/pairs where the values are 'XXX' arguments
55 60 50       123 if ($name =~ s/=([\$\@\%])(.+)$//) {
56 0         0 $self->debug("config item: $name [$1] [$2]") if DEBUG;
57 0         0 $config->{ arity } = $ARITY->{ $1 };
58 0         0 $config->{ args } = $2;
59             }
60              
61              
62             # name can be 'name|alias1|alias2|...'
63 60         159 ($name, @aka) = split(/\|/, $name);
64              
65             # alias can be specified as hash ref or string
66 60   50     201 $alias = $config->{ alias } || { };
67 60 50       130 $alias = [ split(DELIMITER, $alias) ]
68             unless ref $alias;
69 60 50       142 $alias = { map { $_ => $name } @$alias }
  0         0  
70             if ref $alias eq ARRAY;
71 60 50       95 return $self->error_msg( invalid => alias => $alias )
72             unless ref $alias eq HASH;
73              
74             # aliases, and more generally, fallbacks, can be specified as a list ref
75             # or string which we split
76 60         59 $self->debug("fallback: ", $self->dump_data($config->{ fallback })) if DEBUG;
77              
78 60   100     180 $fallback = $config->{ fallback } || [ ];
79 60 100       119 $fallback = [ split(DELIMITER, $fallback) ]
80             unless ref $fallback eq ARRAY;
81 60         102 push(@$fallback, @aka);
82              
83 60         55 $self->debug("fallbacks: ", $self->dump_data($fallback)) if DEBUG;
84              
85 60         97 foreach my $item (@$fallback) {
86 63 100       150 unless ($item =~ /:/) {
87 22         60 $alias->{ $item } = $name;
88 22         33 next;
89             }
90 41         126 my ($type, $data) = split(/:/, $item, 2);
91 41   50     144 $item = $fall->fallback($name, $type, $data)
92             || return $self->error_msg( bad_type => $name, $type );
93             }
94              
95             # add any aliases specified as part of the name and bind them
96             # back into the field info hash
97 60         78 $self->{ fallback } = $fallback;
98              
99             # this is getting way too large... but I just want to get things working
100             # before I start paring things down
101 60         96 $self->{ name } = $name;
102 60         115 $self->{ alias } = $alias;
103 60   33     196 $self->{ message } = $config->{ message } || $config->{ error };
104 60         81 $self->{ action } = $config->{ action };
105 60         165 $self->{ method } = $config->{ method };
106 60         78 $self->{ about } = $config->{ about };
107 60         70 $self->{ args } = $config->{ args };
108 60   50     184 $self->{ arity } = $config->{ arity } || 0;
109              
110 60         62 $self->debug(
111             "Configured configuration item: ", $self->dump
112             ) if DEBUG;
113              
114 60         139 return $self;
115             }
116              
117              
118             sub fallback {
119 0     0 0 0 shift->not_implemented;
120             }
121              
122             sub names {
123 72     72 0 85 my $self = shift;
124 72         91 my @names = ($self->{ name }, keys %{ $self->{ alias } });
  72         194  
125             return wantarray
126             ? @names
127 72 50       195 : \@names;
128             }
129              
130              
131             sub configure {
132 275     275 0 444 my ($self, $config, $target, $class) = @_;
133 275         317 my ($name, $alias, $code, @args, $ok, $value);
134              
135 275   33     431 $class ||= $target;
136              
137 275         268 $self->debug("configure(", CLASS->dump_data_inline($config), ')') if DEBUG;
138 275         261 $self->debug("item is ", $self->dump_data($self)) if DEBUG;
139             # $self->debug("items: ", CLASS->dump_data($items)) if DEBUG;
140              
141 275         529 $name = $self->{ name };
142              
143             # TODO: abstract out action calls.
144              
145 275 50       386 FALLBACK: foreach $alias ($name, @{ $self->{ fallback } || [ ] }) {
  275         598  
146 508 50       770 next unless defined $alias;
147              
148 508 100       906 if (ref $alias eq ARRAY) {
    100          
149 107         221 ($code, @args) = @$alias;
150             #$self->todo('calling code');
151 107         246 ($ok, $value) = $code->($class, $name, $config, $target, @args);
152 107 100       217 if ($ok) {
153 95         186 return $self->set($target, $name, $value, $class);
154             }
155             }
156             elsif (defined $config->{ $alias }) {
157 74         81 $self->debug("Found value for $name ($alias): $config->{ $alias }\n") if DEBUG;
158 74         162 return $self->set($target, $name, $config->{ $alias }, $class);
159             }
160             else {
161 327         448 $self->debug("Nothing found for $alias to set $name\n") if DEBUG;
162             }
163             }
164              
165 106 100       209 if (defined $self->{ default }) {
166 13         14 $self->debug("setting to default value: $self->{ default }\n") if DEBUG;
167 13         30 return $self->set($target, $name, $self->{ default }, $class);
168             }
169              
170 93 100       146 if ($self->{ required }) {
171 1         3 $self->debug("$name is required, throwing error\n") if DEBUG;
172 1   50     11 return $self->error_msg( $self->{ message } || missing => $name );
173             }
174              
175 92         177 return $self;
176             }
177              
178              
179             sub set {
180 182     182 0 318 my ($self, $target, $name, $value, $object) = @_;
181 182         196 my $method;
182              
183 182   33     268 $object ||= $target;
184              
185 182         182 $self->debug("set($target, $name, $value)") if DEBUG;
186              
187 182 50       428 if ($self->{ arity } == ARITY_LIST) {
    50          
188 0   0     0 my $list = $target->{ $name } ||= [ ];
189 0         0 push(@$list, $value);
190             }
191             elsif ($self->{ arity } == ARITY_HASH) {
192 0 0       0 return $self->error_msg( invalid => 'key/value pair' => $value)
193             unless ref $value eq ARRAY;
194              
195 0   0     0 my $hash = $target->{ $name } ||= { };
196 0         0 $hash->{ $value->[0] } = $value->[1];
197             }
198             else {
199 182         339 $target->{ $name } = $value;
200             }
201              
202 182 50       339 $self->{ action }->($self, $name, $value) if $self->{ action };
203              
204 182 50 66     783 if (blessed($object) && ($method = $self->{ method })) {
205 0         0 $self->debug("calling method $method on object $object\n") if DEBUG;
206 0         0 $object->$method($name, $value);
207             }
208              
209 182         584 return $self;
210             }
211              
212              
213             # this is being replaced by Badger::Config::Reader::Args
214              
215             sub args {
216 0     0 0   my $self = shift;
217 0           my $args = shift;
218 0           my $value;
219              
220 0 0         if ($self->{ args }) {
221 0           $self->debug("looking for $self->{ name } arg in ", $self->dump_data($args)) if DEBUG;
222              
223             return $self->error_msg( no_value => $self->{ name } )
224 0 0 0       unless @$args && defined $args->[0] && $args->[0] !~ /^-/;
      0        
225              
226 0           $value = shift @$args;
227              
228 0 0         if ($self->{ arity } == ARITY_HASH) {
229 0           my $key = $value;
230 0 0 0       return $self->error_msg( no_key_value => $self->{ name }, $key )
      0        
231             unless @$args && defined $args->[0] && $args->[0] !~ /^-/;
232 0           $value = shift @$args;
233 0           $value = [ $key, $value ];
234             }
235             }
236             else {
237 0           $value = 1;
238             }
239             # this is all the wrong way around - quick hack
240 0           return $self->configure({ $self->{ name } => $value }, @_);
241             }
242              
243             # temporary method providing access to args value
244             sub has_args {
245 0     0 0   shift->{ args };
246             }
247              
248             sub hash_arity {
249 0     0 0   shift->{ arity } == ARITY_HASH;
250             }
251              
252             sub list_arity {
253 0     0 0   shift->{ arity } == ARITY_LIST;
254             }
255              
256             sub summary {
257 0     0 0   my ($self, $reporter) = @_;
258 0           my $name = $self->{ name };
259 0   0       my $args = $self->{ args } || '';
260 0   0       my $about = $self->{ about } || '';
261 0 0         if (length $args) {
262 0           $args =~ s/\s+/>
263 0           $args = " <$args>";
264             }
265 0 0         return $reporter
266             ? $reporter->option( $name.$args, $about )
267             : sprintf('--%-20s %s', $name.$args, $about);
268             }
269              
270              
271             1;