Diab Jerius

NAME

Hash::Wrap - create lightweight on-the-fly objects from hashes

VERSION

version 0.05

SYNOPSIS

  use Hash::Wrap;

  sub foo {
    wrap_hash { a => 1 };
  }

  $result = foo();
  print $result->a;  # prints
  print $result->b;  # throws

  # create two constructors, <cloned> and <copied> with different
  # behaviors. does not import C<wrap_hash>
  use Hash::Wrap
    { -as => 'cloned', clone => 1},
    { -as => 'copied', copy => 1 };

DESCRIPTION

This module provides constructors which create light-weight objects from existing hashes, allowing access to hash elements via methods (and thus avoiding typos). By default, attempting to access a non-existent element via a method will result in an exception, but this may be modified so that the undefined value is returned (see "-undef").

Hash elements may be added to or deleted from the object after instantiation using the standard Perl hash operations, and changes will be reflected in the object's methods. For example,

   $obj = wrap_hash( { a => 1, b => 2 );
   $obj->c; # throws exception
   $obj->{c} = 3;
   $obj->c; # returns 3
   delete $obj->{c};
   $obj->c; # throws exception

To prevent modification of the hash, consider using the lock routines in Hash::Util on the object.

The methods act as both accessors and setters, e.g.

  $obj = wrap_hash( { a => 1 } );
  print $obj->a; # 1
  $obj->a( 3 );
  print $obj->a; # 3

Only hash keys which are legal method names will be accessible via object methods.

Accessors may optionally be used as lvalues, e.g.,

  $obj->a = 3;

in Perl version 5.16 or later. See "-lvalue".

Object construction and constructor customization

By default Hash::Wrap exports a wrap_hash subroutine which, given a hashref, blesses it directly into the Hash::Wrap::Class class.

The constructor may be customized to change which class the object is instantiated from, and how it is constructed from the data. For example,

  use Hash::Wrap
    { -as => 'return_cloned_object', -clone => 1 };

will create a constructor which clones the passed hash and is imported as return_cloned_object. To import it under the original name, wrap_hash, leave out the -as option.

The following options are available to customize the constructor.

-as => subroutine name

This is optional, and imports the constructor with the given name. If not specified, it defaults to wrap_hash.

-class => class name

The object will be blessed into the specified class. If the class should be created on the fly, specify the -create option. See "Object Classes" for what is expected of the object classes. This defaults to Hash::Wrap::Class.

-create => boolean

If true, and -class is specified, a class with the given name will be created.

-copy => boolean

If true, the object will store the data in a shallow copy of the hash. By default, the object uses the hash directly.

-clone => boolean | coderef

Store the data in a deep copy of the hash. if true, "dclone" in Storable is used. If a coderef, it will be called as

   $clone = coderef->( $hash )

By default, the object uses the hash directly.

-undef => boolean

Normally an attempt to use an accessor for an non-existent key will result in an exception. The -undef option causes the accessor to return undef instead. It does not create an element in the hash for the key.

-lvalue => boolean

If true, the accessors will be lvalue routines, e.g. they can change the underlying hash value by assigning to them:

   $obj->attr = 3;

The hash entry must already exist before using the accessor in this manner, or it will throw an exception.

This is only available on Perl version 5.16 and later.

Object Classes

An object class has the following properties:

  • The class must be a subclass of Hash::Wrap::Base.

  • The class typically does not provide any methods, as they would mask a hash key of the same name.

  • The class need not have a constructor. If it does, it is passed a hashref which it should bless as the actual object. For example:

      package My::Result;
      use parent 'Hash::Wrap::Base';
    
      sub new {
        my  ( $class, $hash ) = @_;
        return bless $hash, $class;
      }

    This excludes having a hash key named new.

Hash::Wrap::Base provides an empty DESTROY method, a can method, and an AUTOLOAD method. They will mask hash keys with the same names.

LIMITATIONS

  • Lvalue accessors are available only on Perl 5.16 and later.

SEE ALSO

Here's a comparison of this module and others on CPAN.

Hash::Wrap (this module)
  • core dependencies only

  • only applies object paradigm to top level hash

  • accessors may be lvalue subroutines

  • accessing a non-existing element via an accessor throws

  • can use custom package

  • can copy/clone existing hash. clone may be customized

Object::Result

As you might expect from a DCONWAY module, this does just about everything you'd like. It has a very heavy set of dependencies.

Hash::AsObject
  • core dependencies only

  • applies object paradigm recursively

  • accessing a non-existing element via an accessor creates it

Data::AsObject
  • moderate dependency chain (no XS?)

  • applies object paradigm recursively

  • accessing a non-existing element throws

Class::Hash
  • core dependencies only

  • only applies object paradigm to top level hash

  • can add generic accessor, mutator, and element management methods

  • accessing a non-existing element via an accessor creates it (not documented, but code implies it)

  • can() doesn't work

Hash::Inflator
  • core dependencies only

  • accessing a non-existing element via an accessor returns undef

  • applies object paradigm recursively

Hash::AutoHash
  • moderate dependency chain. Requires XS, tied hashes

  • applies object paradigm recursively

  • accessing a non-existing element via an accessor creates it

Hash::Objectify
  • light dependency chain. Requires XS.

  • only applies object paradigm to top level hash

  • accessing a non-existing element throws, but if an existing element is accessed, then deleted, accessor returns undef rather than throwing

  • can use custom package

Data::OpenStruct::Deep
  • uses source filters

  • applies object paradigm recursively

Object::AutoAccessor
  • light dependency chain

  • applies object paradigm recursively

  • accessing a non-existing element via an accessor creates it

Data::Object::Autowrap
  • core dependencies only

  • no documentation

BUGS

Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Hash-Wrap or by email to bug-Hash-Wrap@rt.cpan.org.

When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature.

SOURCE

The development version is on github at https://github.com/djerius/hash-wrap and may be cloned from git://github.com/djerius/hash-wrap.git

AUTHOR

Diab Jerius <djerius@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2017 by Smithsonian Astrophysical Observatory.

This is free software, licensed under:

  The GNU General Public License, Version 3, June 2007