|
by Yanick Champoux Ottawa Perl Mongers Meeting of may 2009 |
Original talk for the FOSSLC Summercamp 2009
Content altered for Monger consumtion
|
"Oh yeah, Perl. Quaint scripting tool. But it's not like it's a real programming language. I mean *sneer* it doesn't even do OO." |
![]() |
They are right. Perl doesn't have a Object Oriented system.
It has a friggin' boatload of them!
|
![]() |
|
![]() |
Summercamp2009::Person |
|
In the file Person.pm
use MooseX::Declare;
class Person {
} package Person;
use Moose;
use namespace::clean -except => 'meta';
# ...
__PACKAGE__->meta->make_immutable();
no Moose;
1; use Person;
my $peep = Person->new; TADA!
... okay, it's not that exciting yet.
Characteristics defining the object
use MooseX::Declare;
class Person {
has 'name';
has 'age';
has 'gender';
} |
|
use Person;
my $peep = Person->new(
name => 'Vitru Vian',
age => 43,
gender => 'Male',
); Getting marginally more interesting...
In Java
void set_name ( String n ) {
name = n;
}
String get_name ( ) {
return name;
} void set_age ( int a ) {
age = a;
}
int get_age ( ) {
return age;
}
void set_gender ( Gender g ) {
gender = d;
}
Gender get_gender ( ) {
retuAAAAARGH! |
|
use MooseX::Declare;
class Person {
has name => ( is => 'rw' );
has age => ( is => 'rw' );
has gender => ( is => 'ro' );
} $peep->name( 'Vitru Vian' );
print "Person's age is ", $peep->age; use MooseX::FollowPBP;
$peep->set_name( 'Vitru Vian' );
my $name = $peep->get_name;
use MooseX::SemiAffordanceAccessor;
$peep->set_name( 'Vitru Vian' );
my $name = $peep->name; has name => (
is => 'rw',
required => 1 ,
predicate => 'has_name',
clearer => 'dename',
); has age => (
is => 'rw',
default => 42
); or
has age => (
is => 'rw',
default => sub { int rand 100 }
); use Twitter::Badge;
has twitter_id => ( is => 'rw' );
has twitter_status => (
is => 'ro',
lazy => 1,
default => sub {
my $self = shift;
return Twitter::Badge->new(
id => $self->twitter_id
)->text;
}
); my $peep = Person->new(
twitter_id => '12345'
);
print $peep->twitter_status; has twitter_account => (
isa => 'Twitter::Badge',
handles => {
twitter_status => 'text',
}
);
# equivalent to '$peep->twitter_account->text
$peep->twitter_status $peep->set_age( 'banana' );
Any
Item
Bool
Maybe[`a]
Undef
Defined
Value
Num
Int
Str
ClassName
RoleName |
Defined (cont'd)
Ref
ScalarRef
ArrayRef[`a]
HashRef[`a]
CodeRef
RegexpRef
GlobRef
FileHandle
Object
Role |
has age => (
isa => 'Int',
is => 'rw',
); use Moose::Util::TypeConstraints;
subtype 'Age'
=> as 'Int'
=> where { $_ > 18 and $_ < 100 }
=> message { 'must be between 18 and 100' }; Later on, in the class
has age => ( isa => 'Age',
is => 'rw',
);
enum Gender => qw/ Male Female /;
has 'gender' => (
is => 'rw',
isa => 'Gender'
); |
![]() |
Be strict in what you produce, and permissive in what you accept.
has 'gender' => (
coerce => 1
is => 'rw',
isa => 'Gender'
);
coerce Gender
=> from 'Str'
=> via {
return 'Male' if /^( man|lad|guy )/xi;
return 'Female' if /^( woman|lass|gal )/xi;
return $_; # not recognized
}; coerce Gender
=> from 'Person'
=> via { return $_->gender }; $peep->gender( 'man' );
print $peep->gender; $ prints 'Male'
# bob is like that peep dude
my $bob = Person->new( gender => $peep ); In the class
method asks ( Str $question ) {
$self->raise_hand;
say "Sorry, but ", $question;
} In use
$peep->ask( 'what is that $self variable?' ); # question must end with question mark
method ask ( Str $question where { /\?$/ } ) {
$self->raise_hand;
say "Sorry, but ", $question;
} Fine, let's give it a Java flavor
method ask ($this: Str $question ) {
$this->raise_hand;
say "Sorry, but ", $question;
} method ask ( $question, $tone = 'puzzled' ) {
# ...
}
# $tone is 'puzzled'
$peep->ask( 'why?' );
# $tone is 'curious'
$peep->ask( 'how?', 'curious' ) method ask ( :$question, :$tone = 'puzzled' ) {
# ...
}
$peep->ask(
tone => 'baffled',
question => 'why?'
); method ask ( $question, :$tone = 'puzzled' ) {
# ...
}
$peep->ask( 'why?', tone => 'hysteric' ); multi method compare ( Age $age ) {
return $self->age <=> $age;
}
multi method compare ( Gender $gender ) {
return $self->gender eq $gender;
}
$peep->compare( 'Male' ); In Summercamp2009::Person
method ask ( $question ) {
$self->say( $question );
} In Summercamp2009::Person::Polite
before ask ( $question ) {
$self->raise_hand;
}
after ask ( $question ) {
say "Thank you!";
} In Summercamp2009::Person::HyperExcited
override ask ( $question ) {
say uc $question;
} class Summercamp2009::Presenter
extends Summercamp2009::Person {
has presentation_title => ( is => 'rw', );
has '+age' => ( required => 1, );
method present {
say 'Hi, my name is ', $self->name;
'and I'm going to talk about ',
$self->presentation_title;
}
} |
A set of behaviors applied to an object Also knows as traits (Perl 6), interfaces (Java). Unlike in java, roles don't need to be abstract. |
|
role AdmissionFee {
requires 'price';
has 'taxes' => ( is => 'rw' );
method print_fee {
$self->set_taxes( $self->price * 0.15);
say 'amount owed: ',
$self->price + $self->taxes;
}
} class Summercamp2009::Person does AdmissionFee {
# all the other stuff ...
method price {
given ( $self->age ) {
when ( $_ < 21 ) { return 10; }
when ( $_ > 60 ) { return 15; }
default { return 25; }
}
}
} class Summercamp2009::Group does AdmissionFee {
# all the other stuff ...
method price {
my $peeps = $self->nbr_members;
my $unit_price = $peeps < 10 ? 25 : 20 ;
return $unit_price * $peeps;
}
} my $peep = Summercamp2009::Person->new( ... );
$peep->print_fee;
my $group = Summercamp2009::Group->new;
$group->add( $peep );
$group->print_fee; has xml_src => (
is => 'ro',
isa => 'XML::LibXML::Node',
);
has foo => (
is => 'ro',
lazy => 1,
default => sub {
# extract from 'xml_src'
},
); has foo => (
is => 'ro',
traits => [ 'XMLExtract' ],
);
has bar => (
is => 'ro',
traits => [ 'XMLExtract' ],
xpath => '//yadah',
xml_src => 'other_src',
); role XMLExtract {
has 'xml_src' => ( isa => 'Str', );
has xpath => ( isa => 'Str', );
has '+lazy' => ( default => 1 );
before '_process_options' => sub {
my ( $class, $name, $options ) = @_;
my $src = $options->{xml_src} ||= 'xml_src';
my $xpath = $options->{xpath} ||= $name;
$options->{default} = sub {
return $_[0]->$src->findvalue($xpath);
};
};
} http://www.iinteractive.com/moose
http://search.cpan.org/search?query=moose&mode=dist
http://mail.pm.org/mailman/listinfo/ottawa-pm