package Evo;
use strict;
use warnings;
use Carp 'croak';
use Module::Load 'load';
use Evo::Util;
use feature 'say';


my $ARGS_RX = qr/[\s\(\[]*    ( [^\)\]]*?)    [\s\)\]]*/x;

sub _parse {
  my ($caller, $val) = @_;
  my $orig = $val;
  $val =~ tr/\n/ /;
  $val =~ s/^\s+|\s+$//g;

  $val =~ /^ ((\-|\:\:|\:)? $Evo::Util::RX_PKG_NOT_FIRST*) (.*)$/x;
  croak qq#Can't parse string "$orig"# unless $1;
  my ($class, $args) = (Evo::Util::resolve_package($caller, $1), $3);

  $args =~ s/^$ARGS_RX$/$1/;
  return ($class) unless $args;

  my @args = split /[,\s]+/, $args;
  ($class, @args);
}

sub import {
  shift;
  my ($target, $filename, $line) = caller;
  my @list = @_;
  unshift @list, '-Default' unless grep { $_ && $_ eq '-Default' } @list;

  @list = map { split ';', $_ } @list;
  foreach my $key (@list) {
    my ($class, @args) = _parse($target, $key);
    load($class);
    if (my $import = $class->can('import')) {
      Evo::Util::inject(package => $target, line => $line, filename => $filename, code => $import)
        ->($class, @args);
    }
    elsif (@args) {
      croak qq#Got import arguments but $class hasn't "import" method#;
    }
  }
}


our $VERSION = '0.0172';    # TRIAL VERSION

1;

# ABSTRACT: Perl Evo design pattern

__END__

=pod

=encoding UTF-8

=head1 NAME

Evo - Perl Evo design pattern

=head1 VERSION

version 0.0172

=head1 DESCRIPTION

Tiny framework for organization non-trivial code into a simple logic.
It includes benefits from functional and OO styles.

Write fast, reusable and testable code.

=head1 ATTENTION

Attention. Don't use it right now. Wait for the stable release.
Documentation is on it's way.

=head1 IMPORTING
Calls loads L<Evo::Eval> and calls it's C<import> method, emulating C<caller>.

  use Evo 'Evo::SomeComp';
  use Evo 'Evo::SomeComp(function)';
  use Evo 'Evo::SomeComp(function,otherfunc)';
  use Evo 'Evo::SomeComp function1 function2';

=head2 SHORTCUTS

  : => . (append to current)
  :: => .. (append to parent)
  - => Evo (append to Evo)

Import C<Evo::SomeComp> namespace

  use Evo '-SomeComp';

Import C<My::Ns::Foo::Rel>:

  package My::Ns::Foo;
  use Evo ':Bar';

Import C<My::Ns::Bar>:

  package My::Ns::Foo;
  use Evo '::Bar';

You can split import by C<;>

  package My::Ns::Foo;
  use Evo ':Bar bar1; :Baz baz1; Other::Foo foo1';

=head1 IMPORTS

With or without options, C<use Evo> loads L<Evo::Default>:

=head2 -Default

  use strict;
  use warnings;
  use feature ':5.20';

=head2 -Modern

Enable cool experimental features from L<Evo::Modern>

=head2 -Loaded

This marks inline or generated classes as loaded, so can be used with
C<require> or C<use>. So this code won't die

  require My::Inline;

  {
    package My::Inline;
    use Evo -Loaded;
    sub foo {'foo'}
  }

=head1 AUTHOR

alexbyk.com

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

=cut
