My::Object - a simple object system for Perl 5
package Local::Pony { use My::Object { name => undef }; sub BUILD_Pony { my ($self, $name) = @_; $self->name = $name; } sub eatCarrot { printf "%s eats a carrot.\n", shift->name; } } *pony = Local::Pony->NEW; my $cuddles = pony("Cuddles"); $cuddles->eatCarrot;
Unstable. Stuff might change. As I have no clue what I'm doing, the code might be evil.
A small object system using blessed hashes with autogenerated lvalue accessors. Code reuse is achieved via composition instead of inheritance: @ISA is not used. Instead, all methods are flattened into the package.
@ISA
This module takes a worse-is-better approach: There's no encapsulation, no inheritance, no type checking or other bells and whistles.
This is not Moose; it is not even Mo.
A class is just a package that invokes use on another class, in particular My::Object. This composes the callee into the caller, copying all sub declarations into the package.
use
My::Object
The use statement takes a hash of members as optional argument, mapping names to initializers. Accessors for these members will be generated automatically.
Any sub defined within the package may be used as a method, with a reference to the object passed as first argument.
Initializers are treated as constants by default. If you need to initialize a member dynamically, you may provide a sub reference as initializer. You need to prefix the member name with a -. This prefix is not part of the name proper.
-
use Scalar::Util qw(refaddr); package Local::Node { use My::Object { name => undef, -children => sub { [] }, }; } my $n1 = Local::Node::NEW->(); my $n2 = Local::Node::NEW->(); printf "0x%X != 0x%X\n", refaddr($n1->children), refaddr($n2->children);
You may use multiple use statements to compose several classes into the same package. Conflicts arise if the classes have methods with the same name. In contrast, members of the same name will map to the same slot and no conflict arises.
Conflicts can be resolved by adding the line
use subs qw(name_of_conflicting_method);
before using any of the conflicting classes and manually providing an appropriate method implementation:
package Local::Alice { use My::Object; sub transmogrify { print "I'm a tiger!\n" } } package Local::Bob { use My::Object; sub transmogrify { print "I'm a frog!\n" } } package Local::AliceAndBob { use Local::Alice; use Local::Bob; }
This will die with Subroutine transmogrify redefined, so we need to resolve the conflict:
package Local::AliceAndBob { use subs qw(transmogrify); use Local::Alice; use Local::Bob; sub transmogrify { print "Alice: "; Local::Alice::transmogrify(@_); print "Bob: "; Local::Bob::transmogrify(@_); } } Local::AliceAndBob::NEW->()->transmogrify;
Any class automatically gets a sub NEW that returns a reference to the default constructor, initializing member variables from named arguments:
NEW
package Local::Point { use My::Object { x => 0, y => 0 }; } my $p = Local::Point::NEW->(x => 0.1, y => 0.2); printf "x=%f, y=%f\n", $p->x, $p->y;
Use the symbol table to manually import the constructor into the current package:
*point = Local::Point::NEW; my $q = point(x => 0.5, y => 0.2);
It's best to do so at BEGIN time.
BEGIN
If you want to provide a custom constructor, prefix the sub's name with BUILD_ and pass the name without prefix to NEW :
BUILD_
package Local::Point { use My::Object { x => 0, y => 0 }; sub BUILD_from_coords { my ($self, $x, $y) = @_; $self->x = $x; $self->y = $y; } } BEGIN { *point = Local::Point::NEW('from_coords') }
If you name constructor and package the same (only the part after the last :: is relevant), ->NEW will do the right thing:
::
->NEW
package Local::Point { use My::Object { x => 0, y => 0 } sub BUILD_Point { ... } } BEGIN { *point = Local::Point->NEW }
Development happens at Bitbucket. If you found a bug or have a feature request, use the issue tracker over there.
Copyright (C) 2014 by Christoph Gärtner <cygx@cpan.org>
Distributed under the Boost Software License, Version 1.0
To install My::Object, copy and paste the appropriate command in to your terminal.
cpanm
cpanm My::Object
CPAN shell
perl -MCPAN -e shell install My::Object
For more information on module installation, please visit the detailed CPAN module installation guide.