http://qs1969.pair.com?node_id=258164

I've been reading through the book Refactoring: Improving the Design of Existing Code by Martin Fowler and noticed that one of his refactorings, Parameter Objects, was fairly easy to implement as a generic module. Whether or not people would use this is another question. I've seen several modules that do similar things, but not quite this thing. If this is duplicated effort, please let me know.

You can download the module from my site.

POD follows.


NAME

Sub::ParamObject - Perl extension for creating parameter objects


SYNOPSIS

  use Sub::ParamObject;
  my %params = (
    type  => qr/Order|Return/,
    month => sub { my $month = shift; return grep { /$month/ } (1 .. 12) }
  );
  my $param = Sub::ParamObject->new(\%params);
  $param
    ->set_type('Return')
    ->set_month(3);
  print $param->type;  # prints 'Return'
  print $param->month; # prints 3
  # the following two method calls will fail (returning false)
  $param->set_type('Ovid');
  $param->set_month(13);


DESCRIPTION

When working with large programs, we often find that we're passing the same parameters to multiple subroutines. We also have to remember to validate those parameters in every subroutine. Rather than do this, we can create a ``parameter object'' (see Martin Fowler's book 'Refactoring') that allows us to pass those parameters as a unit. Further, this parameter object can take the data and apply standard validations, thus ensuring that you do not have to repeat the validation every time.

The benefit results in smaller parameter lists and less repetition of validation code. Further, when parameter groups are created and used, it may provide insight into behaviors that should logically be moved to other classes.

Sub::ParamObject is a generic mechanism for creating parameter objects.


CONSTRUCTOR

The constructor expects a hash reference as an argument. It will croak if one is not supplied. The keys are the parameter names and the values must either be a regular expression to validate arguments against, or an anonymous subroutine that takes returns true or false for argument validation.

  my %params = (
    type  => qr/Order|Return/,
    month => sub { my $month = shift; return grep { /$month/ } (1 .. 12) }
  );
  my $param = Sub::ParamObject->new(\%params);

The constructor croaks if the hash values are not a regex or code reference. Returns an object upon success.


DYNAMIC METHODS

Mutators

Each key in the argument hash will be transformed into a mutator by prepending the name with 'set_'. Any value supplied to the mutator must successfully validate against the value supplied to the key. Upon success, the mutator will return the object. Upon failure, it will simply return.

Because the object is returned upon success, mutators may be chained:

  $param
    ->set_foo(7)
    ->set_bar('Higher')
    ->set_baz('whuzzup?');

This is equivalent to:


  $param->set_foo(7);
  $param->set_bar('Higher');
  $param->set_baz('whuzzup?');

The only difference between the two is that with the first method, you don't need to explicitly test every mutator for success. Passing a bad argument will return false, thus ensuring that the subsequent method call in the chain fails.

Note that because the argument to the mutator must be a single value. Thus, if you need to supply something like a array or a hash, you will need to pass a reference to it and you'll have to use subroutine validation instead of regex validation. Maybe I'll change this in the future?

Accessors

Each key in the argument hash will be transformed into an accessor with the same name as the key.

  sub something {
    my $param_object = shift;
    my $foo = $param_object->foo;
    my $bar = $param_object->bar;
    ...
  }

Note that once the parameter object is passed, validation is not necessary because that happened when the values were set.

EXPORT

Nothing.


AUTHOR

Curtis ``Ovid'' Poe, <poec@yahoo.com>


BUGS

Probably.


SEE ALSO

perl.

``Refactoring'', by Martin Fowler. Published by Addison Wesley.

Cheers,
Ovid

New address of my CGI Course.
Silence is Evil (feel free to copy and distribute widely - note copyright text)