From: Peter Rabbitson Date: Tue, 14 Jun 2016 16:05:51 +0000 (+0200) Subject: Fix describe_class_methods on non-mergeable DFS mro X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits%2FDBIx-Class.git;a=commitdiff_plain;h=085dbdd69f2b8c80e32698fc6b7e918addaf7fc9 Fix describe_class_methods on non-mergeable DFS mro Instead of trying to deduplicate - simply track which methods are locally defined, and use that info combined with a reverse ISA-per-select-MRO to build the final stack. As a result the code is even more efficient and can now deal with real-life insane hierarchies like: https://metacpan.org/source/MJFLICK/DBIx-Class-Bootstrap-Simple-0.03/lib/DBIx/Class/Bootstrap/Simple.pm#L93 --- diff --git a/lib/DBIx/Class/_Util.pm b/lib/DBIx/Class/_Util.pm index 371db28..35d11df 100644 --- a/lib/DBIx/Class/_Util.pm +++ b/lib/DBIx/Class/_Util.pm @@ -699,15 +699,15 @@ sub modver_gt_or_eq_and_lt ($$$) { and - # on complex MI herarchies the method can be anywhere in the - # shadow stack - look through the entire slot, not just [0] - ( ! grep { - refaddr($_) == $current_node_refaddr - } @{ $slot->{methods}{ $_->{name} } || [] } ) + unshift @{ $slot->{methods}{$_->{name}} }, $_ and - unshift @{ $slot->{methods}{$_->{name}} }, $_ + ( + $_->{via_class} ne $class + or + $slot->{methods_defined_in_class}{$_->{name}} = $_ + ) and @@ -720,9 +720,9 @@ sub modver_gt_or_eq_and_lt ($$$) { ) for ( # what describe_class_methods for @my_ISA produced above - ( map { $_->[0] } map { - values %{ $describe_class_query_cache->{$_}{methods} } - } reverse @my_ISA ), + ( map { values %{ + $describe_class_query_cache->{$_}{methods_defined_in_class} || {} + } } reverse @my_ISA ), # our own non-cleaned subs + their attributes ( map { diff --git a/xt/extra/internals/attributes.t b/xt/extra/internals/attributes.t index b26f5d5..bed8efd 100644 --- a/xt/extra/internals/attributes.t +++ b/xt/extra/internals/attributes.t @@ -390,6 +390,9 @@ sub add_more_attrs { $expected_desc->{methods_with_supers}{VALID_DBIC_CODE_ATTRIBUTE} = $expected_desc->{methods}{VALID_DBIC_CODE_ATTRIBUTE}; + $expected_desc->{methods_defined_in_class}{attr} + = $expected_desc->{methods}{attr}[0]; + is_deeply ( describe_class_methods("DBICTest::AttrTest"), $expected_desc, @@ -441,4 +444,27 @@ else { SKIP: { ); }} +# this doesn't really belong in this test, but screw it +{ + package DBICTest::WackyDFS; + use base qw( DBICTest::SomeGrandParentClass DBICTest::SomeParentClass ); +} + +is_deeply + describe_class_methods("DBICTest::WackyDFS")->{methods}{VALID_DBIC_CODE_ATTRIBUTE}, + [ + { + attributes => {}, + name => "VALID_DBIC_CODE_ATTRIBUTE", + via_class => "DBICTest::SomeGrandParentClass", + }, + { + attributes => {}, + name => "VALID_DBIC_CODE_ATTRIBUTE", + via_class => "DBIx::Class::MethodAttributes" + }, + ], + 'Expected description on unusable inheritance hierarchy' +; + done_testing;