Ref-Util

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

          WriteMakefile() is called (issue #41).

0.203     2017-05-14 10:55:51+02:00 Europe/Paris

        * Rename $REF_UTIL_IMPLEMENTATION environment variable to
          $PERL_REF_UTIL_IMPLEMENTATION (suggested by ether++)

0.202     2017-05-14 10:39:52+02:00 Europe/Paris

        * Use of the Pure-Perl implementation can now be forced at runtime by
          setting either $Ref::Util::IMPLEMENTATION or
          $ENV{REF_UTIL_IMPLEMENTATION} to "XS"
        * Fix is_*_formatref() error messages (reported by tobyink, #38)
        * Speed enhancements for is_*_formatref() on 5.8+
        * Restore 5.6 and 5.8 compatibility
        * PP behaviour now matches XS for \v1.2.3 and \sub {}
        * Updated documentation to reflect the PP/XS split

0.201     2017-05-12 15:42:54+02:00 Europe/Paris

        * Fix space/tab issue in Makefile (srezic, ether)
        * Don't use DynamicPrereqs for unrelated Makefile.PL snippet (ether)

0.200     2017-05-12 10:14:26+02:00 Europe/Paris

        * Reimplement in pure Perl, with a dynamic dependency on a new
          Ref::Util::XS module that contains the fast XS implementation.
          ether++ for the Dist::Zilla wrangling.

0.113     2017-01-16 19:36:58+01:00 Europe/Amsterdam

        * Fix bugtracker link.
          (Shoichi Kaji)

0.112     2017-01-15 17:15:26+01:00 Europe/Amsterdam

        * GH #35: Fix compilation on Sun (Oracle) and some MSVC compilers.

META.json  view on Meta::CPAN

            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "Test::More" : "0.96"
         }
      }
   },
   "provides" : {
      "Ref::Util" : {
         "file" : "lib/Ref/Util.pm",
         "version" : "0.204"
      },
      "Ref::Util::PP" : {
         "file" : "lib/Ref/Util/PP.pm",
         "version" : "0.204"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/p5pclub/ref-util/issues"
      },
      "repository" : {

META.yml  view on Meta::CPAN

  ExtUtils::MakeMaker: '0'
  Text::ParseWords: '0'
dynamic_config: 1
generated_by: 'Dist::Zilla version 6.011, CPAN::Meta::Converter version 2.150010'
license: mit
meta-spec:
  url: http://module-build.sourceforge.net/META-spec-v1.4.html
  version: '1.4'
name: Ref-Util
provides:
  Ref::Util:
    file: lib/Ref/Util.pm
    version: '0.204'
  Ref::Util::PP:
    file: lib/Ref/Util/PP.pm
    version: '0.204'
requires:
  Exporter: '5.57'
  perl: '5.006'
resources:
  bugtracker: https://github.com/p5pclub/ref-util/issues
  repository: git://github.com/p5pclub/ref-util.git
version: '0.204'
x_Dist_Zilla:

Makefile.PL  view on Meta::CPAN

# This Makefile.PL for Ref-Util was generated by
# Dist::Zilla::Plugin::MakeMaker::Awesome 0.41.
# Don't edit it but the dist.ini and plugins used to construct it.

use strict;
use warnings;

use 5.006;
use ExtUtils::MakeMaker;

if (eval { require Ref::Util } && Ref::Util->VERSION < 0.114) {
  package MY;
  no warnings 'once';

  *install = sub {
    my $self = shift;
    return '
pure_site_install ::
	$(NOECHO) $(RM_F) ' . $self->quote_literal(
      $self->catfile('$(DESTINSTALLSITEARCH)', 'Ref', 'Util.pm')
    ) . "\n" . $self->SUPER::install;

Makefile.PL  view on Meta::CPAN

my %WriteMakefileArgs = (
  "ABSTRACT" => "Utility functions for checking references",
  "AUTHOR" => "Sawyer X <xsawyerx\@cpan.org>, Aaron Crane <arc\@cpan.org>, Vikenty Fesunov <vyf\@cpan.org>, Gonzalo Diethelm <gonzus\@cpan.org>, Karen Etheridge <ether\@cpan.org>",
  "CONFIGURE_REQUIRES" => {
    "ExtUtils::MakeMaker" => 0,
    "Text::ParseWords" => 0
  },
  "DISTNAME" => "Ref-Util",
  "LICENSE" => "mit",
  "MIN_PERL_VERSION" => "5.006",
  "NAME" => "Ref::Util",
  "PREREQ_PM" => {
    "Exporter" => "5.57"
  },
  "TEST_REQUIRES" => {
    "ExtUtils::MakeMaker" => 0,
    "File::Spec" => 0,
    "Test::More" => "0.96"
  },
  "VERSION" => "0.204",
  "test" => {

Makefile.PL  view on Meta::CPAN


my %FallbackPrereqs = (
  "Exporter" => "5.57",
  "ExtUtils::MakeMaker" => 0,
  "File::Spec" => 0,
  "Test::More" => "0.96"
);

# inserted by Dist::Zilla::Plugin::DynamicPrereqs 0.034
if (!want_pp() && can_xs()) {
    test_requires('Ref::Util::XS');
    runtime_requires('Ref::Util::XS');
}

unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
  delete $WriteMakefileArgs{TEST_REQUIRES};
  delete $WriteMakefileArgs{BUILD_REQUIRES};
  $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
}

delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
  unless eval { ExtUtils::MakeMaker->VERSION(6.52) };

dist.ini  view on Meta::CPAN


[MakeMaker::Awesome]
:version = 0.35
header_file = makefile-pl-inc.pl

; authordep ExtUtils::HasCompiler = 0.014
[DynamicPrereqs]
:version = 0.029
-delimiter = |
-body = |if (!want_pp() && can_xs()) {
-body = |    test_requires('Ref::Util::XS');
-body = |    runtime_requires('Ref::Util::XS');
-body = |}

lib/Ref/Util.pm  view on Meta::CPAN

package Ref::Util;
# ABSTRACT: Utility functions for checking references
$Ref::Util::VERSION = '0.204';
use strict;
use warnings;

use Exporter 5.57 'import';

{
    my $impl = $ENV{PERL_REF_UTIL_IMPLEMENTATION}
        || our $IMPLEMENTATION
        || 'XS';
    if ($impl ne 'PP' && eval { require Ref::Util::XS; 1 }) {
        _install_aliases('Ref::Util::XS');
    }
    else {
        require Ref::Util::PP;
        _install_aliases('Ref::Util::PP');
    }
}

sub _install_aliases {
    my ($package) = @_;
    no warnings 'once';
    no strict 'refs';
    our %EXPORT_TAGS = %{"${package}::EXPORT_TAGS"};
    our @EXPORT_OK   = @{"${package}::EXPORT_OK"};
    *$_ = \&{"${package}::$_"} for '_using_custom_ops', @EXPORT_OK;

lib/Ref/Util.pm  view on Meta::CPAN

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Ref::Util - Utility functions for checking references

=head1 VERSION

version 0.204

=head1 SYNOPSIS

    use Ref::Util qw( is_plain_arrayref is_plain_hashref );

    if ( is_plain_arrayref( $something ) ) {
        print for @{ $something };
    } elsif ( is_plain_hashref( $something ) ) {
        print for sort values %{ $something };
    }

=head1 DESCRIPTION

Ref::Util introduces several functions to help identify references in a
B<smarter> (and usually faster) way. In short:

    # conventional approach             # with Ref::Util

    ref( $foo ) eq 'ARRAY'              is_plain_arrayref( $foo )

    use Scalar::Util qw( reftype );
    reftype( $foo ) eq 'ARRAY'          is_arrayref( $foo )

The difference:

=over 4

lib/Ref/Util.pm  view on Meta::CPAN


When calling C<ref>, you receive either the reference type (B<SCALAR>,
B<ARRAY>, B<HASH>, etc.) or the package it's blessed into.

When calling C<is_arrayref> (et. al.), you check the variable flags,
so even if it's blessed, you know what type of variable is blessed.

    my $foo = bless {}, 'PKG';
    ref($foo) eq 'HASH'; # fails

    use Ref::Util 'is_hashref';
    my $foo = bless {}, 'PKG';
    is_hashref($foo); # works

On the other hand, in some situations it might be better to specifically
exclude blessed references. The rationale for that might be that merely
because some object happens to be implemented using a hash doesn't mean it's
necessarily correct to treat it as a hash. For these situations, you can use
C<is_plain_hashref> and friends, which have the same performance benefits as
C<is_hashref>.

There is also a family of functions with names like C<is_blessed_hashref>;
these return true for blessed object instances that are implemented using
the relevant underlying type.

=item * Supports tied variables and magic

Tied variables (used in L<Readonly>, for example) are supported.

    use Ref::Util qw<is_plain_hashref>;
    use Readonly;

    Readonly::Scalar my $rh2 => { a => { b => 2 } };
    is_plain_hashref($rh2); # success

L<Ref::Util> added support for this in 0.100. Prior to this version
the test would fail.

=item * Ignores overloading

These functions ignore overloaded operators and simply check the
variable type. Overloading will likely not ever be supported, since I
deem it problematic and confusing.

Overloading makes your variables opaque containers and hides away
B<what> they are and instead require you to figure out B<how> to use

lib/Ref/Util.pm  view on Meta::CPAN

=item * C<INVLIST>

I couldn't find documentation for this type.

=back

Support might be added, if a good reason arises.

=item * Usually fast

When possible, Ref::Util uses L<Ref::Util::XS> as its implementation. (If
you don't have a C compiler available, it uses a pure Perl fallback that has
all the other advantages of Ref::Util, but isn't as fast.)

In fact, Ref::Util::XS has two alternative implementations available
internally, depending on the features supported by the version of Perl
you're using. For Perls that supports custom OPs, we actually add an OP
(which is faster); for other Perls, the implementation that simply calls an
XS function (which is still faster than the pure-Perl equivalent).

See below for L<benchmark results|/"BENCHMARKS">.

=back

=head1 EXPORT

Nothing is exported by default. You can ask for specific subroutines
(described below) or ask for all subroutines at once:

    use Ref::Util qw<is_scalarref is_arrayref is_hashref ...>;

    # or

    use Ref::Util ':all';

=head1 SUBROUTINES

=head2 is_ref($ref)

Check for a reference to anything.

    is_ref([]);

=head2 is_scalarref($ref)

lib/Ref/Util.pm  view on Meta::CPAN


    my $bench = Dumbbench->new(
        target_rel_precision => 0.005,
        initial_runs         => 20,
    );

    my $amount = 1e7;
    my $ref    = [];
    $bench->add_instances(
        Dumbbench::Instance::PerlSub->new(
            name => 'Ref::Util::is_plain_arrayref (CustomOP)',
            code => sub {
                Ref::Util::is_plain_arrayref($ref) for ( 1 .. $amount )
            },
        ),

        Dumbbench::Instance::PerlSub->new(
            name => 'ref(), reftype(), !blessed()',
            code => sub {
                ref $ref
                    && Scalar::Util::reftype($ref) eq 'ARRAY'
                    && !Scalar::Util::blessed($ref)
                    for ( 1 .. $amount );

lib/Ref/Util.pm  view on Meta::CPAN

            name => 'Data::Util::is_array_ref',
            code => sub { is_array_ref($ref) for ( 1 .. $amount ) },
        ),

    );

The results:

    ref():                                   5.335e+00 +/- 1.8e-02 (0.3%)
    ref(), reftype(), !blessed():            1.5545e+01 +/- 3.1e-02 (0.2%)
    Ref::Util::is_plain_arrayref (CustomOP): 2.7951e+00 +/- 6.2e-03 (0.2%)
    Data::Util::is_array_ref:                5.9074e+00 +/- 7.5e-03 (0.1%)

(Rounded run time per iteration)

A benchmark against L<Data::Util>:

    Ref::Util::is_plain_arrayref: 3.47157e-01 +/- 6.8e-05 (0.0%)
    Data::Util::is_array_ref:     6.7562e-01 +/- 7.5e-04 (0.1%)

=head1 SEE ALSO

=over 4

=item * L<Params::Classify>

=item * L<Scalar::Util>

lib/Ref/Util/PP.pm  view on Meta::CPAN

package Ref::Util::PP;
$Ref::Util::PP::VERSION = '0.204';
# ABSTRACT: pure-Perl version of Ref::Util

use strict;
use warnings;
use Carp         ();
use Scalar::Util ();
use Exporter 5.57 'import';

use constant _FORMAT_REFS_WORK => ("$]" >= 5.007);
use constant _RX_NEEDS_MAGIC   => (Scalar::Util::reftype(qr/^/) ne 'REGEXP');

lib/Ref/Util/PP.pm  view on Meta::CPAN

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Ref::Util::PP - pure-Perl version of Ref::Util

=head1 VERSION

version 0.204

=head1 SYNOPSIS

    use Ref::Util;

=head1 DESCRIPTION

This module provides a pure-Perl implementation of the functions in
L<Ref::Util>.

Ref::Util:PP will be used automatically if Ref::Util is installed on a
system with no C compiler, but you can force its usage by setting either
C<$Ref::Util::IMPLEMENTATION> or the C<PERL_REF_UTIL_IMPLEMENTATION>
environment variable to C<PP>.

=head1 AUTHORS

=over 4

=item *

Sawyer X <xsawyerx@cpan.org>

t/all-permutations.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More 'tests' => 5;
use Ref::Util ':all';

use constant FORMAT_REFS_WORK => ("$]" >= 5.007);

# FIXME: plain regular expressions, blessed regular expressions

my $plain_formatref = do {
    format FH1 =
.
    *FH1{'FORMAT'};
};

t/all-permutations.t  view on Meta::CPAN


my @all_keys     = sort keys %all;
my @plain_keys   = sort keys %plain;
my @blessed_keys = sort keys %blessed;

subtest 'non-refs' => sub {
    foreach my $value ( 0, 1, 'string', '', undef, '0', '0e0' ) {
        # better string representation for test output
        my $rep = defined $value ? $value eq '' ? q{''} : $value : '(undef)';

        for my $name (grep /^is_/, @Ref::Util::EXPORT_OK) {
            next if !FORMAT_REFS_WORK && $name =~ /formatref/;
            my $func = do { no strict 'refs'; \&{"Ref::Util::$name"} };
            ok( !$func->($value), "$name($rep) is false" );
        }
    }

    done_testing();
};

subtest 'plain references only work on is_plain functions' => sub {
    # each %plain should fail each test of the %blessed
    foreach my $plain_type (@plain_keys) {

t/arrayref.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More tests => 7;

BEGIN {
    use_ok('Ref::Util');
    Ref::Util->import('is_arrayref');
}

can_ok( Ref::Util::, 'is_arrayref' );
Ref::Util::is_arrayref(\1);

ok( !is_arrayref(\1), 'Correctly identify scalarref' );
ok( !is_arrayref({}), 'Correctly identify hashref' );
ok( !is_arrayref(sub {}), 'Correctly identify coderef' );
ok( !is_arrayref(qr//), 'Correctly identify regexpref' );
ok( is_arrayref([]), 'Correctly identify arrayref' );

t/b-concise.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;
use Ref::Util 'is_arrayref';
require B::Concise;

plan skip_all => 'This version of B::Concise does not have "compile"'
    if !B::Concise->can('compile');

plan skip_all => 'nothing to do when no custom ops'
    if !Ref::Util::_using_custom_ops();

plan tests => 2;

sub func { is_arrayref([]) }

my $walker = B::Concise::compile('-exec', 'func', \&func);
B::Concise::walk_output(\ my $buf);
eval { $walker->() };
my $exn = $@;

t/dynamic.t  view on Meta::CPAN

use strict;
use warnings;
use Ref::Util;
use Test::More tests => 2;

my $cb = Ref::Util->can('is_arrayref');
ok( $cb->([]), 'is_arrayref with can()' );
ok( !$cb->({}), 'is_arrayref with can()' );

t/expr.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More tests => 1;
use Ref::Util 'is_arrayref';

sub arrayref { [] }
ok( is_arrayref( arrayref() ), 'Got arrayref from expression' );

t/functions.t  view on Meta::CPAN

        [bless(sub {}),              'blessed code'],
        [$blessed_glob,              'blessed glob'],
        [do { bless \\(my $x = 1) }, 'blessed ref'],
        [$blessed_format,            'blessed format'],
    );

    plan tests => 26 * @cases + 1;  # extra one is for use_ok() above
}

BEGIN {
    use_ok('Ref::Util');

    Ref::Util->import(qw<
        is_ref
        is_scalarref
        is_arrayref
        is_hashref
        is_coderef
        is_regexpref
        is_globref
        is_formatref
        is_ioref
        is_refref

t/list.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More tests => 2;
use Ref::Util qw<is_arrayref is_hashref>;

# Call multiple routines in a single list expression:
my @got = ( is_arrayref([]), is_hashref({}) );

ok( $got[0], 'got arrayref in list context' );
ok( $got[1], 'got hashref in list context' );

t/magic-readonly.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;
use Ref::Util qw<is_hashref is_plain_hashref is_blessed_hashref>;

eval { require Readonly; Readonly->import; 1; }
or plan 'skip_all' => 'Readonly is required for this test';

plan 'tests' => 3;

Readonly::Scalar( my $rh2 => { a => { b => 2 } } );

ok( is_hashref($rh2), 'Readonly objects work!' );
ok( is_plain_hashref($rh2), 'They are not plain!' );

t/magic.t  view on Meta::CPAN

use strict;
use warnings;
use Ref::Util qw<is_arrayref>;
use Test::More 'tests' => 1;

my ( $x, $y );

{
    package Foo;
    sub TIESCALAR { bless {}, shift }
    sub FETCH { $x }
}

t/pureperl.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;

BEGIN {
    plan skip_all => "All tests already executed in PP mode"
        if !eval { require Ref::Util::XS };

    no warnings 'uninitialized';
    plan skip_all => "Already running pure-Perl tests"
        if $ENV{PERL_REF_UTIL_IMPLEMENTATION} eq 'PP';
}

use Config;
use IPC::Open2 qw(open2);
use File::Find qw(find);

t/toomany.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More tests => 6;
use Ref::Util qw<is_arrayref is_hashref>;

my $array_func = \&is_arrayref;
my $hash_func = \&is_hashref;

is(prototype($array_func), '$', 'is_arrayref has "$" prototype');
is(prototype($hash_func), '$', 'is_hashref has "$" prototype');

# We have to use string eval for this, because when the custom op is being
# used, we expect the direct calls to fail at compile time
my @cases = (

t/toomany.t  view on Meta::CPAN

     'direct hash call with too many arguments'],
    [is_hashref => '$hash_func->([], 17)',
     'hash call through coderef with too many arguments'],
);

for my $case (@cases) {
    my ($name, $code, $desc) = @$case;
    scalar eval $code;
    my $exn = $@;
    my @all_names =
        ($name, map "$_\::$name", qw<Ref::Util Ref::Util::PP Ref::Util::XS>);
    my $rx = join '|', (
        (map "Too many arguments for $_\\b", @all_names),
        (map "Usage: $_\\(ref\\)", @all_names),
    );
    like($exn, qr/^(?:$rx)/, $desc);
}

tools/bench.pl  view on Meta::CPAN

use strict;
use warnings;
use constant { 'AMOUNT' => 1e8 };

use Ref::Util qw<is_arrayref is_plain_arrayref is_plain_hashref>;
use Scalar::Util ();
use Data::Util ':check';
use Dumbbench;
use Dumbbench::Instance::PerlSub;

my $bench = Dumbbench->new(
    'target_rel_precision' => 0.005, # seek ~0.5%
    'initial_runs'         => 20,    # the higher the more reliable
);

my $amount = AMOUNT();
my $ref    = [];

no warnings;
$bench->add_instances(
    Dumbbench::Instance::PerlSub->new(
        'name' => 'Ref::Util::is_plain_arrayref (CustomOP)',
        'code' => sub { Ref::Util::is_plain_arrayref($ref) for ( 1 .. $amount ) },
    ),

    Dumbbench::Instance::PerlSub->new(
        'name' => 'ref(), reftype(), !blessed()',
        'code' => sub {
            ref $ref
                && Scalar::Util::reftype($ref) eq 'ARRAY'
                && !Scalar::Util::blessed($ref)
                for ( 1 .. $amount );
        },



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