in reply to Is there a better way to do this?

Hi TorontoJim,

I would compose in my methods with roles. I use Moo and Moo::Role:

In MyClass.pm -

package MyClass; use Moo; with 'MyClass::Child'; sub foo { return 'foo'; } 1;
In MyClass/Child.pm -
package MyClass::Child; use Moo::Role; sub foo { die 'horribly'; } sub bar { return 'bar'; } 1;
In your script:
#!/usr/bin/perl use strict; use warnings; use feature 'say'; use MyClass; my $obj = MyClass->new; say $obj->foo; say $obj->bar; __END__
Output:
$ perl 1158279.pl foo bar

You could also use Role::Tiny directly, but with Moo you'll of course get access to the other sugar like not having to write a constructor, type-checking, etc.

If you have a whole bunch of roles and for some reason they are expensive to compile you can load them conditionally with with and eval, say based on arguments passed to the constructor call:

package MyClass; use Moo; sub BUILD { my ( $self, $args ) = @_; my %modules = ( 1 => 'MyClass::MyChild', 0 => 'Acme::Frobnicate', ); my $module = $modules{ $args->{'be_serious'} }; eval "with '$module'; 1;" or die $@; return $self; } sub foo { return 'foo'; } 1;

As far as whether you should be rethinking what you're doing, there's certainly no harm in reinventing a wheel as an academic exercise ... but I would look at the DateTime project (maybe especially DateTime.pm#How_DateTime_Math_Works), Date::Calc, even Time::Piece before I put too many CPU cycles into tackling date math. I'd also recommend against releasing any code under the Date::Math namespace, until you're very sure that it's at least as reliable as the aforementioned modules.

Hope this helps!


The way forward always starts with a minimal test.

Replies are listed 'Best First'.
Re^2: Is there a better way to do this?
by choroba (Cardinal) on Mar 19, 2016 at 09:46 UTC
    Instead of evaling a with, you can also apply_roles_to_package or apply_roles_to_object .
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Thanks choroba, I didn't know about those Role::Tiny methods.

      I am not sure about whether I prefer them to eval "with '$module'; 1;", though.

      I had to load Role::Tiny explicitly not importing anything, since its before(), after(), around() and with() methods clash with Moo's :

      Subroutine MyClass::before redefined at [...]/5.22.0/Role/Tiny.pm line + 58. Subroutine MyClass::after redefined at [...]/5.22.0/Role/Tiny.pm line +58. Subroutine MyClass::around redefined at [...]/5.22.0/Role/Tiny.pm line + 58. Subroutine MyClass::with redefined at [...]/5.22.0/Role/Tiny.pm line 6 +7.

      And even when I do that I can't use apply_roles_to_object() inside sub BUILD, because the parent's methods haven't been loaded and thus the child's will be.

      package MyClass::Child; use Moo::Role; sub foo { die 'horribly'; } sub bar { return 'bar'; } 1;
      package MyClass; use Moo; use Role::Tiny(); sub BUILD { my $self = shift; Role::Tiny->apply_roles_to_object( $self, 'MyClass::Child' ); return $self; }; sub foo { return 'foo'; } 1;
      Output:
      $ perl -MMyClass -E '$o = MyClass->new; say $o->foo, $o->bar;' horribly at MyClass/Child.pm line 5.

      So the only way I could make it work as part of the Moo constructor was with apply_roles_to_package() :

      package MyClass; use Moo; use Role::Tiny(); sub BUILD { my $self = shift; Role::Tiny->apply_roles_to_package( __PACKAGE__, 'MyClass::Child' +); return $self; }; sub foo { return 'foo'; } 1;
      Output:
      $ perl -MMyClass -E '$o = MyClass->new; say $o->foo, $o->bar;' foobar

      Thanks again for the pointer.


      The way forward always starts with a minimal test.
        Moo::Role is based on Role::Tiny. It means you can use
        'Moo::Role'->apply_roles_to_package(...);

        There's no need to use Role::Tiny from Moo.

        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re^2: Is there a better way to do this?
by TorontoJim (Beadle) on Mar 19, 2016 at 14:04 UTC
    Thank you for your responses. Yes, this is an academic exercise on my part, learning how to do this. I've written custom modules for years for proprietary implementations, but I've never written a parent/child scenario before. This is my attempt to learn it as date math is easy, it's the getting things to work how I want ... or changing how I want them to work ... that is the learning curve.