File Coverage

blib/lib/Module/MultiConf.pm
Criterion Covered Total %
statement 96 100 96.0
branch 16 20 80.0
condition 7 9 77.7
subroutine 14 15 93.3
pod 0 2 0.0
total 133 146 91.1


line stmt bran cond sub pod time code
1             #
2             # $Id: MultiConf.pm 1384 2007-09-30 13:49:29Z oliver $
3             #
4             package Module::MultiConf;
5              
6 9     9   1601202 use strict;
  9         22  
  9         360  
7 9     9   49 use warnings FATAL => 'all';
  9         15  
  9         359  
8              
9 9     9   48 use Carp;
  9         19  
  9         760  
10 9     9   6504 use Symbol;
  9         6965  
  9         577  
11 9     9   10456 use UNIVERSAL;
  9         114  
  9         118  
12 9     9   293 use Scalar::Util 'blessed';
  9         20  
  9         957  
13 9     9   14593 use Config::Any;
  9         108104  
  9         132  
14 9     9   9597 use Params::Validate ':all';
  9         110669  
  9         2471  
15 9     9   9182 use Class::Data::Inheritable;
  9         2768  
  9         111  
16              
17             our $VERSION = '1.0401';
18             $VERSION = eval $VERSION; # numify for warning-free dev releases
19              
20             sub import {
21 8     8   77 my $caller = caller(0);
22 8 50       41 return if $caller eq 'main'; # testing abuse
23              
24 8         18 my $class = shift;
25 8         18 my %args = @_;
26              
27             # fake up use base...
28 8         16 push @{*{Symbol::qualify_to_ref('ISA',$caller)}},
  8         10  
  8         38  
29             'Class::Data::Inheritable', __PACKAGE__;
30              
31             # push useful things into caller's namespace
32 8         246 foreach my $t (qw/SCALAR ARRAYREF HASHREF CODEREF GLOB GLOBREF
33             SCALARREF HANDLE BOOLEAN UNDEF OBJECT/) {
34 88         1268 *{Symbol::qualify_to_ref($t,$caller)} =
  88         189  
35 88         1273 *{Symbol::qualify_to_ref($t)}{CODE};
36             }
37              
38 8         189 $caller->mk_classdata(Validate => {});
39 8         171 $caller->mk_classdata(Force => {});
40             $caller->mk_classdata(Defaults => {
41             allow_extra => 1,
42 3     3   590 on_fail => sub { croak $_[0] },
43 8         183 no_validation => 0,
44             %args,
45             });
46             }
47              
48             *{Symbol::qualify_to_ref('parse')} = \&new;
49              
50             sub new {
51 13     13 0 8279 my $self = shift;
52 13         34 my @args = @_;
53              
54 13 100       86 return $self->_load_args() if scalar @args == 0;
55              
56 8         21 foreach (@args) {
57 8         16 my $config = $_;
58              
59             # if arg is a filename, "convert" to a hashref by loading
60 8 100       35 if (!ref $config) {
61 3         53 my $loaded = Config::Any->load_files(
62             {files => [$config], use_ext => 1});
63 3 100       12910 croak "Failed to parse contents of filename '$config'"
64             if scalar @$loaded == 0;
65              
66 2         4 (undef, $config) = each %{$loaded->[0]};
  2         12  
67             }
68              
69 7 50 66     103 croak "Config does not build a HASHREF"
70             unless ref $config eq 'HASH' or blessed $config;
71              
72 7         47 $self = $self->_load_args($config);
73             }
74              
75 3         11 return $self;
76             }
77              
78             sub _load_args {
79 12     12   24 my $self = shift;
80              
81             # factory
82 12 100       54 $self = bless {}, $self if !ref $self;
83              
84 12   100     56 my $args = shift || {};
85 12         102 my %copy = %$self; # copy for validation and munging
86 12         29 my $pkg = ref $self; # package into which we look for Validation spec
87              
88             # load in new content
89 12         38 foreach my $k (keys %$args) {
90 11 100       286 croak "Loaded config must be a HASHREF of HASHREFs"
91             if ref $args->{$k} ne 'HASH';
92 10         11 @{$copy{$k}}{keys %{$args->{$k}}} = (values %{$args->{$k}});
  10         43  
  10         28  
  10         27  
93             }
94              
95             # validate new content
96 11         49 my $validate = $pkg->Validate;
97 11   50     112 my $no_valid = $pkg->Defaults->{'no_validation'} || 0;
98              
99             {
100 11         182 local $Params::Validate::NO_VALIDATION = $no_valid;
  11         18  
101 11         31 foreach my $k (keys %$validate) {
102 12         531 %{$copy{$k}} = validate_with(
  15         47  
103             params => $copy{$k} || {},
104             spec => $validate->{$k},
105 15   100     73 %{ $pkg->Defaults },
106             );
107             }
108             }
109              
110             # squash things which are enforced
111 8         34 my $force = $pkg->Force;
112 8         59 foreach my $k (keys %$force) {
113 6         10 @{$copy{$k}}{keys %{$force->{$k}}} = (values %{$force->{$k}});
  6         25  
  6         13  
  6         15  
114             }
115              
116 8         23 foreach my $k (keys %copy) {
117 19 100       293 next if UNIVERSAL::can($self, $k);
118 13 50       129 next if UNIVERSAL::can('main', $k); # testing abuse
119              
120 13         49 *{Symbol::qualify_to_ref($k, $pkg)} = sub {
121 7     7   9342 my $self = shift;
122 7         13 my $pkg = ref $self;
123              
124             # squash things which are enforced
125 7         25 my $force = $pkg->Force;
126 7         78 foreach my $k (keys %$force) {
127 4         12 @{$self->{$k}}{keys %{$force->{$k}}} = (values %{$force->{$k}});
  4         15  
  4         7  
  4         10  
128             }
129              
130 7 50       48 return ( wantarray ? %{$self->{$k}} : $self->{$k} );
  0         0  
131 13         98 };
132             }
133              
134 8         147 %$self = %copy; # restore validated and merged params into self
135 8         69 return $self;
136             }
137              
138             sub me {
139 0     0 0   my $self = shift;
140 0           (my $me = lc (scalar caller(0))) =~ s/::/_/g;
141 0           return $self->$me;
142             }
143              
144             1;
145              
146             __END__