File Coverage

lib/Badger/Class/Config.pm
Criterion Covered Total %
statement 60 60 100.0
branch 17 20 85.0
condition 4 7 57.1
subroutine 13 13 100.0
pod 9 9 100.0
total 103 109 94.5


line stmt bran cond sub pod time code
1             #========================================================================
2             #
3             # Badger::Class::Config
4             #
5             # DESCRIPTION
6             # Class mixin module for adding code onto a class for configuration.
7             #
8             # AUTHOR
9             # Andy Wardley
10             #
11             #========================================================================
12              
13             package Badger::Class::Config;
14              
15 7     7   1129 use Carp;
  7         13  
  7         451  
16 7     7   38 use Badger::Debug ':dump';
  7         19  
  7         57  
17 7     7   2479 use Badger::Config::Schema;
  7         16  
  7         398  
18             use Badger::Class
19 7         86 version => 0.01,
20             debug => 0,
21             base => 'Badger::Exporter Badger::Base',
22             import => 'class CLASS',
23             words => 'CONFIG_SCHEMA CONFIG_ITEMS',
24             constants => 'HASH ARRAY DELIMITER',
25             constant => {
26             SCHEMA => 'Badger::Config::Schema',
27             CONFIG_METHOD => 'configure',
28             VALUE => 1,
29             NOTHING => 0,
30             },
31             messages => {
32             bad_type => 'Invalid type prefix specified for %s: %s',
33             bad_method => 'Missing method for the %s %s configuration item: %s',
34 7     7   42 };
  7         12  
35              
36              
37             sub export {
38 20     20 1 34 my $class = shift;
39 20         28 my $target = shift;
40 20         32 $class->debug("export to $target: ", join(', ', @_)) if DEBUG;
41 20 100       58 my $params = @_ == 1 ? shift : { @_ };
42 20         47 my $schema = $class->schema($target, $params);
43 20         45 my $items = $schema->items;
44              
45 20         26 $class->debug(
46             "exporting CONFIG_SCHEMA to $target: $schema"
47             ) if DEBUG;
48              
49 20         84 $class->export_symbol(
50             $target,
51             CONFIG_SCHEMA,
52             \$schema
53             );
54              
55 20         28 $class->debug(
56             "export CONFIG_ITEMS to $target: ",
57             $class->dump_data($items)
58             ) if DEBUG;
59              
60 20         82 $class->export_symbol(
61             $target,
62             CONFIG_ITEMS,
63             \$items,
64             );
65              
66 20         124 $class->export_symbol(
67             $target,
68             CONFIG_METHOD,
69             $class->can(CONFIG_METHOD) # subclass might redefine method
70             );
71             }
72              
73             sub schema {
74 20     20 1 35 my $class = shift;
75 20         24 my $target = shift;
76 20 100       72 my $config = @_ == 1 ? (ref $_[0] eq ARRAY ? [@{$_[0]}] : shift) : [ @_ ];
  4 50       14  
77              
78 20         26 $class->debug("Generating schema from config: ", $class->dump_data($config))
79             if DEBUG;
80              
81 20 100       162 $config = [ split(DELIMITER, $config) ]
82             unless ref $config;
83              
84             # inherit any other items define in base classes
85 20         49 my $items = class($target)->list_vars(CONFIG_ITEMS);
86              
87 20         122 $class->SCHEMA->new(
88             class => $target,
89             schema => $config,
90             fallback => $class,
91             extend => $items,
92             );
93             }
94              
95             sub fallback {
96 41     41 1 69 my ($self, $name, $type, $data) = @_;
97 41   50     199 my $code = $self->can('configure_' . $type) || return;
98 41         178 return [ $code, $data ];
99             }
100              
101              
102             #-----------------------------------------------------------------------
103             # this method is mixed into the target module
104             #-----------------------------------------------------------------------
105              
106             sub configure {
107 38     38 1 100 my ($self, $config, $target) = @_;
108 38         104 my $class = class($self);
109 38         113 my $schema = $class->any_var(CONFIG_SCHEMA);
110              
111             # if a specific $target isn't defined then we default to updating $self
112 38 100 66     249 $schema->configure($config, $target || $self, $self)
113             || return $self->error($schema->reason->info);
114              
115 37         91 return $self;
116             }
117              
118              
119             #-----------------------------------------------------------------------
120             # These handlers implement the various fallback types for providing
121             # configuration data. The schema() method maps fallacks specified as
122             # 'pkg:FOO' and 'class:BAR', for example, to the configure_pkg() and
123             # configure_class() handlers, passing the token following the colon as
124             # an argument. They are called as code refs, but the class of the
125             # object that they're configuring is passed as the first argument, $class.
126             # So they look like class methods, but they're not exported into the
127             # object's namespace. The $target is usually the object that's being
128             # configured, e.g. when $self->configure($config) is called, but it might
129             # also be a bare hash, e.g. $target = { }; $self->configure($config, $target)
130             #-----------------------------------------------------------------------
131              
132             # TODO: move these into Badger::Config::Item or somewhere else
133              
134             sub configure_pkg {
135 1     1 1 4 my ($class, $name, $config, $target, $var) = @_;
136 1         3 my $value = class($class)->var($var);
137              
138 1         3 $class->debug(
139             "Looking for \$$var package variable in $class to set $name: ",
140             defined $value ? $value : ''
141             ) if DEBUG;
142              
143 1 50       6 return defined $value
144             ? (VALUE => $value)
145             : (NOTHING);
146             }
147              
148             sub configure_class {
149 89     89 1 166 my ($class, $name, $config, $target, $var) = @_;
150 89         175 my $value = class($class)->any_var_in( split(':', $var) );
151              
152 89         152 $class->debug(
153             "Looking for \$$var class variable in $class to set $name: ",
154             defined $value ? $value : ''
155             ) if DEBUG;
156              
157 89 100       304 return defined $value
158             ? (VALUE => $value)
159             : (NOTHING);
160             }
161              
162             sub configure_env {
163 7     7 1 12 my ($class, $name, $config, $target, $var) = @_;
164 7         12 my $value = $ENV{ $var };
165              
166 7         7 $class->debug(
167             "Looking for $var environment variable to set $name: ",
168             defined $value ? $value : ''
169             ) if DEBUG;
170              
171 7 100       24 return defined $value
172             ? (VALUE => $value)
173             : (NOTHING);
174             }
175              
176             sub configure_method {
177 7     7 1 31 my ($class, $name, $config, $target, $method) = @_;
178              
179             # see if the object has the required method - note we must call
180             # error_msg against CLASS (Badger::Class::Config) to use the 'bad_method'
181             # message defined above.
182 7   50     77 my $code = $class->can($method)
183             || return CLASS->error_msg( bad_method => class($class), $name, $method );
184              
185             # call the code and do the usual shuffle
186 7         36 my $value = $code->($class);
187              
188 7         10 $class->debug(
189             "Called $method() method to set $name: ",
190             defined $value ? $value : ''
191             ) if DEBUG;
192              
193 7 100       36 return defined $value
194             ? (VALUE => $value)
195             : (NOTHING);
196             }
197              
198             sub configure_target {
199 3     3 1 8 my ($class, $name, $config, $target, $var) = @_;
200              
201 3         6 my $value = $target->{ $var };
202              
203 3         4 $class->debug(
204             "Looking for $var in $class target $target to set $name: ",
205             defined $value ? $value : ''
206             ) if DEBUG;
207              
208 3 50       10 return defined $value
209             ? (VALUE => $value)
210             : (NOTHING);
211             }
212              
213              
214              
215             1;
216              
217             __END__