NAME
Evo::Class
VERSION
version 0.0222
DESCRIPTION
Mixins programming
A new promising inject-code programming concepts based on mixins. Documentation will be available if someone will be willing to help write it.
Why not OO and Moose like?
The syntax differs from Moose, I fixed most frustating parts of it. It's not Moose-compatible at all. Evo::Class
is more strict by default and prevents many errors.
Every class is a role (Evo::Class::Role
) and we don't use perl's @ISA
OO inheritance. Code reuse is based on so called "mixins". This concept doesn't suffer a fragile base class problem
from traditional OO
Every class is also an interface and can be used to check the shape of other classes.
A tiny amount of code means less bugs.
These advantages make Evo::Class
perfect for both "corporate level" and "small" projects
SYNOPSYS
package main;
use Evo;
{
package My::Human;
use Evo -Class, -Loaded;
has 'name' => 'unnamed';
has 'gender', is => 'ro', required => 1;
has age => check => sub($v) { $v >= 18 };
sub greet($self) : Public { say "I'm " . $self->name }
}
my $alex = My::Human->new(gender => 'male');
# default value "unnamed"
say $alex->name;
# fluent design
$alex->name('Alex')->age(18);
say $alex->name, ': ', $alex->age;
# method
$alex->greet;
## ------------ protecting you from errors, uncomment to test
## will die, gender is required
#My::Human->new();
## will die, age must be >= 18
#My::Human->new(age => 17, gender => 'male');
#My::Human->new()->age(17, gender => 'male');
# --------- code reuse
{
package My::Developer;
use Evo -Class;
with 'My::Human'; # extends 'My::Human'; implements 'My::Human';
has lang => 'Perl';
sub show($self) : Public {
$self->greet();
say "I like ", $self->lang;
}
}
my $dev = My::Developer->new(gender => 'male');
$dev->show;
Usage
creating an object
package My::Class;
use Evo -Class;
has 'simple';
You don't need to call something like __PACKAGE__->meta->make_immutable
unlike in Moose, Evo objects are fast enough by design.
new
my $foo = My::Class->new(simple => 1);
my $foo2 = My::Class->new();
We're protected from common mistakes, because constructor won't accept unknown attributes. You may think why not My::Class::new
? You're right. The first option isn't really necessary and even constructor doesn't use it at all. But I decided to leave it that way because many developers are familiar with My::Class->new
form. There is also an "init" function for perfectionists
init
my $foo = My::Class::init({}, simple => 1);
Like new, but dosn't create an object, your should pass it as the first argument.
Storage
The big advantage of Evo object that it's not tied with implementation. The default uses hashes Evo::Class::Hash, but you can easily switch for example to Evo::Class::Out and use any other refs
Declaring attribute
package My::Foo;
use Evo '-Class *';
has 'simple';
has 'short' => 'value';
has 'foo' => default => 'value', is => 'rw', check => sub {1};
Syntax
Simple rw attribute
has 'simple';
# has 'simple', is => 'rw';
Attribute with default value: short form
has 'short' => 'value';
# has 'short', default => 'value';
Full form
has 'foo' => default => 'value', is => 'rw', check => sub {1};
Options
is
Can be 'rw' or 'ro'; Unlike Perl6 is 'rw' by default
default
Attribute will be filled with this value if isn't provided to the new
constructor You can't use references, but you can provide a coderef instead of value, in this case return value of an invocation of this function will be used.
has ref => sub(%build_args) { {} };
has foo => default => sub(%build_args) { [] };
This is a good way to init some attribute that should always exists. Arguments, passed to new
or init
will be passed to the function without object itself (because there are no object yet). If you're expecting another behaviour, check "lazy"
lazy
Like default, but will be filled at the first invocation, not in constructor, and an instance will be passed as the argument
# pay attention, an instance is passed
has foo => lazy => sub($self) { [] };
required
Attributes with this options are required
check
You can provide function that will check passed value (via constuctor and changing), and if that function doesn't return true, an exception will be thrown.
has big => check => sub { shift > 10 };
You can also return (0, "CustomError")
to provide more expressive explanation
package main;
use Evo;
{
package My::Foo;
use Evo '-Class *';
has big => check => sub($val) { $val > 10 ? 1 : (0, "not > 10"); };
};
my $foo = My::Foo->new(big => 11);
$foo->big(9); # will die
my $bar = My::Foo->new(big => 9); # will die
CODE REUSE
Method should be marked with :Public
if you want to reuse them; Attributes are all public;
Overriding
Evo protects you from method clashing. But if you want to override method or fix clashing, use "has_overriden" function or :Override
attribute
package My::Peter;
use Evo -Class;
with 'My::Human';
has_overriden name => 'peter';
sub greet : Overriden { }
This differs from traditional OO style. With compoment programming, you should reuse code via Evo::Class::Role or just organize classes with independed pieces of code like "mixing". So, try to override less
extends
Extends classes or roles
implements
Check if all required methods are implemented. Like interfaces
with
This does "extend + check implementation". Consider this example:
package main;
use Evo;
{
package My::Role::Happy;
use Evo -Class, -Loaded;
requires 'name';
sub greet($self) : Public {
say "My name is ", $self->name, " and I'm happy!";
}
package My::Class;
use Evo -Class;
has name => 'alex';
#extends 'My::Role::Happy';
#implements 'My::Role::Happy';
with 'My::Role::Happy';
}
My::Class->new()->greet();
My::Role::Happy
requires name
in derivered class. We could install shared code with extends
and then check implemantation with implements
. Or just use with
wich does both.
You may want to use extends
and implements
separately to resolve circular requirements, for example
CODE ATTRIBUTES
sub foo : Override { 'OVERRIDEN'; }
Mark name as overriden. See "Overriding methods" in Evo::Role
AUTHOR
alexbyk.com
COPYRIGHT AND LICENSE
This software is copyright (c) 2016 by alexbyk.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.