File Coverage

blib/lib/ProgressMonitor/AbstractConfiguration.pm
Criterion Covered Total %
statement 24 26 92.3
branch 4 6 66.6
condition 3 6 50.0
subroutine 8 8 100.0
pod n/a
total 39 46 84.7


line stmt bran cond sub pod time code
1             package ProgressMonitor::AbstractConfiguration;
2            
3 10     10   8979 use warnings;
  10         18  
  10         272  
4 10     10   51 use strict;
  10         17  
  10         431  
5            
6 10     10   59 use Scalar::Util qw(blessed);
  10         19  
  10         837  
7            
8             # declare the class
9             #
10             use classes
11 10         78 new => 'new',
12             class_methods => ['ensureCfgObject',],
13             methods => ['defaultAttributeValues', 'checkAttributeValues',],
14             clone => 'classes::clone',
15             throws => ['X::Usage',],
16 10     10   47 ;
  10         23  
17            
18             sub new
19             {
20             # get an empty object
21             #
22 23     23   92 my $self = classes::new_only(shift);
23            
24             # initilize it based on the defaults, overlaid with params to us
25             #
26 23         110 classes::init_args($self, %{$self->defaultAttributeValues}, @_);
  23         111  
27            
28             # now let the object check that all is ok
29             #
30 23         2942 $self->checkAttributeValues;
31            
32 23         248 return $self;
33             }
34            
35             sub defaultAttributeValues
36             {
37             # just return an empty hash
38             #
39 23     23   580 return {};
40             }
41            
42             sub checkAttributeValues
43             {
44             # yep, to us it looks ok! :-)
45             #
46 23     23   53 return;
47             }
48            
49             # class method to help an incoming cfg object to be of the right sort
50             # as well as cloned if necessary
51             #
52             sub ensureCfgObject
53             {
54 23     23   44 my $obj = shift;
55 23         43 my $cfgPkg = shift;
56            
57             # the cfg package name should always end in this...
58             #
59 23         50 $cfgPkg .= "Configuration";
60            
61 23 50 33     257 if (blessed($obj) && $obj->isa($cfgPkg))
    50 66        
62             {
63             # clone a passed cfg to ensure it won't change
64             #
65 0         0 return $obj->clone;
66             }
67             elsif (ref($obj) eq 'HASH' || !defined($obj))
68             {
69             # get a new cfg, possibly initialized by a hash
70             #
71 23 100       507 return $cfgPkg->new($obj ? %$obj : ());
72             }
73            
74 0           X::Usage->throw("not a hash or $cfgPkg object: $obj");
75             }
76            
77             ############################
78            
79             =head1 NAME
80            
81             ProgressMonitor::AbstractConfiguration - a base class for all configuration objects
82            
83             =head1 SYNOPSIS
84            
85             package SomeClass;
86            
87             use classes
88             ...
89            
90             sub new
91             {
92             ...
93             my $cfg = shift;
94            
95             $cfg = ProgressMonitor::AbstractConfiguration::ensureCfgObject($cfg, __PACKAGE__);
96            
97             do_something_with($cfg->get_someValue);
98             ...
99             }
100            
101             ...
102            
103             ###
104            
105             package SomeClassConfiguration;
106            
107             use classes
108             extends => 'ProgressMonitor::AbstractConfiguration',
109             attrs => ['someValue'],
110             ;
111            
112             sub defaultAttributeValues
113             {
114             my $self = shift;
115            
116             return {%{$self->SUPER::defaultAttributeValues()}, someValue => 42 };
117             }
118            
119             sub checkAttributeValues
120             {
121             my $self = shift;
122            
123             $self->SUPER::checkAttributeValues();
124            
125             X::Usage->throw("someValue is not a multiple of 42") if $self->get_value % 42;
126            
127             return;
128             }
129            
130             =head1 DESCRIPTION
131            
132             This is the base class for configuration data as used by (almost) all classes
133             in this package. The intent is that all 'real' classes have a parallel
134             configuration class where such objects holds the values used to configure the
135             real object.
136            
137             The main reason for this strategy started out as a way to reuse some of the
138             'classes' mechanisms for example with automatic getters/setters, but still not
139             expose such methods on the real object. This style also allows a user to create
140             a configuration object and pass it in to several objects - the configuration
141             will be cloned to avoid the user changing values (they may have been used for
142             calculations to set other values - changing them might invalidate such
143             calculations and make things hopelessly confused...).
144            
145             In practice, creating configuration objects directly is uncommon (?) as the
146             real objects will automatically convert an anonymous hash to an object of the
147             right kind (naming of the class is important - add 'Configuration' to the real
148             class name).
149            
150             To reuse, you typically only override the defaultAttributeValues and checkAttributeValues
151             methods.
152            
153             =head1 METHODS
154            
155             =over 2
156            
157             =item new( value1 => data1, value2 => data2, ... )
158            
159             The constructor for a configuration. Note that this method typically should be
160             treated as 'final' and not be overridden.
161            
162             Pass in a hash list with the values you want to set. Throws X::UnknownAttr if an unknown
163             attribute is passed or X::Usage if a value is deemed incorrect.
164            
165             =item defaultAttributeValues
166            
167             Takes no arguments, should return a hash reference with results from calling SUPER
168             overlaid with default values for your attributes (and possibly for the SUPER values
169             if desired).
170            
171             =item checkAttributeValues
172            
173             The implementation of this should check that the values for the attributes are
174             'correct', whatever that entails for your object.
175            
176             In case of incorrectness, throw X::Usage with a relevant message.
177            
178             =item ensureCfgObject( $hashRefOrCfgObject, $packageName)
179            
180             This is a static helper method typically called from the contructor of the 'real'
181             object and will ensure a hash ref is converted into a configuration object or a
182             configuration object is properly cloned.
183            
184             =back
185            
186             =head1 TODO
187            
188             Perhaps this class should provide a simple mechanism for storing/loading data
189             from/to persistence?
190            
191             =head1 AUTHOR
192            
193             Kenneth Olwing, C<< >>
194            
195             =head1 BUGS
196            
197             I wouldn't be surprised! If you can come up with a minimal test that shows the
198             problem I might be able to take a look. Even better, send me a patch.
199            
200             Please report any bugs or feature requests to
201             C, or through the web interface at
202             L.
203             I will be notified, and then you'll automatically be notified of progress on
204             your bug as I make changes.
205            
206             =head1 SUPPORT
207            
208             You can find general documentation for this module with the perldoc command:
209            
210             perldoc ProgressMonitor
211            
212             =head1 ACKNOWLEDGEMENTS
213            
214             Thanks to my family. I'm deeply grateful for you!
215            
216             =head1 COPYRIGHT & LICENSE
217            
218             Copyright 2006,2007 Kenneth Olwing, all rights reserved.
219            
220             This program is free software; you can redistribute it and/or modify it
221             under the same terms as Perl itself.
222            
223             =cut
224            
225             1; # End of ProgressMonitor::AbstractConfiguration