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   1046 use Carp;
  7         13  
  7         410  
16 7     7   34 use Badger::Debug ':dump';
  7         11  
  7         40  
17 7     7   2144 use Badger::Config::Schema;
  7         16  
  7         337  
18             use Badger::Class
19 7         66 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   38 };
  7         12  
35              
36              
37             sub export {
38 20     20 1 26 my $class = shift;
39 20         23 my $target = shift;
40 20         24 $class->debug("export to $target: ", join(', ', @_)) if DEBUG;
41 20 100       55 my $params = @_ == 1 ? shift : { @_ };
42 20         42 my $schema = $class->schema($target, $params);
43 20         55 my $items = $schema->items;
44              
45 20         24 $class->debug(
46             "exporting CONFIG_SCHEMA to $target: $schema"
47             ) if DEBUG;
48              
49 20         86 $class->export_symbol(
50             $target,
51             CONFIG_SCHEMA,
52             \$schema
53             );
54              
55 20         22 $class->debug(
56             "export CONFIG_ITEMS to $target: ",
57             $class->dump_data($items)
58             ) if DEBUG;
59              
60 20         46 $class->export_symbol(
61             $target,
62             CONFIG_ITEMS,
63             \$items,
64             );
65              
66 20         107 $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 25 my $class = shift;
75 20         19 my $target = shift;
76 20 100       52 my $config = @_ == 1 ? (ref $_[0] eq ARRAY ? [@{$_[0]}] : shift) : [ @_ ];
  4 50       16  
77              
78 20         21 $class->debug("Generating schema from config: ", $class->dump_data($config))
79             if DEBUG;
80              
81 20 100       126 $config = [ split(DELIMITER, $config) ]
82             unless ref $config;
83              
84             # inherit any other items define in base classes
85 20         45 my $items = class($target)->list_vars(CONFIG_ITEMS);
86              
87 20         111 $class->SCHEMA->new(
88             class => $target,
89             schema => $config,
90             fallback => $class,
91             extend => $items,
92             );
93             }
94              
95             sub fallback {
96 40     40 1 67 my ($self, $name, $type, $data) = @_;
97 40   50     167 my $code = $self->can('configure_' . $type) || return;
98 40         123 return [ $code, $data ];
99             }
100              
101              
102             #-----------------------------------------------------------------------
103             # this method is mixed into the target module
104             #-----------------------------------------------------------------------
105              
106             sub configure {
107 37     37 1 85 my ($self, $config, $target) = @_;
108 37         75 my $class = class($self);
109 37         101 my $schema = $class->any_var(CONFIG_SCHEMA);
110              
111             # if a specific $target isn't defined then we default to updating $self
112 37 100 66     191 $schema->configure($config, $target || $self, $self)
113             || return $self->error($schema->reason->info);
114              
115 36         71 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 3 my ($class, $name, $config, $target, $var) = @_;
136 1         3 my $value = class($class)->var($var);
137              
138 1         2 $class->debug(
139             "Looking for \$$var package variable in $class to set $name: ",
140             defined $value ? $value : ''
141             ) if DEBUG;
142              
143 1 50       4 return defined $value
144             ? (VALUE => $value)
145             : (NOTHING);
146             }
147              
148             sub configure_class {
149 85     85 1 125 my ($class, $name, $config, $target, $var) = @_;
150 85         129 my $value = class($class)->any_var_in( split(':', $var) );
151              
152 85         112 $class->debug(
153             "Looking for \$$var class variable in $class to set $name: ",
154             defined $value ? $value : ''
155             ) if DEBUG;
156              
157 85 100       228 return defined $value
158             ? (VALUE => $value)
159             : (NOTHING);
160             }
161              
162             sub configure_env {
163 7     7 1 11 my ($class, $name, $config, $target, $var) = @_;
164 7         13 my $value = $ENV{ $var };
165              
166 7         8 $class->debug(
167             "Looking for $var environment variable to set $name: ",
168             defined $value ? $value : ''
169             ) if DEBUG;
170              
171 7 100       19 return defined $value
172             ? (VALUE => $value)
173             : (NOTHING);
174             }
175              
176             sub configure_method {
177 6     6 1 13 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 6   50     60 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 6         19 my $value = $code->($class);
187              
188 6         9 $class->debug(
189             "Called $method() method to set $name: ",
190             defined $value ? $value : ''
191             ) if DEBUG;
192              
193 6 100       23 return defined $value
194             ? (VALUE => $value)
195             : (NOTHING);
196             }
197              
198             sub configure_target {
199 3     3 1 9 my ($class, $name, $config, $target, $var) = @_;
200              
201 3         4 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__