File Coverage

blib/lib/App/Getconf/View.pm
Criterion Covered Total %
statement 39 91 42.8
branch 10 52 19.2
condition 4 16 25.0
subroutine 9 14 64.2
pod 8 8 100.0
total 70 181 38.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             =head1 NAME
4              
5             App::Getconf::View - specific view of options set in App::Getconf
6              
7             =head1 SYNOPSIS
8              
9             use App::Getconf;
10              
11             App::Getconf->schema(...);
12             App::Getconf->cmdline(\@ARGV);
13              
14             my $view = App::Getconf->getopt;
15              
16             if ($view->help) {
17             print "this is --help message\n";
18             exit 0;
19             }
20              
21             print "starting the program\n" if $view->verbose;
22              
23             for my $i (0 .. $view->get("bottles.number")) {
24             printf "%d bottles of beer on the wall, %d bottles of beer.\n" .
25             "Take one down and pass it around, %d bottles of beer on the wall.\n\n",
26             99 - $i, 99 - $i, 99 - $i - 1;
27             }
28              
29             =cut
30              
31             package App::Getconf::View;
32              
33             #-----------------------------------------------------------------------------
34              
35 10     10   61 use warnings;
  10         18  
  10         285  
36 10     10   56 use strict;
  10         17  
  10         270  
37              
38 10     10   51 use Carp;
  10         22  
  10         16492  
39              
40             our @CARP_NOT = qw{App::Getconf};
41              
42             #-----------------------------------------------------------------------------
43              
44             =head1 METHODS
45              
46             Following methods are available:
47              
48             =over
49              
50             =cut
51              
52             #-----------------------------------------------------------------------------
53              
54             =item C
55              
56             Constructor. Typically you won't be calling this on your own, so don't be
57             excited.
58              
59             Following options are honoured:
60              
61             =over
62              
63             =item C
64              
65             Longest prefix for options ("." is a separator). All other prefixes that will
66             be tried in lookup have last component chopped off, compared to previous
67             prefix.
68              
69             =item C
70              
71             Hashref containing all the L objects.
72              
73             =back
74              
75             =cut
76              
77             sub new {
78 5     5 1 22 my ($class, %opts) = @_;
79              
80 5         22 my $self = bless {
81             prefixes => undef,
82             options => $opts{options},
83             }, $class;
84              
85 5         23 my @parts = split /\./, $opts{prefix};
86 5         8 my $prefix = $parts[0];
87 5         18 for my $i (1 .. $#parts) {
88 1         6 $prefix = $parts[$i] = "$prefix.$parts[$i]";
89             }
90 5         23 $self->{prefixes} = [reverse @parts];
91              
92 5         28 return $self;
93             }
94              
95             #-----------------------------------------------------------------------------
96              
97             =item C
98              
99             List of prefixes searched by this view.
100              
101             Prefixes are composed from C option passed to the constructor.
102              
103             =cut
104              
105             sub prefixes {
106 8     8 1 106 my ($self) = @_;
107              
108 8         12 return @{ $self->{prefixes} };
  8         29  
109             }
110              
111             #-----------------------------------------------------------------------------
112             # find an appropriate key
113              
114             =begin Internal
115              
116             =pod _lookup() {{{
117              
118             =item C<_lookup($option_name, $type, $storage)>
119              
120             Find an option called C<$option_name> looking under prefixes.
121              
122             If C<$type> was specified, option will need to have this type.
123              
124             If C<$storage> was specified, option will need to have this storage type.
125              
126             Returned value is full option name (C if nothing was found).
127              
128             =cut
129              
130             sub _lookup {
131 8     8   13 my ($self, $optname, $type, $storage) = @_;
132              
133 8         19 for my $p ($self->prefixes) {
134 8         18 my $o = "$p.$optname";
135              
136             # no node in schema => can't have a value
137 8 100       32 next if not $self->{options}{$o};
138             # type filter was requested, but current node's type doesn't match
139 4 50 33     13 next if defined $type && $self->{options}{$o}->type ne $type;
140             # storage filter was requested, but current node's storage doesn't match
141 4 50 33     49 next if defined $storage && $self->{options}{$o}->storage ne $storage;
142              
143 4 50       14 if (exists $self->{options}{$o}) {
144 4         12 return $o;
145             }
146             }
147              
148 4 50       18 return undef if not $self->{options}{$optname};
149 4 50 33     15 return undef if defined $type && $self->{options}{$optname}->type ne $type;
150 4 50 33     17 return undef if defined $storage && $self->{options}{$optname}->storage ne $storage;
151              
152 4         13 return $optname;
153             }
154              
155             =end Internal
156              
157             =pod }}}
158              
159             =cut
160              
161             #-----------------------------------------------------------------------------
162              
163             =item C
164              
165             Retrieve value of option C<$option_name>. Method performs lookup, consequently
166             prepending each of prefixes (see C method).
167              
168             =cut
169              
170             sub get {
171 8     8 1 20 my ($self, $optname) = @_;
172              
173 8         22 my $key = $self->_lookup($optname);
174 8 50       31 return $key ? $self->top($key) : ();
175             }
176              
177             =item C
178              
179             Retrieve value of option C<$option_name>. Method I lookup.
180             You'll get the option which you asked for.
181              
182             =cut
183              
184             sub top {
185 16     16 1 29 my ($self, $optname) = @_;
186              
187 16 50       57 if (exists $self->{options}{$optname}) {
188 16         65 return $self->{options}{$optname}->get;
189             }
190              
191 0         0 return;
192             }
193              
194             #-----------------------------------------------------------------------------
195             # top_*()
196              
197             =begin Test::Pod::Coverage
198              
199             =item C
200              
201             Retrieve value of option C<$name> (no lookup), expecting type C<$type>. Method
202             does not discriminate between different storage types, it just checks the
203             type. It's a helper for C methods.
204              
205             Method returns C<($value, App::Getconf::Node)>.
206              
207             =end Test::Pod::Coverage
208              
209             =cut
210              
211             sub top_allinwonder {
212 0     0 1 0 my ($self, $optname, $type) = @_;
213              
214 0         0 my $opt = $self->{options}{$optname};
215              
216 0 0       0 if (not $opt) {
217 0         0 croak "Option not found: $optname";
218             }
219              
220 0 0       0 if ($opt->type ne $type) {
221 0         0 croak "Type mismatch for $optname: expected $type, got @{[$opt->type]}";
  0         0  
222             }
223              
224 0         0 return ($opt->get, $opt);
225             }
226              
227             =begin Test::Pod::Coverage
228              
229             =item C
230              
231             Retrieve value of option C<$name> (no lookup), expecting type C<$type> and the
232             option storage being a simple scalar.
233              
234             Method returns value stored for the option.
235              
236             =end Test::Pod::Coverage
237              
238             =cut
239              
240             sub top_type_scalar {
241 0     0 1 0 my ($self, $optname, $type) = @_;
242              
243 0         0 my ($value, $opt) = $self->top_allinwonder($optname, $type);
244              
245 0 0       0 if ($opt->storage ne 'scalar') { # other possibilities: array, hash
246 0         0 croak "Scalar option $optname requested, got @{[$opt->storage]}";
  0         0  
247             }
248              
249             # convert bool to 1/0
250 0 0       0 return ($value ? 1 : 0) if $type eq 'bool';
    0          
251              
252             # other types don't require special treatment
253 0         0 return $value;
254             }
255              
256             =begin Test::Pod::Coverage
257              
258             =item C
259              
260             Retrieve value of option C<$name> (no lookup), expecting type C<$type> and the
261             option storage being an array.
262              
263             Method returns plain list (possibly empty) of values stored for the option.
264              
265             =end Test::Pod::Coverage
266              
267             =cut
268              
269             sub top_type_array {
270 0     0 1 0 my ($self, $optname, $type) = @_;
271              
272 0         0 my ($value, $opt) = $self->top_allinwonder($optname, $type);
273              
274 0 0       0 if ($opt->storage ne 'array') { # other possibilities: "", HASH
275 0         0 my $type = $opt->storage;
276 0         0 croak "Array option $optname requested, got $type";
277             }
278              
279 0 0       0 return @{ $value || [] };
  0         0  
280             }
281              
282             =begin Test::Pod::Coverage
283              
284             =item C
285              
286             Retrieve value of option C<$name> (no lookup), expecting type C<$type> and the
287             option storage being a hash.
288              
289             In list context method returns list of pairs (key => value) of data stored for
290             the option. In scalar context method returns hashref of the data.
291              
292             =end Test::Pod::Coverage
293              
294             =cut
295              
296             sub top_type_hash {
297 0     0 1 0 my ($self, $optname, $type) = @_;
298              
299 0         0 my ($value, $opt) = $self->top_allinwonder($optname, $type);
300              
301 0 0       0 if ($opt->storage ne 'hash') { # other possibilities: scalar, array
302 0         0 my $type = $opt->storage;
303 0         0 croak "Hash option $optname requested, got $type";
304             }
305              
306             # in list context (assignment to hash?) return all the key/value pairs
307             # in scalar context (also: dereference) return hashref
308 0 0       0 if (wantarray) {
309 0 0       0 return %{ $value || {} };
  0         0  
310             } else {
311 0         0 return $value;
312             }
313             }
314              
315             #-----------------------------------------------------------------------------
316              
317             =item C
318              
319             =item C
320              
321             =item C
322              
323             =item C
324              
325             =item C
326              
327             =item C
328              
329             Methods similar to C and C, but they also check if the result is
330             of matching type (C don't stop on non-matching options). Option
331             storage is also checked: it should be, respectively, a scalar, an array or
332             a hash.
333              
334             Methods C when no matching option was found. If the option was found
335             but it had not been set, methods return C or empty list, whichever is
336             appropriate.
337              
338             Methods C<*_array()> return a list of elements, which in scalar context turns
339             out to be a number.
340              
341             Methods C<*_hash()> return a hashref (or C) in scalar context and list
342             of key/value pairs in list context.
343              
344             =item C<< ${option_name}() >>
345              
346             For convenience, options may be retrieved by calling method named after the
347             option. For example, following two are equivalent:
348             C<< $view->get('verbose') >> and C<< $view->verbose >>.
349              
350             Note that this syntax performs lookup, just like C method.
351              
352             Names starting with C, C and C are reserved. Use explicit
353             C method call to retrieve them.
354              
355             =cut
356              
357             our $AUTOLOAD;
358             sub AUTOLOAD {
359 0     0   0 my ($self) = @_;
360              
361 0         0 my $optname = (split /::/, $AUTOLOAD)[-1];
362              
363             # unified support for top_flag(), top_bool(), top_int() and so on
364 0 0       0 if ($optname =~ /^(get|top)_(flag|bool|int|float|string)(_(array|hash))?$/) {
365 0         0 my $lookup = $1;
366 0         0 my $type = $2;
367 0   0     0 my $storage = $4 || "scalar";
368 0         0 my $name = $_[1];
369              
370 0 0       0 if ($lookup eq 'get') {
371 0         0 my $real_name = $self->_lookup($name, $type, $storage);
372 0 0       0 if (not $real_name) {
373 0   0     0 $storage ||= "scalar";
374 0         0 croak "Option not found: $name ($type, $storage)";
375             }
376 0         0 $name = $real_name;
377             }
378              
379 0 0       0 if (not $storage) {
    0          
    0          
380 0         0 return $self->top_type_scalar($name, $type);
381             } elsif ($storage eq 'array') {
382 0         0 return $self->top_type_array($name, $type);
383             } elsif ($storage eq 'hash') {
384 0         0 return $self->top_type_hash($name, $type);
385             }
386             }
387              
388 0 0       0 if ($optname =~ /^(set|get|top)_/) {
389 0         0 croak "Invalid option name for shorthand syntax: $optname";
390             }
391              
392 0         0 return $self->get($optname);
393             }
394              
395             #-----------------------------------------------------------------------------
396              
397             sub DESTROY {
398 5     5   2193 my ($self) = @_;
399              
400             # nuffin();
401             }
402              
403             #-----------------------------------------------------------------------------
404              
405             =back
406              
407             =cut
408              
409             #-----------------------------------------------------------------------------
410              
411             =head1 AUTHOR
412              
413             Stanislaw Klekot, C<< >>
414              
415             =head1 LICENSE AND COPYRIGHT
416              
417             Copyright 2012 Stanislaw Klekot.
418              
419             This program is free software; you can redistribute it and/or modify it
420             under the terms of either: the GNU General Public License as published
421             by the Free Software Foundation; or the Artistic License.
422              
423             See http://dev.perl.org/licenses/ for more information.
424              
425             =head1 SEE ALSO
426              
427             L
428              
429             =cut
430              
431             #-----------------------------------------------------------------------------
432             1;
433             # vim:ft=perl:foldmethod=marker