package Evo::Comp;
use Evo '-Export *', ':Hash';
export_proxy('Evo::Comp::Hash', '*');

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Evo::Comp

=head1 VERSION

version 0.0177

=head1 DESCRIPTION

=head2 Component-oriented programming

A new promising component-oriented programming concepts. Documentation will be available if someone will be willing to help write it.

=head2 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 C<fo> instead of C<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

=head1 SYNOPSYS

  package main;
  use Evo;

  {

    package My::Human;
    use Evo '-Comp *';

    has 'name' => 'unnamed';
    has 'gender', is => 'ro', required => 1;
    has age => check => sub($v) { $v >= 18 };
  }

  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;

  # 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');

=head1 Usage

=head2 creating component

Describe a component, use need to import "*" to get it worked

  package My::Comp;
  use Evo '-Comp *';
  has 'simple';

You don't need to call something like C<__PACKAGE__-E<gt>meta-E<gt>make_immutable> unlike in L<Moose>, components are fast enough by design.

=head2 new

B<important!!!>
Because Components reuse code horizontal, there's no need to pass the class string to every invocation of C<new> (or C<Evo::Comp::Out/"init">). So instead of C<My::Class-E<gt>new> use C<My::Comp::new>

  my $foo = My::Comp::new(simple => 1);
  my $foo2 = My::Comp::new();

We're protected from common mistakes, because constructor won't accept unknown attributes

  my $foo = My::Comp::new(SiMple => 1);

=head2 Storage

The big advantage of component that it's not tied with implementation. The default uses hashes L<Evo::Comp::Hash>, but you can easily switch for example to L<Evo::Comp::Out> and use any other refs

=head2 Declaring attribute 

  package My::Foo;
  use Evo '-Comp *';

  has 'simple';
  has 'short' => 'value';
  has 'foo' => default => 'value', is => 'rw', check => sub {1};

=head3 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};

=head3 Options

=head4 is

Can be 'rw' or 'ro'; Unlike Perl6 is 'rw' by default

=head4 default

Attribute will be filled with this value if isn't provided to the C<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 { {} };

=head4 lazy

Like default, but won't be filled at the first invocation, not in constructor.

=head4 required

Attributes with this options are required

=head4 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 C<(0, "CustomError")> to provide more expressive explanation

  package main;
  use Evo;

  {

    package My::Foo;
    use Evo '-Comp *';

    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

=head2 Code reuse (Roles)

!!! Below C<-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 C<Role> tag. All attributes are shared automatically. In our case method C<upper_name> and attribute C<name> are provided by role.

Let's separate C<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 C<requires>.

=head3 features

=head4 role_gen

Creates generator, very similar to L<Evo::Export/"export_gen">

=head4 role_proxy

  role_proxy 'My::Another', 'My::Another2';

Proxy attributes and methods from one role to another

=head4 role_methods

C<:Role> attribute is preffered

=head4 requires

List method that should be available in component during role installation.
If you require attribute, describe it before L</"with">. If you have circular dependencies, load all roles in the single L</"with">.

=head4 with

Load role and install all methods and attributes to the component

=head1 AUTHOR

alexbyk.com

=head1 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.

=cut
