NAME
Evo::Comp
VERSION
version 0.0173
Component-oriented programming
A new promising component-oriented programming concepts. Documentation will be available if someone will be willing to help write it.
Why not OO and Moose like?
The most problems with Moose like modules is with initialization. Let's take a look:
package My::Moose;
use Moose;
has foo => is =>'rw';
package main;
my $obj = My::Moose->new(fo => 3);
print $obj->foo;
As you can see, we passed fo
instead of foo
, and Moose silently ignored it. You should write a huge amout of extra tests to pervent such errors. So I decided to write all the stuff and name it component oriented programming.
More explanation will be written later
Usage
package My::Comp;
use Evo '-Comp *';
has 'simple';
has read_only => is => 'ro';
package main;
use Evo;
# if My::Comp in separate file
# use My::Comp;
# !!!pay attantion, not My::Foo->new
my $foo = My::Foo::new(important => '22', read_only => 'hi');
$foo->simple('hello')->important(44);
say $foo->simple;
We're protected from common mistakes
# "SiMple" is unknown
my $foo = My::Foo::new(SiMple => 1, important => 1);
# "important" is required
my $foo = My::Foo::new();
Storage
The big advantage of component that it's not tied with implementation. The default uses hashes Evo::Comp::Hash, but you can easily switch for example to Evo::Comp::Out and use any other refs
Declaring attribute
package My::Foo;
use Evo '-Comp *';
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 { {} };
has ref => sub { {} };
lazy
Like default, but won't be filled at the first invocation, not in constructor.
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 '-Comp *';
use Evo -Modern;
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 (Roles)
!!! Below -Loaded
is only needed to copy-paste examples into one file and run it. In the real life code, where every role has separate file, it's unneccessary.
OO is considered an anti-pattern because it's hard to change and reuse such code, and every refactoring makes OO applications low-tested or extra-tested. Component oriented programming doesn't have such weakness. It uses roles (like Moose's roles), or so called "mixins".
Because of that, Components are faster, simpler, and more reusable Also Roles can protect you from method and attributes clashing, because all methods and attributes will be installed into one file
I'll write an article about this late (maybe)
Here is a breaf overview
package main;
use Evo;
{
package Person::Human;
use Evo '-Comp::Role *; -Loaded';
has 'name';
sub upper_name : Role { uc shift->name }
package Person;
use Evo '-Comp *';
with ':Human'; # same as "Person::Human";
sub intro { say "My name is ", shift->upper_name }
};
my $alex = Person::new(name => 'alex');
$alex->intro;
As you can see, role shares attributes and methods. To share method, add Role
tag. All attributes are shared automatically. In our case method upper_name
and attribute name
are provided by role.
Let's separate Person::Human
into 2 different roles;
package main;
use Evo;
{
package Person::Human;
use Evo '-Comp::Role *; -Loaded';
has 'name';
package Person::LoudHuman;
use Evo '-Comp::Role *; -Loaded';
requires 'name';
sub upper_name : Role { uc shift->name }
package Person;
use Evo '-Comp *';
with ':LoudHuman', ':Human';
sub intro { say "My name is ", shift->upper_name }
};
my $alex = Person::new(name => 'alex');
$alex->intro;
Pay attention to the requires
.
features
role_gen
Creates generator, very similar to "export_gen" in Evo::Export
role_proxy
role_proxy 'My::Another', 'My::Another2';
Proxy attributes and methods from one role to another
role_methods
:Role
attribute is preffered
requires
List method that should be available in component during role installation. If you require attribute, describe it before "with". If you have circular dependencies, load all roles in the single "with".
with
Load role and install all methods and attributes to the component
AUTHOR
alexbyk.com
COPYRIGHT AND LICENSE
This software is copyright (c) 2015 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.