Object-Extend-0.4.0/0000755000175000017500000000000012233117036016054 5ustar chocolateboychocolateboyObject-Extend-0.4.0/MANIFEST0000644000175000017500000000044112233117036017204 0ustar chocolateboychocolateboyChanges lib/Object/Extend.pm Makefile.PL MANIFEST This list of files README t/all.t t/cache.t t/rebless.t t/recycled.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Object-Extend-0.4.0/META.yml0000644000175000017500000000130512233117036017324 0ustar chocolateboychocolateboy--- abstract: 'add and override per-object methods' author: - 'chocolateboy ' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.130880' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Object-Extend no_index: directory: - t - inc requires: Scalar::Util: 1.09 Storable: 2.05 perl: 5.008000 resources: bugtracker: https://github.com/chocolateboy/Object-Extend/issues repository: https://github.com/chocolateboy/Object-Extend version: v0.4.0 x_test_requires: Test::More: 0 Object-Extend-0.4.0/lib/0000755000175000017500000000000012233117035016621 5ustar chocolateboychocolateboyObject-Extend-0.4.0/lib/Object/0000755000175000017500000000000012233117035020027 5ustar chocolateboychocolateboyObject-Extend-0.4.0/lib/Object/Extend.pm0000644000175000017500000001710512233111676021625 0ustar chocolateboychocolateboypackage Object::Extend; use 5.008; use strict; use warnings; use base qw(Exporter); use constant { SINGLETON => sprintf('%s::_Singleton', __PACKAGE__ ), METHOD_NAME => qr{^[a-zA-Z_]\w*$}, }; use B qw(perlstring); use Carp qw(confess); use Scalar::Util qw(blessed); use Storable qw(freeze); our @EXPORT_OK = qw(extend with SINGLETON); our $VERSION = '0.4.0'; my $ID = 0; my %CACHE; # find/create a unique class name for the supplied object's class/methods combination. # # Eigenclasses are immutable i.e. once an eigenclass has been created, # its @ISA and installed methods never change. This means we can reuse/recycle # an eigenclass if we're passed the same superclass/methods combo. # # Note: we need to identify the subs in the method hash by value (deparse) # rather than by reference (refaddr), since ref addresses can be recycled # (and frequently are for anonymous subs). # # Note: the SINGLETON class added to the eigenclass's @ISA doesn't # implement any methods: we just use it as metadata to indicate that # the object has been extended. sub _eigenclass($$) { my ($class, $methods) = @_; my $key = do { no warnings qw(once); local $Storable::Deparse = 1; # XXX squashed bugs 1) sort hash keys # 2) freeze the $hashref, not the %$hash! local $Storable::canonical = 1; freeze [ $class, $methods ]; }; my $eigenclass = $CACHE{$key}; unless ($eigenclass) { $eigenclass = sprintf '%s::_%x', SINGLETON, ++$ID; $CACHE{$key} = $eigenclass; if ($class->isa(SINGLETON)) { _set_isa($eigenclass, [ $class ]); } else { _set_isa($eigenclass, [ $class, SINGLETON ]); } while (my ($name, $sub) = each(%$methods)) { _install_sub("$eigenclass\::$name", $sub); } } return $eigenclass; } # install the supplied sub in the supplied class. # "extend" is a pretty clear statement of intent, so # we don't issue a warning if the sub already exists # # XXX if we used Exporter::Tiny, we could # allow the redefine warning to be enabled e.g.: # # use Object::Extend extend => { warn_on_redefine => 1 }; sub _install_sub($$) { my ($class, $sub) = @_; no warnings 'redefine'; no strict 'refs'; *$class = $sub; } # set a class's @ISA array sub _set_isa($$) { my ($class, $isa) = @_; no strict 'refs'; *{"$class\::ISA"} = $isa; } # return true if $ref ISA $class - works with non-references, # unblessed references and objects sub _isa($$) { my ($ref, $class) = @_; return blessed($ref) ? $ref->isa($class) : ref($ref) eq $class; } # confess with a message whose string parameters are quoted sub _error($;@) { my $template = shift; my @args = map { defined($_) ? perlstring($_) : 'undef' } @_; confess sprintf($template, @args); } # sanity check the arguments to extend sub _validate(@) { my $object = shift; my $class = blessed($object); unless ($class) { _error( "invalid 'object' parameter: expected blessed reference, got: %s", ref($object) ); } my $methods; if (@_ == 1) { $methods = shift; } elsif (@_ % 2 == 0) { $methods = { @_ }; } unless (_isa($methods, 'HASH')) { _error( "invalid 'methods' parameter: expected a hashref, got: %s", ref($methods) ); } for my $name (keys %$methods) { if (!defined($name)) { _error 'invalid method name (undef)'; } elsif ($name !~ METHOD_NAME) { _error( 'invalid method name (%s): name must match %s', $name, METHOD_NAME ); } else { my $method = $methods->{$name}; unless (_isa($method, 'CODE')) { _error( 'invalid method value for %s: expected a coderef, got: %s', $name, ref($method), ); } } } return ($object, $class, $methods); } # dummy sub to optionally make the syntax # a bit more DSL-ish: extend $object => with ... sub with($) { my $methods = shift; unless (_isa($methods, 'HASH')) { _error( "invalid 'methods' parameter: expected a hashref, got: %s", ref($methods) ); } return $methods; } # find/create an eigenclass for the object's class/methods and bless the object into it sub extend($;@) { my ($object, $class, $methods) = _validate(@_); if (%$methods) { my $eigenclass = _eigenclass($class, $methods); bless $object, $eigenclass; } # else return the original object unchanged return $object; } 1; =head1 NAME Object::Extend - add and override per-object methods =head1 SYNOPSIS use Object::Extend qw(extend); my $foo1 = Foo->new; my $foo2 = Foo->new; extend $foo1 => { bar => sub { ... }, }; $foo1->bar; # OK $foo2->bar; # error =head1 DESCRIPTION This module allows objects to be extended with per-object methods, similar to the use of L in Ruby. Object methods are added to an object-specific shim class (known as an C), which extends the object's original class. The original class is left unchanged. =head2 EXPORTS =head3 extend C takes an object and a hash or hashref of method names and method values (coderefs) and adds the methods to the object's shim class. The object is then blessed into this class and returned. It can be used in standalone statements: extend $object, foo => sub { ... }, bar => \&bar; Or expressions: return extend($object => { bar => sub { ... } })->bar; In both cases, C operates on and returns the supplied object i.e. a new object is never created. If a new object is needed, it can be created manually e.g.: my $object2 = Object->new($object1); my $object3 = clone($object1); extend($object2, foo => sub { ... })->foo; return extend($object3 => ...); Objects can be extended multiple times with new or overridden methods: # call the original method my $object = Foo->new; $object->foo; # override the original method extend $object, foo => sub { ... }; $object->foo; # add a new method extend $object, bar => sub { ... }; $object->bar; =head3 with This sub can optionally be imported to make the use of C more descriptive. It takes and returns a hashref of method names/coderefs: use Object::Extend qw(extend with); extend $object => with { foo => sub { ... } }; =head3 SINGLETON Every extended object's shim class includes an additional (empty) class in its C<@ISA> which indicates that the object has been extended. The name of this class can be accessed by importing the C constant e.g.: use Object::Extend qw(SINGLETON); if ($object->isa(SINGLETON)) { ... } # object extended with object-specific methods =head1 VERSION 0.4.0 =head1 SEE ALSO =over =item * L =item * L =item * L =item * L =back =head1 AUTHOR chocolateboy =head1 COPYRIGHT AND LICENSE Copyright (C) 2013 by chocolateboy This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.14.2 or, at your option, any later version of Perl 5 you may have available. =cut Object-Extend-0.4.0/README0000644000175000017500000000150312233111704016727 0ustar chocolateboychocolateboyObject-Extend version 0.4.0 =========================== This module allows objects to be extended with per-object methods, similar to the use of singleton methods in Ruby. Object methods are added to an object-specific shim class (known as an "eigenclass"), which extends the object's original class. The original class is left unchanged. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires these other modules and libraries: Scalar::Util Storable Test::More COPYRIGHT AND LICENCE Copyright (C) 2013 by chocolateboy This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.14.2 or, at your option, any later version of Perl 5 you may have available. Object-Extend-0.4.0/t/0000755000175000017500000000000012233117035016316 5ustar chocolateboychocolateboyObject-Extend-0.4.0/t/recycled.t0000644000175000017500000000647712233111346020312 0ustar chocolateboychocolateboy#!/usr/bin/env perl use strict; use warnings; use constant { BAR => { bar => sub { 'Bar' } }, BAZ => { baz => sub { 'Baz' } }, NO_RECYCLED => "Can't get a recycled reference", ROUNDS => 1000, }; use Object::Extend qw(extend SINGLETON); use Scalar::Util qw(refaddr); use Test::More tests => 31; sub foo { 'Foo' } # try to trigger the reuse of a refaddr (i.e. C pointer) # and return the first object that uses a recycled refaddr sub recycle(;%) { my %options = @_; my ($original_methods, $recycled_methods) = @options{qw(original recycled)}; my ($recycled, %seen); for (1 .. ROUNDS) { my $object = bless {}; my $refaddr = refaddr($object); if ($seen{$refaddr}) { $recycled = $object; if ($recycled_methods) { extend $recycled => $recycled_methods; } last; } else { if ($original_methods) { extend $object => $original_methods; } $seen{$refaddr} = 1; undef $object; } } return $recycled; } # sanity check the base case: neither the original nor # the recycled are extended SKIP: { my $recycled = recycle(); skip NO_RECYCLED, 5 unless ($recycled); isa_ok $recycled, __PACKAGE__; can_ok $recycled, 'foo'; ok !$recycled->isa(SINGLETON); ok !$recycled->can('bar'); ok !$recycled->can('baz'); }; # make sure the unextended recycled isn't contaminated by # the extended original SKIP: { my $recycled = recycle(original => BAR); skip NO_RECYCLED, 5 unless ($recycled); isa_ok $recycled, __PACKAGE__; can_ok $recycled, 'foo'; ok !$recycled->isa(SINGLETON); ok !$recycled->can('bar'); ok !$recycled->can('baz'); }; # for completeness, make sure the recycled is sane if the # original wasn't extended SKIP: { my $recycled = recycle(recycled => BAR); skip NO_RECYCLED, 5 unless ($recycled); isa_ok $recycled, __PACKAGE__; isa_ok $recycled, SINGLETON; can_ok $recycled, 'foo'; can_ok $recycled, 'bar'; ok !$recycled->can('baz'); }; # make sure there are no surprises if we extend the recycled # in the same way that we've extended the original SKIP: { my $recycled = recycle(original => BAR, recycled => BAR); skip NO_RECYCLED, 5 unless ($recycled); isa_ok $recycled, __PACKAGE__; isa_ok $recycled, SINGLETON; can_ok $recycled, 'foo'; can_ok $recycled, 'bar'; ok !$recycled->can('baz'); }; # define bar in the original and redefine it to return a different value # in recycled. make sure $recycled->bar returns the overridden value SKIP: { my $recycled = recycle(original => BAR, recycled => { bar => sub { 'Bar 2' } }); skip NO_RECYCLED, 6 unless ($recycled); isa_ok $recycled, __PACKAGE__; isa_ok $recycled, SINGLETON; can_ok $recycled, 'foo'; can_ok $recycled, 'bar'; ok !$recycled->can('baz'); is $recycled->bar, 'Bar 2'; }; # extend the original with bar and the recycled with baz # and make sure the recycled isn't contaminated by bar SKIP: { my $recycled = recycle(original => BAR, recycled => BAZ); skip NO_RECYCLED, 5 unless ($recycled); isa_ok $recycled, __PACKAGE__; isa_ok $recycled, SINGLETON; can_ok $recycled, 'foo'; can_ok $recycled, 'baz'; ok !$recycled->can('bar'); }; Object-Extend-0.4.0/t/rebless.t0000644000175000017500000000430412233111346020142 0ustar chocolateboychocolateboy#!/usr/bin/env perl use strict; use warnings; package Bar; sub foo { 'Bar::foo' } sub bar { 'Bar::bar' }; package main; use constant { BAR => { bar => sub { 'bar' } }, BAZ => { baz => sub { 'baz' } }, }; use Object::Extend qw(extend SINGLETON); use Test::More tests => 40; sub foo { 'main::foo' } # if an object is reblessed into another class, then the singleton object # should extend the new class and cease to extend the old class # start with a normal class instance my $object = bless {}; isa_ok $object, __PACKAGE__; ok !$object->isa(SINGLETON); can_ok $object, 'foo'; is $object->foo, 'main::foo'; ok !$object->can('bar'); # extend it with a bar method extend $object => BAR; my $old_eigenclass = ref($object); isa_ok $object, __PACKAGE__; isa_ok $object, SINGLETON; can_ok $object, 'foo'; can_ok $object, 'bar'; is $object->foo, 'main::foo'; is $object->bar, 'bar'; # now rebless the object into a different class (Bar); # there should be no traces of its brush with singleton # status bless $object, 'Bar'; isa_ok $object, 'Bar'; ok !$object->isa(__PACKAGE__); ok !$object->isa(SINGLETON); can_ok $object, 'foo'; can_ok $object, 'bar'; is $object->foo, 'Bar::foo'; is $object->bar, 'Bar::bar'; # make sure the singleton stuff still works if we # bless the object back into its old eigenclass bless $object, $old_eigenclass; isa_ok $object, __PACKAGE__; isa_ok $object, SINGLETON; can_ok $object, 'foo'; can_ok $object, 'bar'; is $object->foo, 'main::foo'; is $object->bar, 'bar'; # now bless the object back into its new class # and re-run the sanity checks for that class bless $object, 'Bar'; isa_ok $object, 'Bar'; ok !$object->isa(__PACKAGE__); ok !$object->isa(SINGLETON); can_ok $object, 'foo'; can_ok $object, 'bar'; is $object->foo, 'Bar::foo'; is $object->bar, 'Bar::bar'; # finally, extend this instance of the # new class and confirm that it # behaves as a singleton instance of # the new class extend $object => %{BAR()}, %{BAZ()}; isa_ok $object, 'Bar'; ok !$object->isa(__PACKAGE__); isa_ok $object, SINGLETON; can_ok $object, 'foo'; can_ok $object, 'bar'; can_ok $object, 'baz'; is $object->foo, 'Bar::foo'; # preserved is $object->bar, 'bar'; # overridden is $object->baz, 'baz'; # new Object-Extend-0.4.0/t/cache.t0000644000175000017500000000531612233111346017552 0ustar chocolateboychocolateboy#!/usr/bin/env perl use strict; use warnings; use constant { FOO => { foo => sub { 'Foo' } }, BAR => { bar => sub { 'Bar' } }, BAZ => { baz => sub { 'Baz' } }, }; use Object::Extend qw(extend SINGLETON); use Test::More tests => 42; my $object = {}; bless $object; extend $object, FOO; isa_ok $object, __PACKAGE__; isa_ok $object, SINGLETON; can_ok $object, 'foo'; ok !$object->can('bar'); ok !$object->can('baz'); my $foo_eigenclass = ref($object); bless $object; extend $object, BAR; isa_ok $object, __PACKAGE__; isa_ok $object, SINGLETON; can_ok $object, 'bar'; ok !$object->can('foo'); ok !$object->can('baz'); my $bar_eigenclass = ref($object); bless $object; extend $object, %{FOO()}, %{BAR()}; isa_ok $object, __PACKAGE__; isa_ok $object, SINGLETON; can_ok $object, 'foo'; can_ok $object, 'bar'; my $foo_bar_eigenclass = ref($object); isnt $foo_eigenclass, $bar_eigenclass; isnt $foo_eigenclass, $foo_bar_eigenclass; isnt $bar_eigenclass, $foo_bar_eigenclass; bless $object; extend $object, FOO; is ref($object), $foo_eigenclass; bless $object; extend $object, BAR; is ref($object), $bar_eigenclass; bless $object; extend $object, %{FOO()}, %{BAR()}; is ref($object), $foo_bar_eigenclass; bless $object; extend $object, %{FOO()}, %{BAZ()}; isnt ref($object), $foo_eigenclass; isnt ref($object), $bar_eigenclass; isnt ref($object), $foo_bar_eigenclass; bless $object; extend $object, %{BAR()}, %{BAZ()}; isnt ref($object), $foo_eigenclass; isnt ref($object), $bar_eigenclass; isnt ref($object), $foo_bar_eigenclass; bless $object; extend $object, %{FOO()}, %{BAR()}, %{BAZ()}; isnt ref($object), $foo_eigenclass; isnt ref($object), $bar_eigenclass; isnt ref($object), $foo_bar_eigenclass; my $foo_bar_baz_eigenclass = ref($object); bless $object; extend $object, %{FOO()}, %{BAR()}, %{BAZ()}; isnt ref($object), $foo_eigenclass; isnt ref($object), $bar_eigenclass; isnt ref($object), $foo_bar_eigenclass; is ref($object), $foo_bar_baz_eigenclass; # seperate calls create a chain, so foo-then-bar # and foo-then-bar-then-baz create new eigenclasses bless $object; extend $object, FOO; is ref($object), $foo_eigenclass; extend $object, BAR; isnt ref($object), $foo_bar_eigenclass; my $foo_then_bar_eigenclass = ref($object); extend $object, BAZ; isnt ref($object), $foo_bar_baz_eigenclass; my $foo_then_bar_then_baz_eigenclass = ref($object); isnt $foo_bar_eigenclass, $foo_then_bar_eigenclass; isnt $foo_bar_baz_eigenclass, $foo_then_bar_then_baz_eigenclass; isnt $foo_then_bar_eigenclass, $foo_then_bar_then_baz_eigenclass; bless $object; extend $object, FOO; is ref($object), $foo_eigenclass; extend $object, BAR; is ref($object), $foo_then_bar_eigenclass; extend $object, BAZ; is ref($object), $foo_then_bar_then_baz_eigenclass; Object-Extend-0.4.0/t/all.t0000644000175000017500000000703412233111346017256 0ustar chocolateboychocolateboy#!/usr/bin/env perl use strict; use warnings; use constant { BAZ_QUUX => { baz => sub { 'Baz' }, quux => sub { 'Quux' }, }, EXTENDED => 1, }; use Scalar::Util qw(refaddr); use Test::More tests => 125; # do this at compile time so that we don't get # "Useless use of anonymous hash ({}) in void context" # warnings BEGIN { use_ok 'Object::Extend' => qw(extend with SINGLETON) } # try to break things with operator overloading: we need to # make sure these don't confuse the code that assigns each # object's eigenclass use overload '+' => \&add, '0+' => \&num, '""' => \&str; sub add { 42 } sub num { 42 } sub str { '42' } # built-in methods for this class sub foo { 'Foo' } sub bar { 'Bar' } # test helper sub check_methods($;$) { my ($object, $extended) = @_; # report errors with caller's line number local $Test::Builder::Level = $Test::Builder::Level + 1; isa_ok $object, __PACKAGE__; is $object->foo, 'Foo'; is $object->bar, 'Bar'; if ($extended) { isnt ref($object), __PACKAGE__; isa_ok $object, SINGLETON; is $object->baz, 'Baz'; is $object->quux, 'Quux'; } else { is ref($object), __PACKAGE__; ok !$object->isa(SINGLETON); ok !$object->can('baz'); ok !$object->can('quux'); } } # setup my $object1 = bless {}; my $object1_refaddr = refaddr($object1); check_methods($object1); # add some methods extend $object1 => BAZ_QUUX; check_methods($object1, EXTENDED); is refaddr($object1), $object1_refaddr; # make sure there's no change (and no error) when adding # the same methods extend $object1 => BAZ_QUUX; check_methods($object1, EXTENDED); is refaddr($object1), $object1_refaddr; # confirm that the eigenclass is the same if we add a new method # to an already extended object extend $object1 => { extra => sub { 'Extra' } }; check_methods($object1, EXTENDED); is refaddr($object1), $object1_refaddr; is $object1->extra, 'Extra'; # confirm that the value returned is the supplied object my $object2 = bless {}; my $object2_refaddr = refaddr($object2); check_methods($object2); my $object3 = extend $object2 => BAZ_QUUX; check_methods($object3, EXTENDED); is refaddr($object3), $object2_refaddr; # make sure extend $object => with { ... } works my $object4 = bless {}; my $object4_refaddr = refaddr($object4); check_methods($object4); extend $object4 => with BAZ_QUUX; check_methods($object4, EXTENDED); is refaddr($object4), $object4_refaddr; # confirm that extend works if methods are supplied as # key/value pairs rather than a hashref my $object5 = bless {}; my $object5_refaddr = refaddr($object5); check_methods($object5); extend $object5 => %{ BAZ_QUUX() }; check_methods($object5, EXTENDED); is refaddr($object5), $object5_refaddr; # confirm that extend works if methods are supplied as # a blessed hashref my $object6 = bless {}; my $object6_refaddr = refaddr($object6); check_methods($object6); extend $object6 => bless(BAZ_QUUX); check_methods($object6, EXTENDED); is refaddr($object6), $object6_refaddr; # make sure the eigenclass assignment isn't # fooled by overloading my $object7 = bless {}; my $object8 = bless {}; my $object7_refaddr = refaddr($object7); my $object8_refaddr = refaddr($object8); isnt $object7_refaddr, $object8_refaddr; check_methods($object7); check_methods($object8); extend $object7 => BAZ_QUUX; extend $object8 => BAZ_QUUX; check_methods($object7, EXTENDED); check_methods($object8, EXTENDED); is refaddr($object7), $object7_refaddr; is refaddr($object8), $object8_refaddr; isnt refaddr($object7), refaddr($object8); Object-Extend-0.4.0/META.json0000644000175000017500000000232512233117036017477 0ustar chocolateboychocolateboy{ "abstract" : "add and override per-object methods", "author" : [ "chocolateboy " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.130880", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Object-Extend", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Scalar::Util" : "1.09", "Storable" : "2.05", "perl" : "5.008000" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/chocolateboy/Object-Extend/issues" }, "repository" : { "url" : "https://github.com/chocolateboy/Object-Extend" } }, "version" : "v0.4.0", "x_test_requires" : { "Test::More" : 0 } } Object-Extend-0.4.0/Changes0000644000175000017500000000137712233116661017362 0ustar chocolateboychocolateboyRevision history for Perl extension Object::Extend. 0.4.0 Sun Oct 27 02:07:03 2013 - allow SINGLETON to be imported 0.3.0 Sun Oct 27 00:27:51 2013 - bump minimum perl version to 5.8.0 0.2.0 Thu Sep 12 22:01:05 2013 - rename EIGENCLASS -> SINGLETON - ensure correctness when ref addresses are recycled: - recycled.t - reuse eigenclasses when safe: - cache.t - ensure reblessed objects behave as expected: - rebless.t 0.1.1 Tue Sep 3 17:41:42 2013 - doc cleanup 0.1.0 Tue Sep 3 03:50:59 2013 - use Scalar::Util::refaddr to ensure eigenclass names aren't broken by overloading - fix doc nit 0.0.1 Mon Sep 2 21:37:07 2013 - original version; created by h2xs 1.23 with options h2xs -AXn Object::Extend Object-Extend-0.4.0/Makefile.PL0000644000175000017500000000171112233113501020017 0ustar chocolateboychocolateboyuse 5.008; use strict; use warnings; use ExtUtils::MakeMaker; my $EUMM_VERSION = eval($ExtUtils::MakeMaker::VERSION); WriteMakefile( NAME => 'Object::Extend', VERSION_FROM => 'lib/Object/Extend.pm', PREREQ_PM => { 'Scalar::Util' => '1.09', # refaddr (used in t/recycled.t) 'Storable' => '2.05', # coderef deparsing }, ABSTRACT_FROM => 'lib/Object/Extend.pm', AUTHOR => 'chocolateboy ', ($EUMM_VERSION >= 6.48 ? (MIN_PERL_VERSION => '5.8.0') : ()), ($EUMM_VERSION >= 6.31 ? (LICENSE => 'perl') : ()), ($EUMM_VERSION >= 6.46 ? (META_MERGE => { test_requires => { 'Test::More' => 0, }, resources => { repository => 'https://github.com/chocolateboy/Object-Extend', bugtracker => 'https://github.com/chocolateboy/Object-Extend/issues', }, }) : () ), );