Iterator-Flex

 view release on metacpan or  search on metacpan

META.json  view on Meta::CPAN

            "Test::Spelling" : "0.12",
            "Test::Version" : "1"
         }
      },
      "runtime" : {
         "requires" : {
            "Class::Method::Modifiers" : "0",
            "List::Util" : "1.33",
            "Module::Runtime" : "0",
            "Package::Variant" : "0",
            "Ref::Util" : "0",
            "Role::Tiny" : "2.002004",
            "custom::failures" : "0",
            "experimental" : "0",
            "namespace::clean" : "0",
            "perl" : "v5.28.0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"

META.yml  view on Meta::CPAN

    file: lib/Iterator/Flex/Stack.pm
    version: '0.19'
  Iterator::Flex::Utils:
    file: lib/Iterator/Flex/Utils.pm
    version: '0.19'
requires:
  Class::Method::Modifiers: '0'
  List::Util: '1.33'
  Module::Runtime: '0'
  Package::Variant: '0'
  Ref::Util: '0'
  Role::Tiny: '2.002004'
  custom::failures: '0'
  experimental: '0'
  namespace::clean: '0'
  perl: v5.28.0
resources:
  bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Iterator-Flex
  repository: https://gitlab.com/djerius/iterator-flex.git
version: '0.19'
x_generated_by_perl: v5.40.0

dist.ini  view on Meta::CPAN


; --- Project-specific directives

;[AutoPrereqs]

[Prereqs]
Class::Method::Modifiers = 0
List::Util               = 1.33
Module::Runtime          = 0
Package::Variant         = 0
Ref::Util                = 0
Role::Tiny               = 2.002004
custom::failures         = 0
experimental             = 0
namespace::clean         = 0
perl                     = 5.28.0

[Prereqs / ConfigureRequires ]
Module::Build::Tiny      = 0

[Prereqs / TestRequires]

lib/Iterator/Flex/Array.pm  view on Meta::CPAN

package Iterator::Flex::Array;

# ABSTRACT: Array Iterator Class

use strict;
use warnings;

our $VERSION = '0.19';

use Iterator::Flex::Utils ':IterAttrs';
use Ref::Util;
use namespace::clean;
use experimental 'signatures';

use parent 'Iterator::Flex::Base';






lib/Iterator/Flex/Array.pm  view on Meta::CPAN









sub new ( $class, $array, $pars = {} ) {
    $class->_throw( parameter => "argument must be an ARRAY reference" )
      unless Ref::Util::is_arrayref( $array );

    $class->SUPER::new( { array => $array }, $pars );
}


sub construct ( $class, $state ) {

    $class->_throw( parameter => "'state' parameter must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    my ( $arr, $prev, $current, $next )
      = @{$state}{qw[ array prev current next ]};

    $class->_throw( parameter => "state 'array' parameter must be a HASH reference" )
      unless Ref::Util::is_arrayref( $arr );

    my $len = @$arr;

    $next = 0 unless defined $next;

    $class->_throw( parameter => "illegal value for state 'prev' argument" )
      if defined $prev && ( $prev < 0 || $prev >= $len );

    $class->_throw( parameter => "illegal value for state 'current' argument" )
      if defined $current && ( $current < 0 || $current >= $len );

lib/Iterator/Flex/ArrayLike.pm  view on Meta::CPAN

package Iterator::Flex::ArrayLike;

# ABSTRACT: ArrayLike Iterator Class

use strict;
use warnings;
use experimental 'signatures';

our $VERSION = '0.19';

use Ref::Util;
use Iterator::Flex::Utils ':IterAttrs';
use namespace::clean;

use parent 'Iterator::Flex::Base';
use Role::Tiny::With ();
Role::Tiny::With::with 'Iterator::Flex::Role::Utils';




lib/Iterator/Flex/ArrayLike.pm  view on Meta::CPAN








sub new ( $class, $obj, $pars = {} ) {

    $class->_croak( parameter => "argument must be a blessed reference" )
      unless Ref::Util::is_blessed_ref( $obj );

    $class->SUPER::new( { object => $obj }, $pars );
}

sub construct ( $class, $state ) {

    $class->_throw( parameter => "state must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    my ( $obj, $prev, $current, $next, $length, $at )
      = @{$state}{qw[ object prev current next length at ]};

    $class->_throw( parameter => "state 'object' argument must be a blessed reference" )
      unless Ref::Util::is_blessed_ref( $obj );

    $length = $class->_resolve_meth( $obj, $length, 'length', 'len' );

    $at = $class->_resolve_meth( $obj, $at, 'at', 'getitem' );

    my $len = $obj->$length;

    $next = 0 unless defined $next;

    $class->_throw( parameter => "illegal value for state 'prev' argument" )

lib/Iterator/Flex/Base.pm  view on Meta::CPAN


use 5.10.0;

use strict;
use warnings;

use experimental qw( signatures postderef );

our $VERSION = '0.19';

use Ref::Util;
use List::Util;
use Role::Tiny       ();
use Role::Tiny::With ();
use Module::Runtime  ();

Role::Tiny::With::with 'Iterator::Flex::Role', 'Iterator::Flex::Role::Utils';

use Iterator::Flex::Utils qw (
  :default
  :ExhaustionActions

lib/Iterator/Flex/Base.pm  view on Meta::CPAN

    my %ipar = $in_ipar->%*;
    my %gpar = $in_gpar->%*;

    $class->_validate_interface_pars( \%ipar );
    $class->_validate_signal_pars( \%gpar );

    my @roles = ( delete( $ipar{ +_ROLES } ) // [] )->@*;

    $gpar{ +ERROR } //= [ ( +THROW ) ];
    $gpar{ +ERROR } = [ $gpar{ +ERROR } ]
      unless Ref::Util::is_arrayref( $gpar{ +ERROR } );

    if ( $gpar{ +ERROR }[0] eq +THROW ) {
        push @roles, 'Error::Throw';
    }
    else {
        $class->_throw( "unknown specification of iterator error signaling behavior:", $gpar{ +ERROR }[0] );
    }

    my $exhaustion_action = $gpar{ +EXHAUSTION } // [ ( +RETURN ) => undef ];

    my @exhaustion_action
      = Ref::Util::is_arrayref( $exhaustion_action )
      ? ( $exhaustion_action->@* )
      : ( $exhaustion_action );

    $gpar{ +EXHAUSTION } = \@exhaustion_action;

    if ( $exhaustion_action[0] eq +RETURN ) {
        push @roles, 'Exhaustion::Return';
    }
    elsif ( $exhaustion_action[0] eq +THROW ) {

lib/Iterator/Flex/Base.pm  view on Meta::CPAN

    }
    else {
        $class->_throw( parameter => "unknown exhaustion action: $exhaustion_action[0]" );
    }

    if ( defined( my $par = $ipar{ +METHODS } ) ) {

        require Iterator::Flex::Method;

        $class->_throw( parameter => "value for methods parameter must be a hash reference" )
          unless Ref::Util::is_hashref( $par );

        for my $name ( keys $par->%* ) {

            my $code = $par->{$name};

            $class->_throw( parameter => "value for 'methods' parameter key '$name' must be a code reference" )
              unless Ref::Util::is_coderef( $code );

            # create role for the method
            my $role = eval { Iterator::Flex::Method::Maker( $name, name => $name ) };

            if ( $@ ne '' ) {
                my $error = $@;
                die $error
                  unless Ref::Util::is_blessed_ref( $error )
                  && $error->isa( 'Iterator::Flex::Failure::RoleExists' );
                $role = $error->payload;
            }

            push @roles, '+' . $role;    # need '+', as these are fully qualified role module names.
        }
    }

    @roles = map { $class->_load_role( $_ ) } @roles;
    $class = Role::Tiny->create_class_with_roles( $class, @roles );

lib/Iterator/Flex/Base.pm  view on Meta::CPAN

}

sub _validate_interface_pars ( $class, $pars ) {

    my @bad = check_invalid_interface_parameters( [ keys $pars->%* ] );

    $class->_throw( parameter => "unknown interface parameters: @{[ join ', ', @bad ]}" )
      if @bad;

    $class->_throw( parameter => "@{[ +_ROLES ]}  must be an arrayref" )
      if defined $pars->{ +_ROLES } && !Ref::Util::is_arrayref( $pars->{ +_ROLES } );

    if ( defined( my $par = $pars->{ +_DEPENDS } ) ) {
        $pars->{ +_DEPENDS } = $par = [$par] unless Ref::Util::is_arrayref( $par );
        $class->_throw( parameter => "dependency #$_ is not an iterator object" )
          unless List::Util::all { $class->_is_iterator( $_ ) } $par->@*;
    }

    return;
}

sub _validate_signal_pars ( $class, $pars ) {

    my @bad = check_invalid_signal_parameters( [ keys $pars->%* ] );

lib/Iterator/Flex/Base.pm  view on Meta::CPAN







# TODO: this is too restrictive. It should allow simple coderefs, or
# things with a next or __next__.

sub _is_iterator ( $, $obj ) {
    return Ref::Util::is_blessed_ref( $obj ) && $obj->isa( __PACKAGE__ );
}









lib/Iterator/Flex/Cache.pm  view on Meta::CPAN

use strict;
use warnings;
use experimental qw( signatures postderef );

our $VERSION = '0.19';

use parent 'Iterator::Flex::Base';
use Iterator::Flex::Utils qw( STATE :IterAttrs :IterStates throw_failure );
use Iterator::Flex::Factory;
use Scalar::Util;
use Ref::Util;

use namespace::clean;








lib/Iterator/Flex/Cache.pm  view on Meta::CPAN








sub new ( $class, $iterable, $pars = {} ) {

    throw_failure( parameter => '"pars" argument must be a hash' )
      unless Ref::Util::is_hashref( $pars );

    my %pars = $pars->%*;

    my $capacity = delete $pars{capacity} // 2;

    $class->SUPER::new( {
            capacity => $capacity,
            depends  => [ Iterator::Flex::Factory->to_iterator( $iterable ) ],
        },
        \%pars

lib/Iterator/Flex/Cache.pm  view on Meta::CPAN








sub construct ( $class, $state ) {

    $class->_throw( parameter => "state must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    my ( $src, $capacity, $idx, $cache ) = @{$state}{qw[ depends capacity idx cache ]};
    $src = $src->[0];
    $idx   //= -1;
    $cache //= [];

    my $self;
    my $iterator_state;

    return {

lib/Iterator/Flex/Cat.pm  view on Meta::CPAN










sub new ( $class, @args ) {
    my $pars = Ref::Util::is_hashref( $args[-1] ) ? pop @args : {};

    @args
      or $class->_throw( parameter => 'not enough parameters' );

    $class->SUPER::new( {
            depends                => \@args,
            current_iterator_index => undef,
        },
        $pars
    );
}

sub construct ( $class, $state ) {
    $class->_throw( parameter => "state must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    $state->{value} //= [];

    my ( \@depends, $current_iterator_index, $prev, $current, $next, $thaw )
      = @{$state}{ 'depends', 'current_iterator_index', 'prev', 'current', 'next', 'thaw' };

    # transform into iterators if required.
    my @iterators
      = map { Iterator::Flex::Factory->to_iterator( $_, { ( +EXHAUSTION ) => +RETURN } ) } @depends;
    my $value;

lib/Iterator/Flex/Common.pm  view on Meta::CPAN


use Exporter 'import';

our @EXPORT_OK = qw[
  iterator iter iarray icycle icache
  icat igrep imap iproduct iseq istack ifreeze thaw
];

our %EXPORT_TAGS = ( all => \@EXPORT_OK );

use Ref::Util             qw[ is_arrayref is_hashref is_ref is_globref ];
use Module::Runtime       qw[ require_module ];
use Iterator::Flex::Utils qw[ throw_failure ];
use Iterator::Flex::Factory;







lib/Iterator/Flex/Cycle.pm  view on Meta::CPAN


# ABSTRACT: Array Cycle Iterator Class

use strict;
use warnings;
use experimental 'signatures';

our $VERSION = '0.19';

use Iterator::Flex::Utils ':IterAttrs';
use Ref::Util;
use namespace::clean;

use parent 'Iterator::Flex::Base';







lib/Iterator/Flex/Cycle.pm  view on Meta::CPAN








sub new ( $class, $array, $ ) {

    $class->_throw( parameter => "argument must be an ARRAY reference" )
      unless Ref::Util::is_arrayref( $array );

    $class->SUPER::new( { array => $array }, {} );
}

sub construct ( $class, $state ) {

    $class->_throw( parameter => "state must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    my ( $arr, $prev, $current, $next )
      = @{$state}{qw[ array prev current next ]};

    my $len = @$arr;

    $next = 0 unless defined $next;

    $class->_throw( parameter => "illegal value for 'prev'" )
      if defined $prev && ( $prev < 0 || $prev >= $len );

lib/Iterator/Flex/Factory.pm  view on Meta::CPAN

# ABSTRACT: Create on-the-fly Iterator::Flex classes/objects

use 5.25.0;
use strict;
use warnings;

use experimental qw( signatures declared_refs refaliasing);

our $VERSION = '0.19';

use Ref::Util        ();
use Role::Tiny       ();
use Role::Tiny::With ();
use Module::Runtime;


use Iterator::Flex::Base;
use Iterator::Flex::Utils qw[
  :ExhaustionActions
  :default
  :RegistryKeys

lib/Iterator/Flex/Factory.pm  view on Meta::CPAN








sub construct ( $CLASS, $in_ipar = {}, $in_gpar = {} ) {

    $CLASS->_throw( parameter => "'iterator parameters' parameter must be a hashref" )
      unless Ref::Util::is_hashref( $in_ipar );

    $CLASS->_throw( parameter => "'general parameters' parameter must be a hashref" )
      unless Ref::Util::is_hashref( $in_gpar );

    my %ipar = $in_ipar->%*;
    my %ipar_k;
    @ipar_k{ keys %ipar } = ();
    my %gpar = $in_gpar->%*;
    my %gpar_k;
    @gpar_k{ keys %gpar } = ();

    my $par;
    my @roles;

    my $class = $ipar{ +CLASS } // 'Iterator::Flex::Base';
    delete $ipar_k{ +CLASS };

    $CLASS->_throw( parameter => "'class' parameter must be a string" )
      if Ref::Util::is_ref( $class );

    $CLASS->_throw( parameter => "can't load class $class" )
      if $class ne 'Iterator::Flex::Base'
      && !Module::Runtime::require_module( $class );

    delete $ipar_k{ +_NAME };
    $CLASS->_throw( parameter => "'@{[ _NAME ]}' parameter value must be a string\n" )
      if defined( $par = $ipar{ +_NAME } ) && Ref::Util::is_ref( $par );

    push @roles, 'State::Registry';

    delete $gpar_k{ +INPUT_EXHAUSTION };
    my $input_exhaustion = $gpar{ +INPUT_EXHAUSTION } // [ ( +RETURN ) => undef ];

    my @input_exhaustion
      = Ref::Util::is_arrayref( $input_exhaustion )
      ? ( $input_exhaustion->@* )
      : ( $input_exhaustion );

    delete $gpar_k{ +EXHAUSTION };
    my $has_output_exhaustion_policy = defined $gpar{ +EXHAUSTION };

    if ( $input_exhaustion[0] eq +RETURN ) {
        push @roles, 'Exhaustion::ImportedReturn', 'Wrap::Return';
        push $input_exhaustion->@*, undef if @input_exhaustion == 1;
        $gpar{ +INPUT_EXHAUSTION } = \@input_exhaustion;

lib/Iterator/Flex/Factory.pm  view on Meta::CPAN


    $CLASS->_throw( parameter => "missing or undefined 'next' parameter" )
      if !defined( $ipar{ +NEXT } );

    for my $method ( +NEXT, +REWIND, +RESET, +PREV, +CURRENT ) {

        delete $ipar_k{$method};
        next unless defined( my $code = $ipar{$method} );

        $CLASS->_throw( parameter => "'$method' parameter value must be a code reference\n" )
          unless Ref::Util::is_coderef( $code );

        # if $class can't perform the required method, add a role
        # which can.
        if ( $method eq +NEXT ) {
            # next is always a closure, but the caller may want to
            # keep track of $self
            push @roles, defined $ipar{ +_SELF } ? 'Next::ClosedSelf' : 'Next::Closure';
            delete $ipar_k{ +_SELF };
        }
        else {

lib/Iterator/Flex/Factory.pm  view on Meta::CPAN



sub construct_from_iterable ( $CLASS, $obj, $pars = {} ) {

    my ( $mpars, $ipars, $spars ) = parse_pars( $pars );

    $CLASS->_throw( parameter =>
          "unknown parameters pased to construct_from_iterable: @{[ join ', ', keys $mpars->%* ]}" )
      if $mpars->%*;

    if ( Ref::Util::is_blessed_ref( $obj ) ) {
        return $CLASS->construct_from_object( $obj, $ipars, $spars );
    }

    elsif ( Ref::Util::is_arrayref( $obj ) ) {
        $CLASS->_throw(
            parameter => "unknown parameters pased to construct_from_iterable: @{[ join ', ', $ipars->%* ]}" )
          if $ipars->%*;
        return $CLASS->construct_from_array( $obj, $spars );
    }

    elsif ( Ref::Util::is_coderef( $obj ) ) {
        return $CLASS->construct( { $ipars->%*, next => $obj }, $spars );
    }

    elsif ( Ref::Util::is_globref( $obj ) ) {
        return $CLASS->construct( {
                $ipars->%*, next => sub { scalar <$obj> }
            },
            $spars
        );
    }

    $CLASS->_throw(
        parameter => sprintf "'%s' object is not iterable",
        ( ref( $obj ) || 'SCALAR' ) );

lib/Iterator/Flex/Factory.pm  view on Meta::CPAN








sub construct_from_object ( $CLASS, $obj, $ipar, $gpar ) {

    $CLASS->_throw( parameter => q['$object' parameter is not a real object] )
      unless Ref::Util::is_blessed_ref( $obj );

    return construct_from_iterator_flex( $CLASS, $obj, $ipar, $gpar )
      if $obj->isa( 'Iterator::Flex::Base' );

    my %ipar = $ipar->%*;
    my %gpar = $gpar->%*;

    $gpar{ +INPUT_EXHAUSTION } //= [ ( +RETURN ) => undef ];

    if ( !exists $ipar{ +NEXT } ) {

lib/Iterator/Flex/Factory.pm  view on Meta::CPAN


    my \%registry
      = exists $REGISTRY{ refaddr $obj }
      ? $REGISTRY{ refaddr $obj }{ +GENERAL }
      : $CLASS->_throw( internal => "non-registered Iterator::Flex iterator" );


    # if caller didn't specify an exhaustion, set it to return => undef
    my @want = do {
        my $exhaustion = $gpar->{ +EXHAUSTION } // [ ( +RETURN ) => undef ];
        Ref::Util::is_arrayref( $exhaustion )
          ? ( $exhaustion->@* )
          : ( $exhaustion );
    };


    # multiple different output exhaustion roles may have been
    # applied, so the object may claim to support both roles,
    # Exhaustion::Throw and Exhaustion::Return, although only the
    # latest one applied will work.  So, use what's in the registry to
    # figure out what it actually does.

lib/Iterator/Flex/Freeze.pm  view on Meta::CPAN

use strict;
use warnings;
use experimental 'signatures';

our $VERSION = '0.19';

use Iterator::Flex::Factory;
use Iterator::Flex::Utils qw( RETURN EXHAUSTION :IterAttrs :Methods );
use parent 'Iterator::Flex::Base';
use Scalar::Util;
use Ref::Util;

use namespace::clean;








lib/Iterator/Flex/Freeze.pm  view on Meta::CPAN








sub new ( $class, $code, $iterator, $pars = {} ) {

    $class->_throw( parameter => "'serialize' parameter is not a coderef" )
      unless Ref::Util::is_coderef( $code );

    $class->_throw( parameter => "iterator (@{[ $iterator->_name ]}) must provide a freeze method" )
      unless $class->_can_meth( $iterator, +FREEZE );

    $class->_throw(
        parameter => "iterator (@{[ $iterator->_name ]}) must provide set_exhausted/is_exhausted methods" )
      unless $class->_can_meth( $iterator, +SET_EXHAUSTED )
      && $class->_can_meth( $iterator, +IS_EXHAUSTED );

    $class->SUPER::new( { serialize => $code, src => $iterator }, $pars );
}


sub construct ( $class, $state ) {

    $class->_throw( parameter => "'state' parameter must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    my ( $serialize, $src ) = @{$state}{qw( serialize src )};

    $class->_throw( parameter => "'serialize' must be a CODE reference" )
      unless Ref::Util::is_coderef( $serialize );

    # wrap the source iterator so that it returns undef on exhaustion.
    $src
      = Iterator::Flex::Factory->to_iterator( $src, { ( +EXHAUSTION ) => +RETURN } );

    my $self;
    my %params = (
        ( +_NAME ) => 'freeze',

        ( +_SELF ) => \$self,

lib/Iterator/Flex/Grep.pm  view on Meta::CPAN

# ABSTRACT: Grep Iterator Class

use strict;
use warnings;
use experimental 'signatures';

our $VERSION = '0.19';

use Iterator::Flex::Factory;
use Iterator::Flex::Utils qw[ THROW STATE EXHAUSTION :IterAttrs :IterStates ];
use Ref::Util;
use parent 'Iterator::Flex::Base';

use namespace::clean;







lib/Iterator/Flex/Grep.pm  view on Meta::CPAN









sub new ( $class, $code, $iterable, $pars = {} ) {
    $class->_throw( parameter => "'code' parameter is not a coderef" )
      unless Ref::Util::is_coderef( $code );

    $class->SUPER::new( { code => $code, src => $iterable }, $pars );
}


sub construct ( $class, $state ) {

    $class->_throw( parameter => "'state' parameter must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    my ( $code, $src ) = @{$state}{qw[ code src ]};

    $src
      = Iterator::Flex::Factory->to_iterator( $src, { ( +EXHAUSTION ) => +THROW } );

    my $self;
    my $iterator_state;

    return {

lib/Iterator/Flex/Grep.pm  view on Meta::CPAN


            my $ret = eval {
                foreach ( ; ; ) {
                    my $rv = $src->();
                    local $_ = $rv;
                    return $rv if $code->();
                }
            };
            if ( $@ ne '' ) {
                die $@
                  unless Ref::Util::is_blessed_ref( $@ )
                  && $@->isa( 'Iterator::Flex::Failure::Exhausted' );
                return $self->signal_exhaustion;
            }
            return $ret;
        },
        ( +RESET )    => sub { },
        ( +_DEPENDS ) => $src,
    };
}

lib/Iterator/Flex/Manual/Authoring.pod  view on Meta::CPAN


The super class' constructor takes two arguments: a variable containing
iterator specific data (state), and the above-mentioned general
argument hash.  The state variable can take any form, it is not
interpreted by the C<Iterator::Flex> framework.

Here's the code for L<Iterator::Flex::Array/new>:

  sub new ( $class, $array, $pars={} ) {
      $class->_throw( parameter => "argument must be an ARRAY reference" )
        unless Ref::Util::is_arrayref( $array );
      $class->SUPER::new( { array => $array }, $pars );
  }

It's pretty simple. It saves the general options hash if present,
stores the passed array (the state) in a hash, and passes both of
them to the super class' constructor.  (A hash is used here because
L<Iterator::Flex::Array> can be serialized, and extra state is
required to do so).

=head4 construct

lib/Iterator/Flex/Manual/Authoring.pod  view on Meta::CPAN


  package My::Array;

  use strict;
  use warnings;

  use parent 'Iterator::Flex::Base';

  sub new {
      my $class = shift;
      my $gpar = Ref::Util::is_hashref( $_[-1] ) ? pop : {};

      $class->_throw( parameter => "argument must be an ARRAY reference" )
        unless Ref::Util::is_arrayref( $_[0] );

      $class->SUPER::new( { array => $_[0] }, $gpar );
  }

  sub construct {
     my ( $class, $state ) = @_;

     # initialize lexical variables here
     ...
     my $arr = $state->{array};

lib/Iterator/Flex/Map.pm  view on Meta::CPAN

# ABSTRACT: Map Iterator Class

use strict;
use warnings;
use experimental 'signatures';

our $VERSION = '0.19';

use Iterator::Flex::Utils qw( STATE THROW EXHAUSTION :IterAttrs :IterStates );
use Iterator::Flex::Factory;
use Ref::Util;
use parent 'Iterator::Flex::Base';

use namespace::clean;







lib/Iterator/Flex/Map.pm  view on Meta::CPAN









sub new ( $class, $code, $iterable, $pars = {} ) {
    $class->_throw( parameter => "'code' parameter is not a coderef" )
      unless Ref::Util::is_coderef( $code );

    $class->SUPER::new( { code => $code, src => $iterable }, $pars );
}

sub construct ( $class, $state ) {

    $class->_throw( parameter => "'state' parameter must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    my ( $code, $src ) = @{$state}{qw[ code src ]};

    $src
      = Iterator::Flex::Factory->to_iterator( $src, { ( +EXHAUSTION ) => +THROW } );

    my $self;
    my $iterator_state;

    return {

lib/Iterator/Flex/Map.pm  view on Meta::CPAN

        ( +NEXT ) => sub {
            return $self->signal_exhaustion if $iterator_state == +IterState_EXHAUSTED;

            my $ret = eval {
                my $value = $src->();
                local $_ = $value;
                $code->();
            };
            if ( $@ ne '' ) {
                die $@
                  unless Ref::Util::is_blessed_ref( $@ )
                  && $@->isa( 'Iterator::Flex::Failure::Exhausted' );
                return $self->signal_exhaustion;
            }
            return $ret;
        },

        ( +RESET )    => sub { },
        ( +_DEPENDS ) => $src,
    };
}

lib/Iterator/Flex/Product.pm  view on Meta::CPAN


use strict;
use warnings;
use experimental qw( signatures declared_refs refaliasing );

our $VERSION = '0.19';

use Iterator::Flex::Utils qw( RETURN STATE EXHAUSTION :IterAttrs :IterStates );
use Iterator::Flex::Factory;
use parent 'Iterator::Flex::Base';
use Ref::Util;
use List::Util;


use namespace::clean;






lib/Iterator/Flex/Product.pm  view on Meta::CPAN










sub new ( $class, @args ) {
    my $pars = Ref::Util::is_hashref( $args[-1] ) ? pop @args : {};

    $class->_throw( parameter => 'not enough parameters' )
      unless @args;

    my @iterators;
    my @keys;

    # distinguish between ( key => iterator, key =>iterator ) and ( iterator, iterator );
    if ( Ref::Util::is_ref( $args[0] ) ) {
        @iterators = @args;
    }
    else {
        $class->_throw( parameter => 'expected an even number of arguments' )
          if @args % 2;

        while ( @args ) {
            push @keys,      shift @args;
            push @iterators, shift @args;
        }
    }

    $class->SUPER::new( { keys => \@keys, depends => \@iterators, value => [] }, $pars );
}

sub construct ( $class, $state ) {
    $class->_throw( parameter => "state must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    $state->{value} //= [];

    my ( \@depends, \@keys, \@value, $thaw )
      = @{$state}{qw[ depends keys value thaw ]};

    # transform into iterators if required.
    my @iterators
      = map { Iterator::Flex::Factory->to_iterator( $_, { ( +EXHAUSTION ) => +RETURN } ) } @depends;

lib/Iterator/Flex/Role/Error/Throw.pm  view on Meta::CPAN

package Iterator::Flex::Role::Error::Throw;

# ABSTRACT: signal error by throwing

use strict;
use warnings;

our $VERSION = '0.19';

use Iterator::Flex::Utils qw( :default :RegistryKeys );
use Ref::Util;

use Role::Tiny;
use experimental 'signatures';

use namespace::clean;











sub signal_error ( $self ) {
    $self->set_error;
    my $exception = $REGISTRY{ refaddr $self }{ +GENERAL }{ +ERROR }[1];

    $exception->() if Ref::Util::is_coderef( $exception );

    require Iterator::Flex::Failure;
    Iterator::Flex::Failure::Error->throw;
}


1;

#
# This file is part of Iterator-Flex

lib/Iterator/Flex/Role/Exhaustion/Throw.pm  view on Meta::CPAN

package Iterator::Flex::Role::Exhaustion::Throw;

# ABSTRACT: signal exhaustion by setting exhausted flag;

use strict;
use warnings;

our $VERSION = '0.19';

use Ref::Util;
use Iterator::Flex::Utils qw( :default :RegistryKeys );

use Role::Tiny;
use experimental 'signatures';

use namespace::clean;




lib/Iterator/Flex/Role/Exhaustion/Throw.pm  view on Meta::CPAN






sub signal_exhaustion ( $self, @ ) {
    $self->set_exhausted;

    my $exception = $REGISTRY{ refaddr $self }{ +GENERAL }{ +EXHAUSTION }[1];

    $exception->() if Ref::Util::is_coderef( $exception );

    require Iterator::Flex::Failure;
    Iterator::Flex::Failure::Exhausted->throw;
}


1;

#
# This file is part of Iterator-Flex

lib/Iterator/Flex/Role/Next/ClosedSelf.pm  view on Meta::CPAN

package Iterator::Flex::Role::Next::ClosedSelf;

# ABSTRACT: Role for closure iterator which closes over self

use strict;
use warnings;

our $VERSION = '0.19';

use Ref::Util;
use Scalar::Util;
use Iterator::Flex::Utils qw( NEXT _SELF );

use Role::Tiny;
use experimental 'signatures';
use namespace::clean;




lib/Iterator/Flex/Role/Utils.pm  view on Meta::CPAN

package Iterator::Flex::Role::Utils;

# ABSTRACT: Role based utilities

use strict;
use warnings;

our $VERSION = '0.19';

use Ref::Util;

use Role::Tiny;
use experimental 'signatures';







lib/Iterator/Flex/Role/Utils.pm  view on Meta::CPAN









sub _can_meth ( $self, @methods ) {

    my $thing = Ref::Util::is_blessed_ref( $methods[0] ) ? shift @methods : $self;

    my $par = Ref::Util::is_hashref( $methods[-1] ) ? pop @methods : {};

    for my $method ( @methods ) {
        $self->_throw( parameter => "'method' parameters must be a string" )
          if Ref::Util::is_ref( $method );

        my $sub;
        foreach ( "__${method}__", $method ) {
            if ( defined( $sub = $thing->can( $_ ) ) ) {
                my @ret = ( ( !!$par->{name} ? $_ : () ), ( !!$par->{code} ? $sub : () ) );
                push @ret, $sub unless @ret;
                return @ret > 1 ? @ret : $ret[0];
            }
        }
    }

lib/Iterator/Flex/Role/Utils.pm  view on Meta::CPAN






sub _resolve_meth ( $obj, $target, $method, @fallbacks ) {

    my $code = do {

        if ( defined $method ) {
            Ref::Util::is_coderef( $method )
              ? $method
              : $target->can( $method )
              // $obj->_throw( parameter => qq{method '$method' is not provided by the object} );
        }

        else {
            $obj->_can_meth( $target, @fallbacks );
        }
    };

lib/Iterator/Flex/Role/Wrap/Throw.pm  view on Meta::CPAN

package Iterator::Flex::Role::Wrap::Throw;

# ABSTRACT: Role to add throw on exhaustion to an iterator which adapts another iterator

use strict;
use warnings;

our $VERSION = '0.19';

use Iterator::Flex::Utils qw( :RegistryKeys INPUT_EXHAUSTION PASSTHROUGH );
use Ref::Util             qw( is_ref is_blessed_ref is_regexpref is_arrayref is_coderef );
use Role::Tiny;
use experimental 'signatures';

use namespace::clean;

around _construct_next => sub ( $orig, $class, $ipar, $gpar ) {

    my $next = $class->$orig( $ipar, $gpar );

    my $exception = (

lib/Iterator/Flex/Sequence.pm  view on Meta::CPAN









sub new ( $class, @args ) {

    my $pars = Ref::Util::is_hashref( $args[-1] ) ? pop @args : {};

    $class->_throw( parameter => "incorrect number of arguments for sequence" )
      if @args < 1 || @args > 3;

    my %state;
    $state{step}  = pop @args if @args == 3;
    $state{end}   = pop @args;
    $state{begin} = pop @args;


lib/Iterator/Flex/Stack.pm  view on Meta::CPAN










sub new ( $class, @args ) {
    my $pars = Ref::Util::is_hashref( $args[-1] ) ? pop @args : {};

    $class->SUPER::new( {
            depends                => \@args,
            current_iterator_index => undef,
        },
        $pars
    );
}

sub construct ( $class, $state ) {
    $class->_throw( parameter => "state must be a HASH reference" )
      unless Ref::Util::is_hashref( $state );

    $state->{value} //= [];

    my ( \@depends, $prev, $current, $next, $thaw )
      = @{$state}{ 'depends', 'prev', 'current', 'next', 'thaw' };

    # transform into iterators if required.
    my @stack
      = map { Iterator::Flex::Factory->to_iterator( $_, { ( +EXHAUSTION ) => +RETURN } ) } @depends;
    my $value;

lib/Iterator/Flex/Utils.pm  view on Meta::CPAN

use 5.28.0;    # hash slices

use strict;
use warnings;

use experimental 'signatures', 'postderef';

our $VERSION = '0.19';

use Scalar::Util qw( refaddr );
use Ref::Util    qw( is_hashref );
use Exporter 'import';

our %REGISTRY;

our %ExhaustionActions;
our %RegistryKeys;
our %IterAttrs;
our %Methods;
our %IterStates;

t/00-report-prereqs.dd  view on Meta::CPAN

                                      'Test::Spelling' => '0.12',
                                      'Test::Version' => '1'
                                    }
                    },
       'runtime' => {
                      'requires' => {
                                      'Class::Method::Modifiers' => '0',
                                      'List::Util' => '1.33',
                                      'Module::Runtime' => '0',
                                      'Package::Variant' => '0',
                                      'Ref::Util' => '0',
                                      'Role::Tiny' => '2.002004',
                                      'custom::failures' => '0',
                                      'experimental' => '0',
                                      'namespace::clean' => '0',
                                      'perl' => 'v5.28.0'
                                    }
                    },
       'test' => {
                   'recommends' => {
                                     'CPAN::Meta' => '2.120900'

t/Common/iterator.t  view on Meta::CPAN

#! perl

use strict;
use warnings;

use Test2::V0;

use Scalar::Util 'refaddr';
use Ref::Util 'is_ref';
use Iterator::Flex::Common 'iterator';

sub use_object {
    sub { $_[0]->next }
}
sub use_coderef {
    sub { $_[0]->() }
}

sub test {



( run in 0.495 second using v1.01-cache-2.11-cpan-4d50c553e7e )