The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

HO::class - class builder for hierarchical objects

SYNOPSIS

   package Foo::Bar;

   use subs 'init';
   use HO::class
      _lvalue => hey => '@',
      _method => huh => sub { print 'go' },
      _rw     => bla => '%',
      _ro     => foo => '$',
      _ro     => bar => sub { 'dub' },
      alias   => go => 'huh';

    sub init {
       my ($self,@args) = @_;
       ...
       return $self;
    }

DESCRIPTION

This is a simple class builder for array based objects. Normally it does its job during compile time. A constructor new is build. The generated new will initialize each member with an appropriate default value.

The method init is reserved for setting up objects during construction. This method gets the fresh build object, and the arguments given calling new. A little questionable optimization is that the call to init is not build into the constructor when no such method exists or the option init is not part of HO::class-\import> call.

For that reason the pragma subs is often used, before HO::class.

Five different keys could be used, to define different accessors.

_rw

The generated accessor can read and write the data.

_ro

The accessor is for read access only.

_lvalue
_method
_index
alias

Currently alias only works for methods and only when the code is given during class definition.

The second field is name of the part from class which will be created. Third field is used for datatype or code references.

Simple Accessors

For this the keys _ro and _rw exists. How the accessor is defined depends on the third argument. The datatypes are defined in HO::accessor class in the global %type hash.

@ - data behind the accessor is array reference
% - a hash reference
$ - means a scalar and defaults to undef

If the third argument is a subref then the return value of this subref is used as a default value for the attribute. To determine the the type, this code will be called once during construction.

Building a class at runtime

It is possible to build class at runtime. The easiest way to do this, is calling HO::class-\import>. At runtime the caller is commonly not the wanted class name. For that reason the global variable $HO::accessor::class is used.

   {
      local $HO::accessor::class = 'My::Class';
      HO::class->import(_ro => acc => '$', init => 'hash');
   }
   my $obj = My::Class->new(acc => 'data');

Methods Changeable For A Object

You can change methods for an object if you overwrite the method using the index.

   package H::first;
   use HO::class _method => hw => sub { 'Hallo Welt!' };

   my $o2 = H::first->new;
   is($o2->hw,'Hallo Welt!'); # ok

   $o2->[$o2->_hw] = sub { 'Hello world!' }
   is($o2->hw,'Hello world!'); # ok

How you can see, it is quite easy to do this in perl. Here during class construction you have to provide the default method, which is used when the object does not has an own method.

The method name can be appended with an additional parameter static separated by a colon. This means that the default method is stored in an additional slot in the object. So it is changeable on per class base. This is not the default, because the extra space required.

   use HO::XML
       _method => namespace:static => sub { undef }

Currently the word behind the colon could be free choosen. Only the existence of a colon in the name is checked.

Add your own types

Your are able to register your own types. The API is low level. Given a simple type like a stack.

  package Sample::Stack;

  sub new { ... }

  sub pop { ... }

  sub push { ... }

First the new type needs to be registered. This done by filling the type hasch with the name and a function, which will return an object of that type.

  $HO::accessor::type{'stack'} = sub { Sample::Stack->new };

The second step is to implement the accessors. It is implemented by an function, which returns an closure around the given index of the accessor.

  $HO::accessor::rw_accessor{'stack'} = sub {
      my ($n,$i) = @_;
      return sub { my ($obj,$idx,$val) = @_;
                   return $obj->[$i] if @_ == 1;
                 }
      }

Motivation

Development started because there was no class builder for array based objects with all the features I needed.

BUGS

Yes, there are bugs in this software. Probably it is only good for experiments and not for serious code.

ACKNOWLEDGEMENT

my employer in Leipzig
translate.google.com

AUTHOR

Sebastian Knapp, <news@young-workers.de>

COPYRIGHT AND LICENSE

Copyright (C) 2007-2017 by Sebastian Knapp

You may distribute this code under the same terms as Perl itself.