Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re^2: Two Moose classes consumering the same role and using each other

by v_melnik (Scribe)
on Jun 26, 2014 at 12:42 UTC ( [id://1091353]=note: print w/replies, xml ) Need Help??


in reply to Re: Two Moose classes consumering the same role and using each other
in thread Two Moose classes consumering the same role and using each other

No, problem, I'll add some actual code.

Here is the role:

package MonkeyMan::CloudStack::Element; use strict; use warnings; use Moose::Role; use namespace::autoclean; with 'MonkeyMan::ErrorHandling'; # ^^^ by the way, the role consumes one more role, but it doesn't gene +rate any warnings # <...> sub find_related_to_me { # <...> my $quasi_object = eval { require "MonkeyMan//CloudStack//Elements//$module_name.pm"; return("MonkeyMan::CloudStack::Elements::$module_name"->new(m +m => $mm)); }; # <...> } # <...> 1;

And here goest our "ClassA":

package MonkeyMan::CloudStack::Elements::Domain; use strict; use warnings; use MonkeyMan::Constants; use Moose; use MooseX::UndefTolerant; use namespace::autoclean; with 'MonkeyMan::CloudStack::Element'; sub element_type { # <...> } sub _load_full_list_command { # <...> } sub _generate_xpath_query { # <...> } 1;

ClassB looks almost the same way:

package MonkeyMan::CloudStack::Elements::VirtualMachine; use strict; use warnings; use MonkeyMan::Constants; use Moose; use MooseX::UndefTolerant; use namespace::autoclean; with 'MonkeyMan::CloudStack::Element'; sub element_type { # <...> } sub _load_full_list_command { # <...> } sub _generate_xpath_query { # <...> } 1;

Yes, ClassA and ClassB are quite short and quite similar, the differences are only in a couple of lines, because all their logic is coded in the Element role. Then my main module calls ClassA->find_related_to_me(...) and it needs to create a ClassB object for doing some tricks. The object is being created, everything works fine, but here are some warnings:

Subroutine element_type redefined at /opt/monkeyman-0.2.x/bin/../lib/M +onkeyMan//CloudStack//Elements//VirtualMachine.pm line 17. Subroutine _load_full_list_command redefined at /opt/monkeyman-0.2.x/b +in/../lib/MonkeyMan//CloudStack//Elements//VirtualMachine.pm line 23. Subroutine _generate_xpath_query redefined at /opt/monkeyman-0.2.x/bin +/../lib/MonkeyMan//CloudStack//Elements//VirtualMachine.pm line 30.

So it doesn't like that I defined element_type(), _load_full_list_command() and _generate_xpath_query() in MonkeyMan::CloudStack::Elements::Domain and then I require MonkeyMan::CloudStack::Elements::VirtualMachine where the same methods are defined as well.

I'm pretty sure that my case isn't too "exotic" and many Perl developers are facing with the necessity of using "sibling" classes consuming the same role.

Thank you!

V.Melnik

Replies are listed 'Best First'.
Re^3: Two Moose classes consumering the same role and using each other
by tobyink (Canon) on Jun 26, 2014 at 22:34 UTC

    I think this is nothing to do with Moose. I think you're loading VirtualMachine.pm twice. Normally require uses %INC to avoid doing that, but the second time you're loading it as ""MonkeyMan//CloudStack//Elements//VirtualMachine.pm" with those strange doubled slashes, so require sees it as a different file name and loads it again.

    You have warnings enabled, so you get a warning about the subs being redefined in the MonkeyMan::CloudStack::Elements::VirtualMachine package. This is because the first time VirtualMachine.pm is loaded, the subs get defined, and the second time it's loaded, they get redefined. (Redefined to the same definition, but redefined all the same!)

    If you want to check to see if I'm right, do this in your role:

    use Data::Dumper (); END { print Data::Dumper::Dumper(\%INC); }

    ... then run your script. When it exits you should get a big dump of all the modules that Perl loaded. VirtualMachine.pm will be in there twice with slightly differing paths.

    I'd combat this problem by getting rid of this:

    my $quasi_object = eval { require "MonkeyMan//CloudStack//Elements//$module_name.pm"; return("MonkeyMan::CloudStack::Elements::$module_name"->new(m +m => $mm)); };

    And replacing it with something cleaner like this:

    use Try::Tiny; use Module::Runtime qw(use_module); my $quasi_object = try { my $class = "MonkeyMan::CloudStack::Elements::$module_name"; use_module($class)->new( mm => $mm ); };

    You won't be adding any extra dependencies because Moose already uses Try::Tiny and Module::Runtime internally!

      Thank you!

      I've got rid of warnings by deleting additional slashes (I added them just for "visual rhyme" of code).

      And also warnings disappear when I add "make_immutable" (it's strongly recommended, as I understand) in the end of ClassA and ClassB packages.

      I'll definitely try Try::Tiny instead of eval, thanks a lot.

      V.Melnik

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1091353]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2024-04-24 21:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found