Skip Menu |

This queue is for tickets about the curry CPAN distribution.

Report information
The Basics
Id: 98407
Status: resolved
Priority: 0/
Queue: curry

People
Owner: Nobody in particular
Requestors: TEAM [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 1.000000
Fixed in: 1.001000



Subject: $_curry and $_curry_weak
As promised, somewhat later than I'd hoped: The attached curry-vars.patch provides the $_curry and $_curry_weak imports: use curry::weak qw($_curry_weak); $obj->$_curry_weak(sub { my ($self, $other, $vars, @args) = @_; ... }, qw(other vars)); use curry qw($_curry); $obj->$_curry(sub { my ($self, $other, $vars, @args) = @_; ... }, qw(other vars)); They're disabled by default. The only issue I'm aware of is that ->import is no longer proxied, but ->curry::import() seems somewhat unlikely to be desirable in practice. There's a second patch (which would be applied on top of the first one) to use the new $_curry/$_curry_weak vars in AUTOLOAD, reduces duplication but introduces extra sub-call overhead. Code's simple enough that a bit of duplication in exchange for a tiny performance improvement seems reasonable though. Also available on github - https://github.com/tm604/curry - if you prefer. cheers, Tom
Subject: curry-vars.patch
diff --git a/Changes b/Changes index 89e2100..35944a0 100644 --- a/Changes +++ b/Changes @@ -1,2 +1,6 @@ +2.000000 - 2014-08-25 + - Support $_curry and $_curry_weak. Note that this means you + can no longer use $obj->curry::import(). + 1.000000 - 2012-09-09 - Initial release diff --git a/lib/curry.pm b/lib/curry.pm index 58bbeb4..9b52c87 100644 --- a/lib/curry.pm +++ b/lib/curry.pm @@ -1,8 +1,18 @@ package curry; -our $VERSION = '1.000000'; +our $VERSION = '2.000000'; $VERSION = eval $VERSION; +use Exporter qw(import); + +our @EXPORT_OK = qw($_curry); + +our $_curry = sub { + my ($invocant, $code) = splice @_, 0, 2; + my @args = @_; + sub { $invocant->$code(@args => @_) } +}; + sub AUTOLOAD { my $invocant = shift; my ($method) = our $AUTOLOAD =~ /^curry::(.+)$/; @@ -16,6 +26,20 @@ package curry::weak; use Scalar::Util (); +use Exporter qw(import); + +our @EXPORT_OK = qw($_curry_weak); + +our $_curry_weak = sub { + my ($invocant, $code) = splice @_, 0, 2; + Scalar::Util::weaken($invocant) if Scalar::Util::blessed($invocant); + my @args = @_; + sub { + return unless $invocant; + $invocant->$code(@args => @_) + } +}; + sub AUTOLOAD { my $invocant = shift; Scalar::Util::weaken($invocant) if Scalar::Util::blessed($invocant); @@ -59,6 +83,39 @@ is equivalent to: }; }; +If you want to pass a weakened copy of an object to a coderef, import +the C< $_curry_weak > variable: + + use curry::weak '$_curry_weak'; + + my $code = $self->$_curry_weak(sub { + my ($self, @args) = @_; + print "$self must still be alive, because we were called (with @args)\n"; + }, 'xyz'); + +which is much the same as: + + my $code = do { + my $sub = sub { + my ($self, @args) = @_; + print "$self must still be alive, because we were called (with @args)\n"; + }; + Scalar::Util::weaken(my $weak_obj = $self); + sub { + return unless $weak_obj; # in case it already went away + $sub->($weak_obj, 'xyz', @_); + } + }; + +There's an equivalent - but somewhat less useful - C< $_curry > variable: + + use curry '$_curry'; + + my $code = $self->$_curry(sub { + my ($self, $var) = @_; + print "The stashed value from our ->something method call was $var\n"; + }, $self->something('complicated')); + =head1 RATIONALE How many times have you written diff --git a/t/curry-import.t b/t/curry-import.t new file mode 100644 index 0000000..d4f1f7b --- /dev/null +++ b/t/curry-import.t @@ -0,0 +1,74 @@ +use strict; +use warnings; + +use Test::More tests => 18; +use Scalar::Util qw(weaken); +use curry qw($_curry); + +sub dispose_ok($;$) { + weaken(my $copy = $_[0]); + fail("variable is not a ref") unless ref $_[0]; + undef $_[0]; + ok(!defined($copy), $_[1]); +} + +{ + package Foo; + sub new { bless {}, shift } +} + +{ # basic behaviour - can we call without args? + my $foo = Foo->new; + + my $called; + my $code = $foo->$_curry(sub { + ok(shift->isa('Foo'), '$_curry object is correct class'); + ok(!@_, '$_curry did not pick up any stray parameters'); + ++$called; + }); + fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(); + ok($called, 'curried code was called'); + undef $foo; + $called = 0; + $code->(); + ok($called, 'curried code executed successfully after original object goes out of scope'); +} + +{ # parameter passthrough + my $foo = Foo->new; + + my $called; + my $code = $foo->$_curry(sub { + ok(shift->isa('Foo'), '$_curry object is correct class'); + is_deeply(\@_, [qw(one two three)], 'curried code had the expected parameters'); + ++$called; + }); + fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(qw(one two three)); + ok($called, 'curried code was called'); + undef $foo; + $called = 0; + $code->(qw(one two three)); + ok($called, 'curried code again executed successfully after original object goes out of scope'); +} + +{ # stashed parameters + my $foo = Foo->new; + + my $called; + my $code = $foo->$_curry(sub { + ok(shift->isa('Foo'), '$_curry object is correct class'); + is_deeply(\@_, [qw(stashed parameters one two three)], 'curried code had the expected parameters'); + ++$called; + }, qw(stashed parameters)); + fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(qw(one two three)); + ok($called, 'curried code was called'); + undef $foo; + $called = 0; + $code->(qw(one two three)); + ok($called, 'curried code again executed successfully after original object goes out of scope'); +} + +done_testing; diff --git a/t/curry-weak-import.t b/t/curry-weak-import.t new file mode 100644 index 0000000..ee7962d --- /dev/null +++ b/t/curry-weak-import.t @@ -0,0 +1,56 @@ +use strict; +use warnings; + +use Test::More; +use Scalar::Util qw(weaken); +use curry::weak qw($_curry_weak); + +sub dispose_ok($;$) { + weaken(my $copy = $_[0]); + fail("variable is not a ref") unless ref $_[0]; + undef $_[0]; + ok(!defined($copy), $_[1]); +} + +{ + package Foo; + sub new { bless {}, shift } +} + +{ # basic behaviour - can we call without args? + my $foo = Foo->new; + + my $called; + my $code = $foo->$_curry_weak(sub { + ok(shift->isa('Foo'), '$_curry_weak object is correct class'); + ok(!@_, '$_curry_weak did not pick up any stray parameters on the way in'); + ++$called; + }); + fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(); + ok($called, 'curried code was called'); + dispose_ok($foo, '$foo departs without a fight'); + $called = 0; + $code->(); + ok(!$called, '... and we can still use the coderef as a no-op'); +} + +{ # parameter passthrough + my $foo = Foo->new; + + my $called; + my $code = $foo->$_curry_weak(sub { + ok(shift->isa('Foo'), '$_curry_weak object is correct class'); + is_deeply(\@_, [qw(stashed parameters one two three)], 'args passed as expected'); + ++$called; + }, qw(stashed parameters)); + fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(qw(one two three)); + ok($called, 'curried code was called'); + dispose_ok($foo, '$foo departs without a fight'); + $called = 0; + $code->(); + ok(!$called, '... and we can still use the coderef as a no-op'); +} + +done_testing;
Subject: less_duplication.patch
diff --git a/lib/curry.pm b/lib/curry.pm index 9b52c87..ba11852 100644 --- a/lib/curry.pm +++ b/lib/curry.pm @@ -16,10 +16,7 @@ our $_curry = sub { sub AUTOLOAD { my $invocant = shift; my ($method) = our $AUTOLOAD =~ /^curry::(.+)$/; - my @args = @_; - return sub { - $invocant->$method(@args => @_); - } + $invocant->$_curry($method => @_); } package curry::weak; @@ -44,11 +41,7 @@ sub AUTOLOAD { my $invocant = shift; Scalar::Util::weaken($invocant) if Scalar::Util::blessed($invocant); my ($method) = our $AUTOLOAD =~ /^curry::weak::(.+)$/; - my @args = @_; - return sub { - return unless $invocant; - $invocant->$method(@args => @_); - } + $invocant->$_curry_weak($method => @_); } 1;
Needs to be refactored to drop the import and use $curry::curry and $curry::weak instead
also, ilmari suggests: add ->$_curry($methodname) to the docs too, not just ->$_curry($coderef)?
Here's a new patch (against master) for $curry::curry and $curry::weak - no import shenanigans.
Subject: curry.patch
diff --git a/Changes b/Changes index 35944a0..2868b4a 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,5 @@ -2.000000 - 2014-08-25 - - Support $_curry and $_curry_weak. Note that this means you - can no longer use $obj->curry::import(). +2.000000 - 2015-06-11 + - Support $curry::curry and $curry::weak. 1.000000 - 2012-09-09 - Initial release diff --git a/lib/curry.pm b/lib/curry.pm index 9b52c87..d5a13d2 100644 --- a/lib/curry.pm +++ b/lib/curry.pm @@ -3,34 +3,25 @@ package curry; our $VERSION = '2.000000'; $VERSION = eval $VERSION; -use Exporter qw(import); - -our @EXPORT_OK = qw($_curry); - -our $_curry = sub { +our $curry = sub { my ($invocant, $code) = splice @_, 0, 2; my @args = @_; sub { $invocant->$code(@args => @_) } }; +our $weak = $curry::weak::curry_weak; + sub AUTOLOAD { my $invocant = shift; my ($method) = our $AUTOLOAD =~ /^curry::(.+)$/; - my @args = @_; - return sub { - $invocant->$method(@args => @_); - } + $invocant->$curry($method => @_); } package curry::weak; use Scalar::Util (); -use Exporter qw(import); - -our @EXPORT_OK = qw($_curry_weak); - -our $_curry_weak = sub { +our $curry_weak = sub { my ($invocant, $code) = splice @_, 0, 2; Scalar::Util::weaken($invocant) if Scalar::Util::blessed($invocant); my @args = @_; @@ -44,11 +35,7 @@ sub AUTOLOAD { my $invocant = shift; Scalar::Util::weaken($invocant) if Scalar::Util::blessed($invocant); my ($method) = our $AUTOLOAD =~ /^curry::weak::(.+)$/; - my @args = @_; - return sub { - return unless $invocant; - $invocant->$method(@args => @_); - } + $invocant->$curry_weak($method => @_); } 1; @@ -83,12 +70,12 @@ is equivalent to: }; }; -If you want to pass a weakened copy of an object to a coderef, import -the C< $_curry_weak > variable: +If you want to pass a weakened copy of an object to a coderef, use the +C< $weak > package variable: - use curry::weak '$_curry_weak'; + use curry::weak; - my $code = $self->$_curry_weak(sub { + my $code = $self->$curry::weak(sub { my ($self, @args) = @_; print "$self must still be alive, because we were called (with @args)\n"; }, 'xyz'); @@ -107,15 +94,24 @@ which is much the same as: } }; -There's an equivalent - but somewhat less useful - C< $_curry > variable: +C< $curry::weak > is actually a copy of C< $curry::weak::curry_weak >. - use curry '$_curry'; +There's an equivalent - but somewhat less useful - C< $curry > package variable: - my $code = $self->$_curry(sub { + use curry; + + my $code = $self->$curry::curry(sub { my ($self, $var) = @_; print "The stashed value from our ->something method call was $var\n"; }, $self->something('complicated')); +Both of these methods can also be used if your scalar is a method name, rather +than a coderef. + + use curry; + + my $code = $self->$curry::curry($methodname, $self->something('complicated')); + =head1 RATIONALE How many times have you written diff --git a/t/curry-import.t b/t/curry-import.t deleted file mode 100644 index d4f1f7b..0000000 --- a/t/curry-import.t +++ /dev/null @@ -1,74 +0,0 @@ -use strict; -use warnings; - -use Test::More tests => 18; -use Scalar::Util qw(weaken); -use curry qw($_curry); - -sub dispose_ok($;$) { - weaken(my $copy = $_[0]); - fail("variable is not a ref") unless ref $_[0]; - undef $_[0]; - ok(!defined($copy), $_[1]); -} - -{ - package Foo; - sub new { bless {}, shift } -} - -{ # basic behaviour - can we call without args? - my $foo = Foo->new; - - my $called; - my $code = $foo->$_curry(sub { - ok(shift->isa('Foo'), '$_curry object is correct class'); - ok(!@_, '$_curry did not pick up any stray parameters'); - ++$called; - }); - fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; - $code->(); - ok($called, 'curried code was called'); - undef $foo; - $called = 0; - $code->(); - ok($called, 'curried code executed successfully after original object goes out of scope'); -} - -{ # parameter passthrough - my $foo = Foo->new; - - my $called; - my $code = $foo->$_curry(sub { - ok(shift->isa('Foo'), '$_curry object is correct class'); - is_deeply(\@_, [qw(one two three)], 'curried code had the expected parameters'); - ++$called; - }); - fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; - $code->(qw(one two three)); - ok($called, 'curried code was called'); - undef $foo; - $called = 0; - $code->(qw(one two three)); - ok($called, 'curried code again executed successfully after original object goes out of scope'); -} - -{ # stashed parameters - my $foo = Foo->new; - - my $called; - my $code = $foo->$_curry(sub { - ok(shift->isa('Foo'), '$_curry object is correct class'); - is_deeply(\@_, [qw(stashed parameters one two three)], 'curried code had the expected parameters'); - ++$called; - }, qw(stashed parameters)); - fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; - $code->(qw(one two three)); - ok($called, 'curried code was called'); - undef $foo; - $called = 0; - $code->(qw(one two three)); - ok($called, 'curried code again executed successfully after original object goes out of scope'); -} - -done_testing; diff --git a/t/curry-packagevar.t b/t/curry-packagevar.t new file mode 100644 index 0000000..e58a972 --- /dev/null +++ b/t/curry-packagevar.t @@ -0,0 +1,74 @@ +use strict; +use warnings; + +use Test::More tests => 18; +use Scalar::Util qw(weaken); +use curry; + +sub dispose_ok($;$) { + weaken(my $copy = $_[0]); + fail("variable is not a ref") unless ref $_[0]; + undef $_[0]; + ok(!defined($copy), $_[1]); +} + +{ + package Foo; + sub new { bless {}, shift } +} + +{ # basic behaviour - can we call without args? + my $foo = Foo->new; + + my $called; + my $code = $foo->$curry::curry(sub { + ok(shift->isa('Foo'), '$curry::curry object is correct class'); + ok(!@_, '$curry::curry did not pick up any stray parameters'); + ++$called; + }); + fail('$curry::curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(); + ok($called, 'curried code was called'); + undef $foo; + $called = 0; + $code->(); + ok($called, 'curried code executed successfully after original object goes out of scope'); +} + +{ # parameter passthrough + my $foo = Foo->new; + + my $called; + my $code = $foo->$curry::curry(sub { + ok(shift->isa('Foo'), '$curry::curry object is correct class'); + is_deeply(\@_, [qw(one two three)], 'curried code had the expected parameters'); + ++$called; + }); + fail('$curry::curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(qw(one two three)); + ok($called, 'curried code was called'); + undef $foo; + $called = 0; + $code->(qw(one two three)); + ok($called, 'curried code again executed successfully after original object goes out of scope'); +} + +{ # stashed parameters + my $foo = Foo->new; + + my $called; + my $code = $foo->$curry::curry(sub { + ok(shift->isa('Foo'), '$curry::curry object is correct class'); + is_deeply(\@_, [qw(stashed parameters one two three)], 'curried code had the expected parameters'); + ++$called; + }, qw(stashed parameters)); + fail('$curry::curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(qw(one two three)); + ok($called, 'curried code was called'); + undef $foo; + $called = 0; + $code->(qw(one two three)); + ok($called, 'curried code again executed successfully after original object goes out of scope'); +} + +done_testing; diff --git a/t/curry-weak-import.t b/t/curry-weak-import.t deleted file mode 100644 index ee7962d..0000000 --- a/t/curry-weak-import.t +++ /dev/null @@ -1,56 +0,0 @@ -use strict; -use warnings; - -use Test::More; -use Scalar::Util qw(weaken); -use curry::weak qw($_curry_weak); - -sub dispose_ok($;$) { - weaken(my $copy = $_[0]); - fail("variable is not a ref") unless ref $_[0]; - undef $_[0]; - ok(!defined($copy), $_[1]); -} - -{ - package Foo; - sub new { bless {}, shift } -} - -{ # basic behaviour - can we call without args? - my $foo = Foo->new; - - my $called; - my $code = $foo->$_curry_weak(sub { - ok(shift->isa('Foo'), '$_curry_weak object is correct class'); - ok(!@_, '$_curry_weak did not pick up any stray parameters on the way in'); - ++$called; - }); - fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; - $code->(); - ok($called, 'curried code was called'); - dispose_ok($foo, '$foo departs without a fight'); - $called = 0; - $code->(); - ok(!$called, '... and we can still use the coderef as a no-op'); -} - -{ # parameter passthrough - my $foo = Foo->new; - - my $called; - my $code = $foo->$_curry_weak(sub { - ok(shift->isa('Foo'), '$_curry_weak object is correct class'); - is_deeply(\@_, [qw(stashed parameters one two three)], 'args passed as expected'); - ++$called; - }, qw(stashed parameters)); - fail('$_curry did not give us a coderef') unless ref($code) eq 'CODE'; - $code->(qw(one two three)); - ok($called, 'curried code was called'); - dispose_ok($foo, '$foo departs without a fight'); - $called = 0; - $code->(); - ok(!$called, '... and we can still use the coderef as a no-op'); -} - -done_testing; diff --git a/t/curry-weak-packagevar.t b/t/curry-weak-packagevar.t new file mode 100644 index 0000000..7a38c39 --- /dev/null +++ b/t/curry-weak-packagevar.t @@ -0,0 +1,56 @@ +use strict; +use warnings; + +use Test::More; +use Scalar::Util qw(weaken); +use curry::weak; + +sub dispose_ok($;$) { + weaken(my $copy = $_[0]); + fail("variable is not a ref") unless ref $_[0]; + undef $_[0]; + ok(!defined($copy), $_[1]); +} + +{ + package Foo; + sub new { bless {}, shift } +} + +{ # basic behaviour - can we call without args? + my $foo = Foo->new; + + my $called; + my $code = $foo->$curry::weak::curry_weak(sub { + ok(shift->isa('Foo'), '$curry::weak::curry_weak object is correct class'); + ok(!@_, '$curry::weak::curry_weak did not pick up any stray parameters on the way in'); + ++$called; + }); + fail('$curry::weak::curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(); + ok($called, 'curried code was called'); + dispose_ok($foo, '$foo departs without a fight'); + $called = 0; + $code->(); + ok(!$called, '... and we can still use the coderef as a no-op'); +} + +{ # parameter passthrough + my $foo = Foo->new; + + my $called; + my $code = $foo->$curry::weak::curry_weak(sub { + ok(shift->isa('Foo'), '$curry::weak::curry_weak object is correct class'); + is_deeply(\@_, [qw(stashed parameters one two three)], 'args passed as expected'); + ++$called; + }, qw(stashed parameters)); + fail('$curry::weak::curry did not give us a coderef') unless ref($code) eq 'CODE'; + $code->(qw(one two three)); + ok($called, 'curried code was called'); + dispose_ok($foo, '$foo departs without a fight'); + $called = 0; + $code->(); + ok(!$called, '... and we can still use the coderef as a no-op'); +} + +done_testing;