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

NAME

Orignal - Very simple properties/attributes/fields for Perl

head1 SYNOPSIS

  package house;
  use parent  qw(Orignal);
     
  house->attributes({SCALARS        =>[qw(address style type)],
                     ORDERED_HASHES =>[qw(owners)],
                     HASHES         =>[qw(rooms)],
                     ARRAYS         =>[qw(occupants pets)]});
                     
  1;
  
  use house;
  
  my $big_house = house->new({address=>'1313 Mockingbird', 
                              type   =>'Mansion'
                              style  =>'Gothic'
                              owners =>{present=>'Lily Munster',past=>'Sam Dracula',builder=>'V. Frankenstein'}
                              rooms  =>{bathrooms=>0,bedrooms=>5,playroom=>1, dungeon=>1, lab=>1},
                              occupants=>[qw(Herman Lilly Grandpa Eddie Marilyn)]},
                              pets     =>[qw(Spot Kitty)]);
  
   my $address = $big_house->address();
   my @people  = $big_house->occupants();
   my %rooms   = $big_house->rooms();
     

DESCRIPTION

When I said simple I meant very simple. It basically just gives you a very easy way to create class level attributes that encapsulate class data, enforcing unique field names and has the added bonus of an ordered hash.

Simply think of it as the base class for other classes and you got the concept. Still unclear well if you are like me and hate writing setters and getters then this is the mod for you, as this is all it does.

The main goal of Orignal is to be light and easy to use, the code is less than 20k and has no dependencies on other modules. I created it out of frustration of liking perl 5.14 attributes but being stuck with coding in perl 5.6.

Usage

Orignal should always be used as part of a larger class or module never on its own. Simply use Orignal and then call the 'attributes' method directly on your package with an attributes hash that contains the correct attribute keys.

  package something;
  use Orignal;
  something->{SCALARS=>[qw(nothing)];
  

There are four Attribute keys SCALARS, HASHES, ORDERED_HAHSES and ARRAYS and each key if used must point to an array reference of fields. Orignal takes the fields and then creates the code references for each them that you can then use as if the code was actually in the module.

Class Methods

attributes

Use only when defining your package. Any other use will result in a die. For example

  package house;
  use parent  qw(Orignal);
     
  house->attributes({SCALARS        =>[qw(address style type)],
                     ORDERED_HASHES =>[qw(owners)],
                     HASHES         =>[qw(rooms)],
                     ARRAYS         =>[qw(occupants pets)]});
                     
  1;

Will create a package called house that you can use like this

  use house;
  
  my $big_house = house->new({address=>'1313 Mockingbird', 
                              type   =>'Mansion'
                              style  =>'Gothic'
                              owners =>{present=>'Lily Munster',past=>'Sam Dracula',builder=>'V. Frankenstein'}
                              rooms  =>{bathrooms=>0,bedrooms=>5,playroom=>1, dungeon=>1, lab=>1},
                              occupants=>[qw(Herman Lilly Grandpa Eddie Marilyn)]},
                              pets     =>[qw(Spot Kitty)]);
                              
                              

new

This is your standard new that takes a hash ref and if a Key in that hash matches a key the name of an attribute the attribute is set to that value. If a hash ref key does not match it is simply ignored. It also does not care if you do not match all the attribute names.

 my $dho_house = house->new({address=>'472 Evergreen Terrace', 
                             type   =>'Small',
                             style  =>'Clapboard',
                             owners =>{present=>'H. J. Simpson',past=>'Ned Flanders'},
                             pets   =>[qw(snowball5,santas little helper)]);
    

my_attributes

This will return the attribute hash ref used in the creation of the class.

  my $attrb = $big_house->my_attributes(); 
  
  $attrb would point to this hash  
                    {SCALARS        =>['address','style','type'],
                     ORDERED_HASHES =>['owners'],
                     HASHES         =>['rooms'],
                     ARRAYS         =>['occupants','pets']}
  
     

Attribute Methods

SCALARS

Simple Perl scalars.

Getter

A perlish getter for these that uses the field name.

  print $big_house->address();

Will return the value stored in 'address' attribute;

Setter

A simple perlish setter that uses the field name.

  $big_house->address('472 Evergreen Terrace');

Will set the value of the 'address' attribute to '472 Evergreen Terrace';

Validate

You can add an optional validator sub to a SCALAR attribute. You can validate any condition you want but you will have to follow this design pattern ATTRIBUTE_NAME_validate for the sub name, a shift to get the class, then the @_ to get the values passed into to validation sub from the setter, Finally use die if you fail validation. See the examples below;

   #address must not be undef
   sub address_validate {
       my $self = shift;
       my ($new_address) = @_;
       die("ERROR: SomeMode::House::address, cannot be empty.")
         unless ($new_address);
   }       
   #address cannot be "NO" 
   sub address_validate {
       my $self = shift;
       my ($new_address) = @_;
       die("ERROR: SomeMode::House::address, cannot be 'NO'.")
         if ($new_address eq 'NO'); 
   }
 

HASHES and ORDERED_HASHES

Simple Perl hashes of scalars. Orignal has two types unordered and ordered they share all the same methods.

Getter

A little more complex this time but still uses the field name.

  my %some_rooms = $big_house->rooms();
  my $some_rooms = $big_house->rooms();

will return the hash stored in the rooms attribute of $big_house when called in list context. In scalar context it will return the hash key pair string.

  my %bath_count = $big_house->rooms('bathrooms','dungeon');
  my $bath_count = $big_house->rooms('bathrooms','dungeon');
  

will return a hash of 2 keys and their values from the 'rooms' attribute when called in list context and in scalar context is will return the hash key pair string. If a key is not found it will return nothing.

Both the hash and ordered_hash work in the same manner.

Setter

Same as Scalar the field name but can take a hash ref as a parameter as well.

  my %owners = $big_house->rooms({kitchen =>1});
  my $owners = $big_house->rooms({kitchen =>1});
  

Will add the name values pair 'kitchen=>1' to the rooms attribute is return the new hash while in scalar context just the key pair string will be returned. When using an ordered_hash the order in which you enter the new key value pairs will be retained by Orignal except when on a new as you are passing a hash in that will not be in order.

Sending an empty hash ref to the function

  $big_house->owners({})

will empty out the rooms attribute and return undef, both the hash and ordered_hash work in the same manner.

Delete

Orignal defines a delete method as well which is in the format delete_field() that works in the same manner as a normal hash delete deleting a value from a hash.

  #  big_house->rooms = {bathrooms=>0,bedrooms=>5,playroom=>1, dungeon=>1, lab=>1}
  
  $scalar = $big_house->delete_rooms(bedrooms);                  # $scalar is 5  
  $scalar = $big_house->delete_rooms(qw(playroom bathrooms));    # $scalar is 0
  @array  = $big_house->delete_rooms(qw(dungeon playroom  lab)); # @array is (1,undef,1);
  

Both the hash and ordered_hash work in the same manner.

Exists

Orignal defines an exists method as well which is in the format exits_field() it works in the same manner as a normal hash exits, testing whether a hash key is present. It has the added bonus if you ask for more than one key it will give the total count of keys present.

  #  big_house->rooms = {bathrooms=>0,bedrooms=>5,playroom=>1, dungeon=>1, lab=>1}
  
  $scalar = $big_house->exists_rooms(bedrooms);                   # $scalar is 1  
  $scalar = $big_house->exists_rooms(funroom);                   # $scalar is 0
  $array  = $big_house->exists_rooms(qw(dungeon playroom lab));  # $scalar is 3
  

Both the hash and ordered_hash work in the same manner.

Keys

Orignal defines a keys method as well which is in the format keys_field() it works in the same manner as a normal hash keys retrieving the list of indices from a hash. However for an Ordered Hash they come out the same way they went in.

  #  big_house->rooms = {bathrooms=>0,bedrooms=>5,playroom=>1, dungeon=>1, lab=>1}
  
  $scalar = $big_house->keys_rooms();    # $scalar is  5 
  @array  = $big_house->keys_rooms();    # @array  is  (dungeon,lab,bedrooms,playroom,bathrooms) 
  
  # $big_house->owners ={present=>'Lily Munster',past=>'Sam Dracula',builder=>'V. Frankenstein'}
  # ordered hash
  
  $scalar = $big_house->keys_owners();    # $scalar is 3
  $array  = $big_house->keys_owners();    # @array  is (present,past,builder)
  

As you can see order hash preserves the order of the keys

Validate

You can add an optional validator sub to any HASH or ORDERED_HASH attribute. You can validate any condition you want but you will have to follow this design pattern ATTRIBUTE_NAME_validate for the sub name, a shift to get the class, then the @_ to get the values passed into to validation sub from the setter, Finally use die if you fail validation. See the examples below;

   #address must not be empty
   sub address_validate {
       my $self = shift;
       my ($new_address) = @_;
       die("ERROR: SomeMode::House::address, cannot be empty.") 
         unless ($new_address);
   }       
   #address has to be an must a hash ref 
   sub address_validate {
       my $self = shift;
       my ($new_address) = @_;
        ref($new_address) eq 'HASH' || die("ERROR: SomeMode::House::address, must be a 'HASH' Ref.");
      
   }
    

Values

Orignal defines a values method as well which is in the format values_field() it works in the same manner as a normal hash values returning a list of the values in a hash. However for an Ordered Hash they come out the same way they went in.

  #  big_house->rooms = {bathrooms=>0,bedrooms=>5,playroom=>1, dungeon=>1, lab=>1}
  
  $scalar = $big_house->values_rooms();    # $scalar is  5 
  @array  = $big_house->values_rooms();    # @array  is  (1,0,5,1,0) 
  
  # $big_house->owners ={present=>'Lily Munster',past=>'Sam Dracula',builder=>'V. Frankenstein'}
  # ordered hash
  
  $scalar = $big_house->values_owners();    # $scalar is 3
  $array  = $big_house->values_owners();    # @array  is ('Lily Munster','Sam Dracula','V. Frankenstein')
  

As you can see order hash preserves the order of the values.

Arrays

Simple Perl Arrays of scalars.

Getter

A little more complex this time but still uses the field name.

  my @pets = $big_house->pets();
  my $pets = $big_house->pets();

will return the array stored in the pets attribute of $big_house when called in list context. In scalar context it will return the count of indexes on the array.

  my @pets = $big_house->pets(0,2);
  my $pets = $big_house->pets(0,2);
  

will return an array of 2 the values from the 'pets' attribute when called in list context and in scalar context is will return the count. If a index is off the array it will return nothing.

Setter

Same as Scalar the field name but can also take an array ref as the parameter.

  my @pets = $big_house->pets(qw(Raven Igor)});
  my $pets = $big_house->pets(qw(Raven Igor));
  

Will add the values Raven and Igor to the end of the pets attribute and return the new array if called in list context. If called in scalar context just the length of the array will be returned. Like any array values can be duplicated.

Sending an empty array ref to the method

  $big_house->pets([]);

will empty out the pets attribute and return undef.

Pop

Orignal defines a pop method as well which is in the format pop_field() it works in the same manner as a normal array pop removing the last element from an array and returning it.

  pets     =>[qw(Spot Kitty)])
  $scalar = $big_house->pop_pets();  # $scalar is Kitty
  @array  = $big_house->pets();      # @array is ('Spot')
  
  

Push

Orignal defines a push method as well which is in the format push_field() it works in the same manner as a normal array push appending one or more elements to an array.

  pets     =>[qw(Spot)])
  $scalar = $big_house->push_pets('Kitty');  # $scalar is 2, pets= ('Spot','Kitty')
  @array  = $big_house->push_pets('Kitty');    @array is ('Spot','Kitty'), pets= ('Spot','Kitty')

Shift

Orignal defines a shift method as well which is in the format shift_field() it works in the same manner as a normal array shift removing the first element of an array, and returning it .

  pets     =>[qw(Spot Kitty)])
  $scalar = $big_house->shift_pets();  # $scalar is Spot
  @array  = $big_house->pets();       # @array is ('Kitty')
  

Unshift

Orignal defines a unshift method as well which is in the format unshift_field() it works in the same manner as a normal array unshift prepending more elements to the beginning of a list.

  pets     =>[qw(Spot)])
  $scalar = $big_house->push_pets('Kitty');  # $scalar is 2, pets= ('Kitty','Spot')
  @array  = $big_house->push_pets('Kitty');    @array is ('Kitty','Spot'), pets= ('Kitty','Spot')

Validate

You can add an optional validator sub to an ARRAY attribute. You can validate any condition you want but you will have to follow this design pattern ATTRIBUTE_NAME_validate for the sub name, a shift to get the class, then the @_ to get the values passed into to validation sub from the setter, Finally use die if you fail validation. See the examples below;

   #address must not be empty
   sub address_validate {
       my $self = shift;
       my ($new_address) = @_;
       die("ERROR: SomeMode::House::address, cannot be empty.") 
         unless ($new_address);
   }       
   #address has to be an must a array ref 
   sub address_validate {
       my $self = shift;
       my ($new_address) = @_;
       ref($new_address) eq 'ARRAY' || die("ERROR: SomeMode::House::address, must be an 'ARRAY' Ref.");
         
   }

CONTRIBUTING If you like Orignal and want to add to it or just complain. The source is available on GitHub at https://github.com/byterock/Orignal

Bugs

I haven't found any but I am sure there are? You can report them here https://rt.cpan.org/Public/Dist/Display.html?Name=Orignal or here https://github.com/byterock/Orignal/issues.

SUPPORT

Now there is a Wiki, but nothing there yet https://github.com/byterock/Orignal/wiki.

AUTHOR

John Scoles.

https://github.com/byterock/Orignal

COPYRIGHT AND LICENSE ^

Copyright 2011 By John Scoles.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.