package Evo::Util;
use Evo::Base -strict;

# die outside dsl_call (if current not exists)
# die if trying to get unexisting value by key
# die if trying to override existing value in the same dsl_call
sub _current {
  my ($name, $self, $key, $val) = @_;
  my $current = $self->{$name};
  $current or Carp::confess 'Using current outside station';
  return $current unless $key;

  # get
  unless ($val) {
    Carp::confess "Using current with wrong key '$key'"
      unless exists $current->{$key};
    return $current->{$key} unless $val;
  }

  # set, die if already exists
  Carp::confess "Attemt to override existing key '$key'"
    if exists $current->{$key};
  $current->{$key} = $val;
  $self;
}

# guard_on_die {$foo->cleanup} sub { die};
# evaluates code only when second arguments causes an exception
# reraises an exception
sub _guard_on_die : prototype(&$) ($die, $cb) {
  my ($want, $res, @res) = (wantarray);

  # perltidy doesn't allow to rewrite this in 3 lines.
  local $@;
  if (!defined $want) {
    eval { $cb->() };
  }
  elsif ($want) {
    @res = eval { $cb->() };
  }
  else {
    $res = eval { $cb->() };
  }
  do { $die->(); Carp::confess $@ } if $@;

  return unless defined $want;
  $want ? @res : $res;
}

# always run first block
# reraises an exception. Like Guard::scope_guard does
sub _guard : prototype(&$) ($always, $cb) {
  my ($want, $res, @res) = (wantarray);

  # perltidy doesn't allow to rewrite this in 3 lines.
  local $@;
  if (!defined $want) {
    eval { $cb->() };
  }
  elsif ($want) {
    @res = eval { $cb->() };
  }
  else {
    $res = eval { $cb->() };
  }

  $always->();
  do { Carp::confess $@ } if $@;

  return unless defined $want;
  $want ? @res : $res;
}

sub run_wrappers {
  my ($mngr, $cb) = (shift, pop);
  my @wrappers = reverse @_;
  foreach my $w (@wrappers) {
    $cb = $w->($mngr, $cb);
  }
  return $cb;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Evo::Util

=head1 VERSION

version 0.009

=head1 DESCRIPTION

Utilites for package. For internal usage

=head1 METHODS

=head2 run_wrappers

Run wrappers in reverse order passing a last argument to each invocation

=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
