NAME

MooX::Value - Base class for minimal Value Object classes

VERSION

This document describes MooX::Value version 0.04

SYNOPSIS

    package MooX::Value::Identifier;

    use Moo;
    use namespace::clean;

    extends 'MooX::Value';

    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 MooX::Value-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 MooX::Value 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 MooX::Value 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 MooX::Value 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 MooX::Value 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 MooX::Value-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.

BUILDARGS

Internal function that makes the simple constructor compatible with the Moo constructor interface.

BUILD

Internal function that validates the constructor input.

DIAGNOSTICS

%s: Invalid parameter when creating value object.

The supplied parameter is not valid for the Value class.

CONFIGURATION AND ENVIRONMENT

MooX::Value requires no configuration files or environment variables.

DEPENDENCIES

Moo, namespace::clean

INCOMPATIBILITIES

None reported.

BUGS AND LIMITATIONS

No bugs have been reported.

Please report any bugs or feature requests to bug-moox-value@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.