Created
February 15, 2013 12:32
-
-
Save tobyink/4960137 to your computer and use it in GitHub Desktop.
git diff master delegation-overwriting-rt81181
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/Changes b/Changes | |
| index 09d39ba..f9a8b4c 100644 | |
| --- a/Changes | |
| +++ b/Changes | |
| @@ -1,3 +1,5 @@ | |
| + - has will refuse to overwrite locally defined subs with generated | |
| + accessors. | |
| - expand is => 'lazy' doc to make it clear that you can make rw lazy | |
| attributes if you really want to | |
| - handles => "RoleName" tries to load the module | |
| diff --git a/lib/Method/Generate/Accessor.pm b/lib/Method/Generate/Accessor.pm | |
| index 1a13a56..2fce625 100644 | |
| --- a/lib/Method/Generate/Accessor.pm | |
| +++ b/lib/Method/Generate/Accessor.pm | |
| @@ -18,9 +18,15 @@ BEGIN { | |
| ; | |
| } | |
| +sub _die_overwrite | |
| +{ | |
| + my ($pkg, $method, $type) = @_; | |
| + die "You cannot overwrite a locally defined method ($method) with @{[ $type || 'an accessor' ]}"; | |
| +} | |
| + | |
| sub generate_method { | |
| my ($self, $into, $name, $spec, $quote_opts) = @_; | |
| - $name =~ s/^\+//; | |
| + $spec->{allow_overwrite}++ if $name =~ s/^\+//; | |
| die "Must have an is" unless my $is = $spec->{is}; | |
| if ($is eq 'ro') { | |
| $spec->{reader} = $name unless exists $spec->{reader}; | |
| @@ -73,6 +79,8 @@ sub generate_method { | |
| my %methods; | |
| if (my $reader = $spec->{reader}) { | |
| + _die_overwrite($into, $reader, 'a reader') | |
| + if !$spec->{allow_overwrite} && *{_getglob("${into}::${reader}")}{CODE}; | |
| if (our $CAN_HAZ_XS && $self->is_simple_get($name, $spec)) { | |
| $methods{$reader} = $self->_generate_xs( | |
| getters => $into, $reader, $name, $spec | |
| @@ -88,6 +96,8 @@ sub generate_method { | |
| } | |
| } | |
| if (my $accessor = $spec->{accessor}) { | |
| + _die_overwrite($into, $accessor, 'an accessor') | |
| + if !$spec->{allow_overwrite} && *{_getglob("${into}::${accessor}")}{CODE}; | |
| if ( | |
| our $CAN_HAZ_XS | |
| && $self->is_simple_get($name, $spec) | |
| @@ -106,6 +116,8 @@ sub generate_method { | |
| } | |
| } | |
| if (my $writer = $spec->{writer}) { | |
| + _die_overwrite($into, $writer, 'a writer') | |
| + if !$spec->{allow_overwrite} && *{_getglob("${into}::${writer}")}{CODE}; | |
| if ( | |
| our $CAN_HAZ_XS | |
| && $self->is_simple_set($name, $spec) | |
| @@ -123,6 +135,8 @@ sub generate_method { | |
| } | |
| } | |
| if (my $pred = $spec->{predicate}) { | |
| + _die_overwrite($into, $pred, 'a predicate') | |
| + if !$spec->{allow_overwrite} && *{_getglob("${into}::${pred}")}{CODE}; | |
| $methods{$pred} = | |
| quote_sub "${into}::${pred}" => | |
| ' '.$self->_generate_simple_has('$_[0]', $name, $spec)."\n" | |
| @@ -132,6 +146,8 @@ sub generate_method { | |
| _install_coderef( "${into}::$spec->{builder}" => $spec->{builder_sub} ); | |
| } | |
| if (my $cl = $spec->{clearer}) { | |
| + _die_overwrite($into, $cl, 'a clearer') | |
| + if !$spec->{allow_overwrite} && *{_getglob("${into}::${cl}")}{CODE}; | |
| $methods{$cl} = | |
| quote_sub "${into}::${cl}" => | |
| $self->_generate_simple_clear('$_[0]', $name, $spec)."\n" | |
| @@ -151,8 +167,10 @@ sub generate_method { | |
| die "You gave me a handles of ${hspec} and I have no idea why"; | |
| } | |
| }; | |
| - foreach my $spec (@specs) { | |
| - my ($proxy, $target, @args) = @$spec; | |
| + foreach my $delegation_spec (@specs) { | |
| + my ($proxy, $target, @args) = @$delegation_spec; | |
| + _die_overwrite($into, $proxy, 'a delegation') | |
| + if !$spec->{allow_overwrite} && *{_getglob("${into}::${proxy}")}{CODE}; | |
| $self->{captures} = {}; | |
| $methods{$proxy} = | |
| quote_sub "${into}::${proxy}" => | |
| diff --git a/t/accessor-handles.t b/t/accessor-handles.t | |
| index a0df36c..8063cca 100644 | |
| --- a/t/accessor-handles.t | |
| +++ b/t/accessor-handles.t | |
| @@ -62,4 +62,16 @@ is $bar->beep, 'beep', 'handles loads roles'; | |
| is $bar->eat_curry, 'Curry!', 'handles works for currying'; | |
| +{ | |
| + local $@; | |
| + ok !eval q{ | |
| + package Baz; | |
| + use Moo; | |
| + has foo => ( is => 'ro', handles => 'Robot' ); | |
| + sub smash { 1 }; | |
| + 1; | |
| + }, 'handles will not overwrite locally defined method'; | |
| + like $@, qr{You cannot overwrite a locally defined method \(smash\) with a delegation}; | |
| +} | |
| + | |
| done_testing; | |
| diff --git a/t/accessor-roles.t b/t/accessor-roles.t | |
| index eb8b8b6..d2ab470 100644 | |
| --- a/t/accessor-roles.t | |
| +++ b/t/accessor-roles.t | |
| @@ -1,5 +1,6 @@ | |
| use strictures 1; | |
| use Test::More; | |
| +use Test::Fatal; | |
| use Sub::Quote; | |
| { | |
| @@ -22,4 +23,20 @@ is $c->one, "one", "attr default set from class"; | |
| is $c->two, "two", "attr default set from role"; | |
| is $c->three, "three", "attr default set from role"; | |
| +{ | |
| + package Deux; use Moo; with 'One::P1'; | |
| + ::like( | |
| + ::exception { has two => (is => 'ro', default => sub { 'II' }); }, | |
| + qr{^You cannot overwrite a locally defined method \(two\) with a reader}, | |
| + 'overwriting accesssors with roles fails' | |
| + ); | |
| +} | |
| + | |
| +{ | |
| + package Two; use Moo; with 'One::P1'; | |
| + has '+two' => (is => 'ro', default => sub { 'II' }); | |
| +} | |
| + | |
| +is(Two->new->two, 'II', "overwriting accessors using +attr works"); | |
| + | |
| done_testing; | |
| diff --git a/t/method-generate-accessor.t b/t/method-generate-accessor.t | |
| index 64dbfee..f228729 100644 | |
| --- a/t/method-generate-accessor.t | |
| +++ b/t/method-generate-accessor.t | |
| @@ -34,37 +34,37 @@ like( | |
| for my $setting (qw( default coerce )) { | |
| like( | |
| - exception { $gen->generate_method('Foo' => 'four' => { is => 'ro', $setting => 5 }) }, | |
| + exception { $gen->generate_method('Foo' => 'four' => { allow_overwrite => 1, is => 'ro', $setting => 5 }) }, | |
| qr/Invalid $setting/, "$setting - scalar rejected" | |
| ); | |
| like( | |
| - exception { $gen->generate_method('Foo' => 'five' => { is => 'ro', $setting => [] }) }, | |
| + exception { $gen->generate_method('Foo' => 'five' => { allow_overwrite => 1, is => 'ro', $setting => [] }) }, | |
| qr/Invalid $setting/, "$setting - arrayref rejected" | |
| ); | |
| like( | |
| - exception { $gen->generate_method('Foo' => 'five' => { is => 'ro', $setting => Foo->new }) }, | |
| + exception { $gen->generate_method('Foo' => 'five' => { allow_overwrite => 1, is => 'ro', $setting => Foo->new }) }, | |
| qr/Invalid $setting/, "$setting - non-code-convertible object rejected" | |
| ); | |
| is( | |
| - exception { $gen->generate_method('Foo' => 'six' => { is => 'ro', $setting => sub { 5 } }) }, | |
| + exception { $gen->generate_method('Foo' => 'six' => { allow_overwrite => 1, is => 'ro', $setting => sub { 5 } }) }, | |
| undef, "$setting - coderef accepted" | |
| ); | |
| is( | |
| - exception { $gen->generate_method('Foo' => 'seven' => { is => 'ro', $setting => bless sub { 5 } => 'Blah' }) }, | |
| + exception { $gen->generate_method('Foo' => 'seven' => { allow_overwrite => 1, is => 'ro', $setting => bless sub { 5 } => 'Blah' }) }, | |
| undef, "$setting - blessed sub accepted" | |
| ); | |
| is( | |
| - exception { $gen->generate_method('Foo' => 'eight' => { is => 'ro', $setting => WithOverload->new }) }, | |
| + exception { $gen->generate_method('Foo' => 'eight' => { allow_overwrite => 1, is => 'ro', $setting => WithOverload->new }) }, | |
| undef, "$setting - object with overloaded ->() accepted" | |
| ); | |
| like( | |
| - exception { $gen->generate_method('Foo' => 'nine' => { is => 'ro', $setting => bless {} => 'Blah' }) }, | |
| + exception { $gen->generate_method('Foo' => 'nine' => { allow_overwrite => 1, is => 'ro', $setting => bless {} => 'Blah' }) }, | |
| qr/Invalid $setting/, "$setting - object rejected" | |
| ); | |
| } | |
| diff --git a/t/moo-accessors.t b/t/moo-accessors.t | |
| index 5bb6b49..ef2cd64 100644 | |
| --- a/t/moo-accessors.t | |
| +++ b/t/moo-accessors.t | |
| @@ -51,4 +51,4 @@ is_deeply( | |
| ok(eval { Foo->meta->make_immutable }, 'make_immutable returns true'); | |
| ok(!$INC{"Moose.pm"}, "Didn't load Moose"); | |
| -done_testing unless caller; | |
| +done_testing; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment