Iterator-Flex

 view release on metacpan or  search on metacpan

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

package Iterator::Flex::Utils;

# ABSTRACT: Internal utilities

use v5.28;
use strict;
use warnings;

use experimental 'signatures', 'postderef';

our $VERSION = '0.34';

use Scalar::Util qw( refaddr );
use Ref::Util    qw( is_hashref );
use Exporter 'import';
use experimental 'declared_refs';
use Module::Runtime;

our %REGISTRY;

sub mk_indices {
    my $idx = 0;
    return { map { $_ => $idx++ } @_ };
}

sub mk_lc {
    return { map { $_ => lc $_ } @_ };
}

use constant ITER_ATTRS => qw(
  CLASS CURRENT FREEZE METHODS NEXT PREV RESET REWIND STATE _DEPENDS _NAME _ROLES _SELF
);
use constant mk_lc ITER_ATTRS;
use constant REGISTRY_ITERATION_INDICES => map { 'REG_ITER_' . $_ } ITER_ATTRS, 'MAY_METHOD';
use constant mk_indices REGISTRY_ITERATION_INDICES;
our \%RegIterationIndexMap = mk_indices map { lc } ITER_ATTRS;

use constant EXHAUSTED_METHODS => qw( IS_EXHAUSTED SET_EXHAUSTED  );
use constant mk_lc EXHAUSTED_METHODS;

use constant ITER_STATES => qw( IterState_CLEAR IterState_EXHAUSTED IterState_ERROR );
use constant mk_indices ITER_STATES;

use constant REGISTRY_INDICES => qw( REG_ITERATOR REG_GENERAL REG_METHODS );
use constant mk_indices REGISTRY_INDICES;

use constant EXHAUSTION_ACTIONS => qw[ THROW RETURN PASSTHROUGH ];
use constant mk_lc EXHAUSTION_ACTIONS;

# these duplicate ITER_ATTRS. combine?
use constant INTERFACE_PARAMETERS =>
  qw( CURRENT FREEZE METHODS NEXT PREV RESET REWIND STATE _DEPENDS _NAME _ROLES _SELF );
use constant INTERFACE_PARAMETER_VALUES => map { lc $_ } INTERFACE_PARAMETERS;
use constant mk_lc INTERFACE_PARAMETERS;


use constant SIGNAL_PARAMETERS       => qw( INPUT_EXHAUSTION EXHAUSTION ERROR );
use constant SIGNAL_PARAMETER_VALUES => map { lc $_ } SIGNAL_PARAMETERS;
use constant mk_lc SIGNAL_PARAMETERS;

use constant GENERAL_PARAMETERS      => ( INTERFACE_PARAMETERS, SIGNAL_PARAMETERS );
use constant REGISTRY_GENPAR_INDICES => map { 'REG_GP_' . $_ } GENERAL_PARAMETERS;
use constant mk_indices REGISTRY_GENPAR_INDICES;

our \%RegGeneralParameterIndexMap = mk_indices map { lc } GENERAL_PARAMETERS;

our %EXPORT_TAGS = (
    ExhaustionActions => [EXHAUSTION_ACTIONS],
    ExhaustedMethods  => [EXHAUSTED_METHODS],
    RegistryIndices   => [
        REGISTRY_INDICES,        REGISTRY_ITERATION_INDICES,
        '%RegIterationIndexMap', REGISTRY_GENPAR_INDICES,
        '%RegGeneralParameterIndexMap',
    ],

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



sub parse_pars ( @args ) {

    my %pars = do {

        if ( @args == 1 ) {
            is_hashref( $args[0] )
              or throw_failure( parameter => 'expected a hashref' );
            $args[0]->%*;
        }

        else {
            @args % 2
              and throw_failure( parameter => 'expected an even number of arguments for hash' );
            @args;
        }
    };

    my %ipars = delete %pars{ grep exists $pars{$_}, INTERFACE_PARAMETER_VALUES };
    my %spars = delete %pars{ grep exists $pars{$_}, SIGNAL_PARAMETER_VALUES };

    return ( \%pars, \%ipars, \%spars );
}


































sub can_meth ( $obj, @methods ) {

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

    for my $method ( @methods ) {
        throw_failure( parameter => q{'method' parameters must be a string} )
          if Ref::Util::is_ref( $method );

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

    return undef;
}


















sub resolve_meth ( $target, $method, @fallbacks ) {

    my $code = do {

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

        else {
            can_meth( $target, @fallbacks );
        }
    };

    return $code;
}
















sub load_module ( $path, @namespaces ) {

    if ( substr( $path, 0, 1 ) eq q{+} ) {
        my $module = substr( $path, 1 );
        return $module if eval { Module::Runtime::require_module( $module ) };
        throw_failure( class => "unable to load $module" );
    }
    else {
        for my $namespace ( @namespaces ) {
            my $module = $namespace . q{::} . $path;
            return $module if eval { Module::Runtime::require_module( $module ) };
        }
    }

    throw_failure(
        class => join q{ },
        "unable to find a module for '$path' in @{[ join( ', ', @namespaces ) ]}",
    );
}











sub load_role ( $role, @namespaces ) {
    load_module( $role, @namespaces );



( run in 1.678 second using v1.01-cache-2.11-cpan-5837b0d9d2c )