Subject: | Make Moo::import easier to develop loosely coupled applications and add extensions |
Hi,
For my projects, I'd like to define a MyProject::Class module and MyProject::Object module as base object that projects modules use in place of Moo and Moo::Object, respectively.
I would like to make MyProject::Class will behave exactly like Moo. A project class that uses MyProject::Class will have all the Moo utils imported and in addition will extend MyProject::Object, which in turn inherits Moo::Object. Likewise, there is also MyProject::Role. This way, I will be able to add OO extensions specific to my projects, also have better control on future feature changes, and even switch OO systems with minimal impact on my project.
However, the current Moo::import (1.003001) makes it harder to do this as it relies on caller() returns the calling package to make it a Moo class. I have been trying to use Sub::Uplevel to fool caller() to return my $target correctly in Moo::import, two levels up instead of one. But it seems to break somewhere if I have other Moo classes loaded before MyProject's Moo classes.
My proposed change below will help me do this. At the same time, Feel free to bring in other solutions for discussions or implementation if this change is considered worth doing.
I propose that Moo::import take an optional argument the package. For instance,
package Moo;
sub import {
my $class = shift;
my $target = shift || caller;
...
}
With this change, I can write MyProject::Class as follows:
package MyProject::Class;
require Moo;
sub import {
my $class = shift;
my $target = shift || caller;
my $extends = "$target\::extends";
# Let Moo do its magic
Moo->import($target);
# Make all other objects to extend MyProject:Object
$extends->('MyProject::Object') unless $target eq 'MyProject::Object';
}
My project Moo classes can be defined as follows:
package MyProject::Work::Item;
use MyProject::Class; #
extends 'MyProject::Work';
has ... ...;
1;
Many thanks,
mytram