This lets you create classes and instances without having to use a new package for each class. Everything can be defined in the main package. A class that is created this way can be modified afterwards and so you can derive other classes from it. An instance is actually a copy of the class that it bases on. So you can derive an instance from another instance, too.
=head1 NAME class - classes and objects without packages =head1 DESCRIPTION class allows you to define class objects in a way that is similar to j +avascript. In this approach there is no difference between classes and objects so + I will only use the word classes. class exports extends() and the variable $this b +y default. =over4 =item Defining classes A new class can be created by using the new method my $class = new class sub{ my $field = shift; $this->field = $field; $this->arrayref = [1,2,3]; $this->hashref = {a => b, c => d}; $this->method = sub{ return $this->field }; }; A class can also be created by copying an existing class with its new( +) method my $object = $class->new; =item Accessing methods and attributes You can access attributes and/or methods by using the class object fol +lowed by an arrow and the element name. Arrays and hashes are automatically derefe +renced. print $class->name; print $class->name(LIST); # a method call with arguments For attributes you can also use hash references. print $class->{name}; The elements() method can be used to access the code of a method. Used + for attributes it is the same as using hash references. print $class->elements("name"); Note that a method that has already been defined can only be overridde +n by using the elements() method or hash references. Using $class->metho +d will always call the method instead of changing it. =back =head1 PREDEFINED METHODS new(), can(), and elements() cannot be overridden. $class->new; # creates an independent clone $class->can("method"); # returns 1 if method is defined $class->elements; # returns number of elements =head1 INHERITANCE Within the class constructor it is possible to use class::extends() wh +ich is by default exported. If a method does not exist in the current class it will be searched in the inherited classes. my $class = new class sub{ extends($class1, $class2); }; =head1 STATIC DATA Lexicals within the class constructor are static to methods that are d +efined within the constructor. That is not the case if you define a method outside t +he constructor. my $class = new class sub{ $this->field = shift; my $static = 1; $this->method = sub{ return $static }; $this->increment = sub{ $static++ }; }; =cut ################################################## package class; require Exporter; use AutoLoader; use strict; use Carp; use vars qw'$AUTOLOAD @EXPORT @ISA $this'; @ISA = qw(Exporter); @EXPORT = qw(&extends $this); $this = undef; sub new{ my $proto = shift; if(ref $proto){ return new class($proto->{CONSTRUCTOR}, @_) }else{ my $self = {}; bless $self, $proto; $self->{EXTENDS} = []; $self->{CONSTRUCTOR} = shift; croak 'class expects CODE not ' . (ref($self->{CONSTRUCTOR}) || 'string "'.$self->{CONSTRUCTOR}.'"') unless ref $self->{CONSTRUCTOR +} eq 'CODE'; my $savethis = ref($this) ? undef : $this; $this = local $$ = $self; $self->{CONSTRUCTOR}->(@_); $this = $savethis; return $self; } } ################################################## # Add inherited classes to $this->{EXTENDS} sub extends{ if(ref $$ ne 'class'){ croak "Cannot extend outside a class"; } my %done; foreach my $ext (@_){ if(ref $ext ne 'class'){ croak 'class::extends expects a class + not ' . (ref($ext) || 'string "'.$ext.'"') } next if $done{scalar($ext)}++; push @{$$->{EXTENDS}}, $ext; } } ################################################## # Return all attributes in a class sub elements : lvalue{ my $self = shift; if(!@_){ my %keys = %$self; delete $keys{CONSTRUCTOR}; delete $keys{EXTENDS}; my @keys = keys %keys; return @keys; } my $element = shift; return undef unless defined $element && exists $self->{$element}; $self->{$element}; } ################################################## # Look whether a method is defined or not sub can{ my $self = shift; my $can = shift; return undef unless defined $can; return 0 unless exists $self->{$can}; return 0 unless ref($self->{$can}) eq 'CODE'; 1; } ################################################## # Link any subroutine call to data in $this. # Seek in $this->{EXTENDS} if needed. sub AUTOLOAD : lvalue{ my $self = shift; $AUTOLOAD=~s/(.*):://; my $data; if(!exists $self->{$AUTOLOAD}){ my @tree = @{$self->{EXTENDS}}; my %done; while(@tree){ $_ = shift @tree; next if $done{scalar($_)}++; unshift @tree, @{$_->{EXTENDS}}; if(exists $_->{$AUTOLOAD}){ $data = $_->{$AUTOLOAD}; last; } } if(ref $$ eq 'class'){ $self->{$AUTOLOAD} = undef unless defined $self->{$AUTOLOA +D}; }else{ croak "Undefined attribute or method \"$AUTOLOAD\"" unless + defined $data; } }else{ $data = $self->{$AUTOLOAD}; } my $ref = ref $data; my $return; if($ref eq 'CODE'){ my $savethis = ref($this) ? undef : $this; $this = local $$ = $self unless ref $$ eq 'class'; $return = $data->(@_); $this = $savethis; return $return; # No lvalues } $ref eq 'ARRAY' ? (wantarray ? @{$self->{$AUTOLOAD}} : $self->{$AU +TOLOAD}) : $ref eq 'HASH' ? (wantarray ? %{$self->{$AUTOLOAD}} : $self->{$AUT +OLOAD}): $self->{$AUTOLOAD} } sub DESTROY{} 1;

Replies are listed 'Best First'.
Re: Creating Classes
by miyagawa (Chaplain) on Oct 04, 2001 at 20:09 UTC