NAME
Value::Object - Base class for minimal Value Object classes
VERSION
This document describes Value::Object version 0.15
SYNOPSIS
package Value::Object::Identifier;
use parent 'Value::Object';
sub _is_valid
{
my ($self, $value) = @_;
return $value =~ m/\A[a-zA-Z_][a-zA-Z0-9_]*\z/;
}
DESCRIPTION
This class serves as a base class for classes implementing the Value Object pattern. The core principles of a Value Object class are:
- The meaning of the object is solely its value.
- The value of the object is immutable.
- The object is validated on creation.
Every Value::Object
-derived object has a minimum of a value
method that returns its value. There is no mutator methods that allow for changing the value of the object. If you need an object with a new value, create a new object. The concept is that one of these objects is more like the integer 5, than the variable $v
that contains the value. You cannot modify the value of 5, but you can make a new integer that is the value of 5 changed by some amount.
The core of this particular Value Object implementation is the validation on creation. Every subclass of Value::Object
must override either the _is_valid
or the _why_invalid
method. The _is_valid
method determines the validity of the supplied value. If the supplied value is not valid, _is_valid
returns false and the constructor throws an exception. If you prefer to have control over the message of the exception, you can override _why_invalid
which returns undef
for a valid value and information about why the value is not valid otherwise. The result is that any Value::Object
object is guaranteed to be validated by its constructor.
There is a temptation when designing a Value object to include extra functionality into the class. The Value::Object
class instead aims for the minimal function consistent with the requirements listed above. If a subclass needs more functionality it can be added to that subclass at the point of need. Valid extra functionality might be accessors for part of the value if it is made of smaller pieces. Any mutator methods would violate the fundamental design of the Value::Object
base class and are, therefore, discouraged.
INTERFACE
The class definition is currently very new. There is a potential that the interface may change in the near-term. In particular, the "Subclassing Interface" has a potential for some modification to make it more flexible.
Public Interface
The public interface only supports creation of the object and returning the value of the object.
$class->new( $value )
The new method is a constructor taking a single value. If the value is deemed valid by the _why_invalid
internal method (which defaults to checking the internal _is_valid
method if not overridden), an object is returned. Otherwise an exception is thrown.
$obj->value()
Return a copy of the value of the Value::Object
-derived object. This method should not return modifiable internal state.
Subclassing Interface
The following methods may be overridden by any subclass to provide actual validation and reporting of errors.
$self->_is_valid( $value )
This method must be overridden in any subclass (unless you override _why_invalid
instead).
It performs the validation on the supplied value and returns true
if the parameter is valid and false
otherwise.
$self->_why_invalid( $value )
By default, this method calls the _is_invalid
method and returns c<undef> on success or a list of three values on failure. The default error message is generic, but it makes creating subclasses by just overriding _is_valid
easier.
By overriding this method instead of _is_valid
you gain control over the error message reported in the exception. If the supplied value is not valid, _why_invalid
returns a list of three values:
- $why
-
This is the only required return item. It is a short message thrown as the exception describing how the value is not valid.
- $longmsg
-
This optional return item is intended to provide a more detailed error message than
$why
. With the default exception method, this message is not used. - $data
-
This optional return item is intended to provide data from the invalidation that could be used for higher level reporting. This data is not used by the default exception method.
$self->_throw_exception( $why, $longmsg, $data )
This internal method handles the actual throwing of the exception. If you need to use something more advanced than a simple die
, you can override this method. The _throw_exception
method must throw an exception by some means. It should never return.
$self->_untaint( $value )
This internal method returns an untainted copy of the value attribute. The base class version of this method performs a brute force untainting of any scalar value. Since it is only called after the value is validated, this should be safe.
A subclass can override this method to perform some other kind of untainting. If the value is not a simple scalar, the subclass must override this method if untainting is desired.
Internal Interface
These methods are documented for completeness, but are called internally and do not require any modification.
new( $value )
Constructs a Value Object. Expects a single argument that is validated according to the rules for the type of Value Object. On success, a value object is returned. Throws an exception on failure to validated.
DIAGNOSTICS
%s: Invalid parameter when creating value object.
-
The supplied parameter is not valid for the Value class.
CONFIGURATION AND ENVIRONMENT
Value::Object
requires no configuration files or environment variables.
DEPENDENCIES
INCOMPATIBILITIES
None reported.
BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to bug-value-object@rt.cpan.org
, or through the web interface at http://rt.cpan.org.
SEE ALSO
Before writing this module, I did examine other modules that implemented the Value Object pattern. Ultimately, I determined that none really matched my need.
- Class::Value
-
Implements typed Value objects. Unfortunately, the base class has a relatively large interface (44 public methods). Most of these would only apply to number-like objects. Many of the derived classes were not number-like, leading to interface surprise.
- Class::Value::*
-
There are a number of classes derived from Class::Value that implement particular Value objects. They all share the design decisions of Class::Value.
- Time::HiRes::Value
-
Implements a reasonable value object for microsecond level times. It is not a general approach to Value objects. The fact that the objects created are mutable violated one of the constraints I was aiming for.
- Scalar::Boolean
-
Another Value-like object. Limits the value of created object to Perl boolean values. It is not a general approach to Value objects. Created objects are also mutable, so they do not meet the criteria I was aiming for.
- Moose::Autobox::Value
-
This is the core funcitonality allowing autoboxing of Perl primitives, not Value objects.
ACKNOWLEDGEMENTS
Thanks to Joshua Brandt for suggesting the idea of untainting the value.
AUTHOR
G. Wade Johnson <gwadej@cpan.org>
LICENCE AND COPYRIGHT
Copyright (c) 2014, G. Wade Johnson <gwadej@cpan.org>
. All rights reserved.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.
DISCLAIMER OF WARRANTY
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.