Dependency injection for Moose classes - perl

I have a Moose class that needs to send requests of type Foo::Request. I need to make this dependency accessible from the outside, so that I can easily exchange the request implementation in tests. I came up with the following attribute:
has request_builder => (
is => 'rw',
isa => 'CodeRef',
default => sub {
sub { Foo::Request->new(#_) }
}
);
And then in code:
my $self = shift;
my $request = $self->request_builder->(path => …);
And in tests:
my $tested_class = …;
my $request = Test::MockObject->new;
$request->mock(…);
$tested_class->request_builder(sub { $request });
Is there a more simple / more idiomatic solution?

How about applying a role dynamically in your tests with Moose::Util::apply_all_roles? I have been wanting to use this for a while, but haven't had an excuse yet. Here is how I think it would work.
First, modify your original attribute slightly:
package MyClientThing;
has request => (
is => 'rw',
isa => 'Foo::Request',
builder => '_build_request',
);
sub _build_request { Foo::Request->new };
....
Then create a Test::RequestBuilder role:
package Test::RequestBuilder;
use Moose::Role;
use Test::Foo::Request; # this module could inherit from Foo::Request I guess?
sub _build_request { return Test::Foo::Request->new };
Meanwhile in 't/my_client_thing.t' you would write something like this:
use MyClientThing;
use Moose::Util qw( apply_all_roles );
use Test::More;
my $client = MyClientThing->new;
apply_all_roles( $client, 'Test::RequestBuilder' );
isa_ok $client->request, 'Test::Foo::Request';
See Moose::Manual::Roles for more info.

My suggestion, following the model in chromatic's article (comment above by Mike), is this:
In your class:
has request => (
is => 'ro',
isa => 'CodeRef',
default => sub {
Foo::Request->new(#_)
}
);
In your test:
my $request = Test::MockObject->new;
$request->mock(…);
my $tested_class = MyClass->new(request => $request, ...);
Does exactly what your code does, with the following refinements:
make the attribute read-only and set it in the constructor, if possible, for better encapsulation.
your request attribute is a ready-to-use object; no need to dereference the sub ref

Consider this approach:
In your Moose class define an 'abstract' method called make_request. Then define two roles which implement make_request - one which calls Foo::Request->new and another one which calls Test::MockObject->new.
Example:
Your main class and the two roles:
package MainMooseClass;
use Moose;
...
# Note: this class requires a role that
# provides an implementation of 'make_request'
package MakeRequestWithFoo;
use Moose::Role;
use Foo::Request; # or require it
sub make_request { Foo::Request->new(...) }
package MakeRequestWithMock;
use Moose::Role;
use Test::MockRequest; # or require it
sub make_request { Test::MockRequest->new(...) }
If you want to test your main class, mix it with the 'MakeRequestWithMock' role:
package TestVersionOfMainMooseClass;
use Moose;
extends 'MainMooseClass';
with 'MakeRequestWithMock';
package main;
my $test_object = TestVersionOfMainMooseClass->new(...);
If you want to use it with the Foo implementation of 'make_request', mix it in with the 'MakeRequestWithFoo' role.
Some advantages:
You will only load in modules that you need. For instance, the class TestVersionOfMainMooseClass will not load the module Foo::Request.
You can add data that is relevant/required by your implementation of make_request as instance members of your new class. For example, your original approach of using a CODEREF can be implemented with this role:
package MakeRequestWithCodeRef;
use Moose::Role;
has request_builder => (
is => 'rw',
isa => 'CodeRef',
required => 1,
);
sub make_request { my $self = shift; $self->request_builder->(#_) };
To use this class you need to supply an initializer for request_builder, e.g.:
package Example;
use Moose;
extends 'MainMooseClass';
with 'MakeRequestWithCodeRef';
package main;
my $object = Example->new(request_builder => sub { ... });
As a final consideration, the roles you write might be usable with other classes.

I know this post is a little old, but for anyone referring to this question now the requester could use a framework like Bread::Board.

Related

Perl share variables with subclasses

I know this may be a very simple topic but I am trying to get the best logic since I am still new to Perl.
If I do not use OO and just split the code into files, all global variables are accessed among all files.
I am trying to do the same but using OO style. Example is I want a base class say called "BaseSub" that has a hash containing the configuration for the application say called %Config. Now I have a sub class called "DB" for the database connection and I want to access the settings from %Config which lives in "BaseSub" package. How do I do that.
If you're writing OO perl in this day and age, you really should be using Moose. It makes OO code much easier, cleaner and smaller.
The proper way to inherit variables is to make object attributes. Here's a quick example:
package MyBaseClass;
use Moose;
has config => (
is => 'ro',
default => sub { {
who => 'World',
} }
);
package MyClass;
use Moose;
extends qw(MyBaseClass);
sub greet
{
my $self = shift;
printf("Hello %s!\n", $self->config->{who});
}
package main;
my $object = MyClass->new();
$object->greet();
A great starting point for learning about Moose is the Moose::Manual.
Edit:
If you want be able to modify the config, you can either just poke the hashref returned from the config accessor directly:
$object->config->{who} = 'Friends';
But a better approach might be to make a config class and make the config attribute hold an instance of that:
package Myconfig;
use Moose;
has who => (is => 'rw', default => 'World');
package MyBaseClass;
use Moose;
has config => (
is => 'ro',
isa => 'MyConfig',
default => sub { MyConfig->new },
);
# inherit, instantiate, etc as before...
$object->config->who('Friends');
Another approach could be Moose::Meta::Attribute::Native::Trait::Hash which makes it easy to setup helper methods to work with native Perl datatypes.
Use its full name.
for (keys(%BaseSub::Config)) {
print("$_: $BaseSub::Config{$_}\n");
}
You could also import it.
our %Config; *Config = \%BaseSub::Config;
for (keys(%Config)) {
print("$_: $Config{$_}\n");
}

Moose Role Derivation

I would like to now what is the better pattern to do what I need. I try to reduce the problem to a minimum, let me explain it step by step.
I have an interface Role like:
{
package Likeable;
use Moose::Role;
requires 'likers';
requires 'do_like';
}
After this, I need 2 Abstract Roles that semi-implement the previous interface (in this case they implement all):
{
package Likeable::OnSelf;
use Moose::Role;
with 'Likeable';
has 'likers' => ( is => 'rw', isa => 'ArrayRef' );
sub do_like { }
}
{
package Likeable::OnParent;
use Moose::Role;
with 'Likeable';
requires 'parent';
sub likers { shift->parent->likers(#_) }
sub do_like { shift->parent->do_like(#_) }
}
and later I need this code to compile
{
package OBJ::OnSelf;
use Moose;
with 'Likeable::OnSelf';
}
{
package OBJ::OnParent;
use Moose;
with 'Likeable::OnParent';
has 'parent' => ( is => 'rw', isa => 'Obj' );
}
foreach my $obj (OBJ::OnSelf->new, OBJ::OnParent->new(parent => OBJ::OnSelf->new)) {
if ( $obj->does('Likeable') ) {
$obj->do_like
}
}
The problem seems to me that is that I'm trying to do derivation on the Moose::Role, but I have no ideia how to solve the problem correctly.
May I have your suggestions?
There's no problem really with your overall role composition, but I assume you are getting an error like this:
'Likeable::OnParent' requires the method 'parent' to be implemented by 'OBJ::OnParent' at .../Moose/Meta/Role/Application.pm line 51
The problem is that has is called to create the attribute accesssor method after with is called to check for the method. (These are just subroutines being called, not actual language constructs.)
There are couple good solutions I know of. I prefer this one:
package OBJ::OnParent;
use Moose;
has 'parent' => ( is => 'rw', isa => 'Obj' );
with 'Likeable::OnParent';
Do your with statement after the attribute(s) are defined. The other option I know of is this:
package OBJ::OnParent;
use Moose;
with 'Likeable::OnParent';
BEGIN {
has 'parent' => ( is => 'rw', isa => 'Obj' );
}
By placing your has calls in a BEGIN block, the attributes are added to the package just after use Moose is run and before with. I don't like sticking in BEGIN blocks like this, but that's mostly a personal preference.
In this particular case, though, I might suggest just changing Likeable::OnParent to such that you better specify that the parent method returns a Likeable, which will also bypass the need to change your object definitions:
package Likeable::OnParent;
use Moose::Role;
with 'Likeable';
has parent => (
is => 'rw',
does => 'Likeable',
required => 1,
);
sub likers { shift->parent->likers(#_) }
sub do_like { shift->parent->do_like(#_) }
This way you have confidence that your calls to likers and do_like will succeed because the attribute must be set and it must implement the role that requires those methods and the documented contract.

Perl / Moose - How can I dynamically choose a specific implementation of a method?

I've written a simple Moose based class called Document. This class has two attributes: name and homepage.
The class also needs to provide a method called do_something() which retrieves and returns text from different sources (like a website or different databases) based on the homepage attribute.
Since there will be a lot of totally different implementations for do_something(), I'd like to have them in different packages/classes and each of these classes should know if it is responsible for the homepage attribute or if it isn't.
My approach so far involves two roles:
package Role::Fetcher;
use Moose::Role;
requires 'do_something';
has url => (
is => 'ro',
isa => 'Str'
);
package Role::Implementation;
use Moose::Role;
with 'Role::Fetcher';
requires 'responsible';
A class called Document::Fetcher which provides a default implmenentation for do_something() and commonly used methods (like a HTTP GET request):
package Document::Fetcher;
use Moose;
use LWP::UserAgent;
with 'Role::Fetcher';
has ua => (
is => 'ro',
isa => 'Object',
required => 1,
default => sub { LWP::UserAgent->new }
);
sub do_something {'called from default implementation'}
sub get {
my $r = shift->ua->get(shift);
return $r->content if $r->is_success;
# ...
}
And specific implementations which determine their responsibility via a method called responsible():
package Document::Fetcher::ImplA;
use Moose;
extends 'Document::Fetcher';
with 'Role::Implementation';
sub do_something {'called from implementation A'}
sub responsible { return 1 if shift->url =~ m#foo#; }
package Document::Fetcher::ImplB;
use Moose;
extends 'Document::Fetcher';
with 'Role::Implementation';
sub do_something {'called from implementation B'}
sub responsible { return 1 if shift->url =~ m#bar#; }
My Document class looks like this:
package Document;
use Moose;
has [qw/name homepage/] => (
is => 'rw',
isa => 'Str'
);
has fetcher => (
is => 'ro',
isa => 'Document::Fetcher',
required => 1,
lazy => 1,
builder => '_build_fetcher',
handles => [qw/do_something/]
);
sub _build_fetcher {
my $self = shift;
my #implementations = qw/ImplA ImplB/;
foreach my $i (#implementations) {
my $fetcher = "Document::Fetcher::$i"->new(url => $self->homepage);
return $fetcher if $fetcher->responsible();
}
return Document::Fetcher->new(url => $self->homepage);
}
Right now this works as it should. If I call the following code:
foreach my $i (qw/foo bar baz/) {
my $doc = Document->new(name => $i, homepage => "http://$i.tld/");
say $doc->name . ": " . $doc->do_something;
}
I get the expected output:
foo: called from implementation A
bar: called from implementation B
baz: called from default implementation
But there are at least two issues with this code:
I need to keep a list of all known implementations in _build_fetcher. I'd prefer a way where the code would automatically choose from every loaded module/class beneath the namespace Document::Fetcher::. Or maybe there's a better way to "register" these kind of plugins?
At the moment the whole code looks a bit too bloated. I am sure people have written this kind of plugin system before. Isn't there something in MooseX which provides the desired behaviour?
What you're looking for is a Factory, specifically an Abstract Factory. The constructor for your Factory class would determine which implementation to return based on its arguments.
# Returns Document::Fetcher::ImplA or Document::Fetcher::ImplB or ...
my $fetcher = Document::Fetcher::Factory->new( url => $url );
The logic in _build_fetcher would go into Document::Fetcher::Factory->new. This separates the Fetchers from your Documents. Instead of Document knowing how to figure out which Fetcher implementation it needs, Fetchers can do that themselves.
Your basic pattern of having the Fetcher role able to inform the Factory if its able to deal with it is good if your priority is to allow people to add new Fetchers without having to alter the Factory. On the down side, the Fetcher::Factory cannot know that multiple Fetchers might be valid for a given URL and that one might be better than the other.
To avoid having a big list of Fetcher implementations hard coded in your Fetcher::Factory, have each Fetcher role register itself with the Fetcher::Factory when its loaded.
my %Registered_Classes;
sub register_class {
my $class = shift;
my $registeree = shift;
$Registered_Classes{$registeree}++;
return;
}
sub registered_classes {
return \%Registered_Classes;
}
You can have something, probably Document, pre-load a bunch of common Fetchers if you want your cake and eat it too.

Use a single module and get Moose plus several MooseX extensions

Let's say I have a codebase with a bunch of Moose-based classes and I want them all to use a common set of MooseX::* extension modules. But I don't want each Moose-based class to have to start like this:
package My::Class;
use Moose;
use MooseX::Aliases;
use MooseX::HasDefaults::RO;
use MooseX::StrictConstructor;
...
Instead, I want each class to begin like this:
package MyClass;
use My::Moose;
and have it be exactly equivalent to the above.
My first attempt at implementing this was based on the approach used by Mason::Moose (source):
package My::Moose;
use Moose;
use Moose::Exporter;
use MooseX::Aliases();
use MooseX::StrictConstructor();
use MooseX::HasDefaults::RO();
use Moose::Util::MetaRole;
Moose::Exporter->setup_import_methods(also => [ 'Moose' ]);
sub init_meta {
my $class = shift;
my %params = #_;
my $for_class = $params{for_class};
Moose->init_meta(#_);
MooseX::Aliases->init_meta(#_);
MooseX::StrictConstructor->init_meta(#_);
MooseX::HasDefaults::RO->init_meta(#_);
return $for_class->meta();
}
But this approach is not recommended by the folks in the #moose IRC channel on irc.perl.org, and it doesn't always work, depending on the mix of MooseX::* modules. For example, trying to use the My::Moose class above to make My::Class like this:
package My::Class;
use My::Moose;
has foo => (isa => 'Str');
Results in the following error when the class is loaded:
Attribute (foo) of class My::Class has no associated methods (did you mean to provide an "is" argument?)
at /usr/local/lib/perl5/site_perl/5.12.1/darwin-2level/Moose/Meta/Attribute.pm line 1020.
Moose::Meta::Attribute::_check_associated_methods('Moose::Meta::Class::__ANON__::SERIAL::2=HASH(0x100bd6f00)') called at /usr/local/lib/perl5/site_perl/5.12.1/darwin-2level/Moose/Meta/Class.pm line 573
Moose::Meta::Class::add_attribute('Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x100be2f10)', 'foo', 'isa', 'Str', 'definition_context', 'HASH(0x100bd2eb8)') called at /usr/local/lib/perl5/site_perl/5.12.1/darwin-2level/Moose.pm line 79
Moose::has('Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x100be2f10)', 'foo', 'isa', 'Str') called at /usr/local/lib/perl5/site_perl/5.12.1/darwin-2level/Moose/Exporter.pm line 370
Moose::has('foo', 'isa', 'Str') called at lib/My/Class.pm line 5
require My/Class.pm called at t.pl line 1
main::BEGIN() called at lib/My/Class.pm line 0
eval {...} called at lib/My/Class.pm line 0
The MooseX::HasDefaults::RO should be preventing this error, but it's apparently not being called upon to do its job. Commenting out the MooseX::Aliases->init_meta(#_); line "fixes" the problem, but a) that's one of the modules I want to use, and b) that just further emphasizes the wrongness of this solution. (In particular, init_meta() should only be called once.)
So, I'm open to suggestions, totally ignoring my failed attempt to implement this. Any strategy is welcome as long as if gives the results described at the start of this question.
Based on #Ether's answer, I now have the following (which also doesn't work):
package My::Moose;
use Moose();
use Moose::Exporter;
use MooseX::Aliases();
use MooseX::StrictConstructor();
use MooseX::HasDefaults::RO();
my %class_metaroles = (
class => [
'MooseX::StrictConstructor::Trait::Class',
],
attribute => [
'MooseX::Aliases::Meta::Trait::Attribute',
'MooseX::HasDefaults::Meta::IsRO',
],
);
my %role_metaroles = (
role =>
[ 'MooseX::Aliases::Meta::Trait::Role' ],
application_to_class =>
[ 'MooseX::Aliases::Meta::Trait::Role::ApplicationToClass' ],
application_to_role =>
[ 'MooseX::Aliases::Meta::Trait::Role::ApplicationToRole' ],
);
if (Moose->VERSION >= 1.9900) {
push(#{$class_metaroles{class}},
'MooseX::Aliases::Meta::Trait::Class');
push(#{$role_metaroles{applied_attribute}},
'MooseX::Aliases::Meta::Trait::Attribute',
'MooseX::HasDefaults::Meta::IsRO');
}
else {
push(#{$class_metaroles{constructor}},
'MooseX::StrictConstructor::Trait::Method::Constructor',
'MooseX::Aliases::Meta::Trait::Constructor');
}
*alias = \&MooseX::Aliases::alias;
Moose::Exporter->setup_import_methods(
also => [ 'Moose' ],
with_meta => ['alias'],
class_metaroles => \%class_metaroles,
role_metaroles => \%role_metaroles,
);
With a sample class like this:
package My::Class;
use My::Moose;
has foo => (isa => 'Str');
I get this error:
Attribute (foo) of class My::Class has no associated methods (did you mean to provide an "is" argument?) at ...
With a sample class like this:
package My::Class;
use My::Moose;
has foo => (isa => 'Str', alias => 'bar');
I get this error:
Found unknown argument(s) passed to 'foo' attribute constructor in 'Moose::Meta::Attribute': alias at ...
I might get raked over the coals for this, but when in doubt, lie :)
package MyMoose;
use strict;
use warnings;
use Carp 'confess';
sub import {
my $caller = caller;
eval <<"END" or confess("Loading MyMoose failed: $#");
package $caller;
use Moose;
use MooseX::StrictConstructor;
use MooseX::FollowPBP;
1;
END
}
1;
By doing that, you're evaling the use statements into the calling package. In other words, you're lying to them about what class they are used in.
And here you declare your person:
package MyPerson;
use MyMoose;
has first_name => ( is => 'ro', required => 1 );
has last_name => ( is => 'rw', required => 1 );
1;
And tests!
use lib 'lib';
use MyPerson;
use Test::Most;
throws_ok { MyPerson->new( first_name => 'Bob' ) }
qr/\QAttribute (last_name) is required/,
'Required attributes should be required';
throws_ok {
MyPerson->new(
first_name => 'Billy',
last_name => 'Bob',
what => '?',
);
}
qr/\Qunknown attribute(s) init_arg passed to the constructor: what/,
'... and unknown keys should throw an error';
my $person;
lives_ok { $person = MyPerson->new( first_name => 'Billy', last_name => 'Bob' ) }
'Calling the constructor with valid arguments should succeed';
isa_ok $person, 'MyPerson';
can_ok $person, qw/get_first_name get_last_name set_last_name/;
ok !$person->can("set_first_name"),
'... but we should not be able to set the first name';
done_testing;
And the test results:
ok 1 - Required attributes should be required
ok 2 - ... and unknown keys should throw an error
ok 3 - Calling the constructor with valid arguments should succeed
ok 4 - The object isa MyPerson
ok 5 - MyPerson->can(...)
ok 6 - ... but we should not be able to set the first name
1..6
Let's keep this our little secret, shall we? :)
As discussed, you shouldn't be calling other extensions' init_meta methods directly. Instead, you should essentially inline those extensions' init_meta methods: combine what all those methods do, into your own init_meta. This is fragile because now you are tying your module to other modules' innards, which are subject to change at any time.
e.g. to combine MooseX::HasDefaults::IsRO, MooseX::StrictConstructor and MooseX::Aliases, you'd do something like this (warning: untested) (now tested!):
package Mooseish;
use Moose ();
use Moose::Exporter;
use MooseX::StrictConstructor ();
use MooseX::Aliases ();
my %class_metaroles = (
class => ['MooseX::StrictConstructor::Trait::Class'],
attribute => [
'MooseX::Aliases::Meta::Trait::Attribute',
'MooseX::HasDefaults::Meta::IsRO',
],
);
my %role_metaroles = (
role =>
['MooseX::Aliases::Meta::Trait::Role'],
application_to_class =>
['MooseX::Aliases::Meta::Trait::Role::ApplicationToClass'],
application_to_role =>
['MooseX::Aliases::Meta::Trait::Role::ApplicationToRole'],
);
if (Moose->VERSION >= 1.9900) {
push #{$class_metaroles{class}}, 'MooseX::Aliases::Meta::Trait::Class';
push #{$role_metaroles{applied_attribute}}, 'MooseX::Aliases::Meta::Trait::Attribute';
}
else {
push #{$class_metaroles{constructor}},
'MooseX::StrictConstructor::Trait::Method::Constructor',
'MooseX::Aliases::Meta::Trait::Constructor';
}
*alias = \&MooseX::Aliases::alias;
Moose::Exporter->setup_import_methods(
also => ['Moose'],
with_meta => ['alias'],
class_metaroles => \%class_metaroles,
role_metaroles => \%role_metaroles,
);
1;
This can be tested with this class and tests:
package MyObject;
use Mooseish;
sub foo { 1 }
has this => (
isa => 'Str',
alias => 'that',
);
1;
use strict;
use warnings;
use MyObject;
use Test::More;
use Test::Fatal;
like(
exception { MyObject->new(does_not_exist => 1) },
qr/unknown attribute.*does_not_exist/,
'strict constructor behaviour is present',
);
can_ok('MyObject', qw(alias this that has with foo));
my $obj = MyObject->new(this => 'thing');
is($obj->that, 'thing', 'can access attribute by its aliased name');
like(
exception { $obj->this('new value') },
qr/Cannot assign a value to a read-only accessor/,
'attribute defaults to read-only',
);
done_testing;
Which prints:
ok 1 - strict constructor behaviour is present
ok 2 - MyObject->can(...)
ok 3 - can access attribute by its aliased name
ok 4 - attribute defaults to read-only
1..4
So long as the MooseX you want to use are all well-behaved and use Moose::Exporter, you can use Moose::Exporter to create a package that will behave like Moose for you:
package MyMoose;
use strict;
use warnings;
use Moose::Exporter;
use MooseX::One ();
use MooseX::Two ();
Moose::Exporter->setup_import_methods(
also => [ qw{ Moose MooseX::One MooseX::Two } ],
);
1;
Note that in also we're using the name of the package that the Moose extension using Moose::Exporter (generally the main package from the extension), and NOT using any of the trait application bits. Moose::Exporter handles that all behind the scenes.
The advantage here? Everything works as expected, all sugar from Moose and extensions is installed and can be removed via 'no MyMoose;'.
I should point out here that some extensions do not play well with others, usually due to their not anticipating that they'll be required to coexist in harmony with others. Luckily, these are becoming increasingly uncommon.
For a larger scale example, check out Reindeer on the CPAN, which collects several extensions and integrates them together in a coherent, consistent fashion.

programmatically creating a Moose class at run time

I've been playing around with this code:
package Foo;
use Moose;
package main;
my $PACKAGE = "Foo";
{
no strict 'refs';
my $has = *{"${PACKAGE}::has"}{CODE};
my $with = *{"${PACKAGE}::with"}{CODE};
# Add a instance member to class $PACKAGE
$has->("bar", is => "rw", required => 1);
# Add a role to class $PACKAGE
$with->("some::role");
}
# Create an instance of $PACKAGE:
$PACKAGE->new(); # error: attribute 'bar' is required means we were successful
This allows me to create a Moose class at run-time, i.e. add instance members to a class, add roles, etc.
My question is: how can I import Moose into package $PACKAGE?
I know I can do this with eval: eval "package $PACKAGE; use Moose"; but I'm wondering if there is a solution along the lines of Moose->import(... $PACKAGE ...).
i.e., a way without using eval. Or is there a completely different way of creating and modifying Moose classes at run time?
You probably want to take a look at Moose::Meta::Class and its create method:
my $class = Moose::Meta::Class->create('Foo',
attributes => [attr => Moose::Meta::Attribute->new(is => 'ro'), ...],
roles => [...],
methods => {...},
superclasses => [...],
);
# Edit: Adding an attribute and method modifiers:
$class->add_attribute(otherattr => (is => 'ro'));
$class->add_around_method_modifier(methodname => sub { ... });
Moose::Meta::Class is a subclass of Class::MOP::Class, so you might want to peek into that one as well. With the above, you can specify roles, superclasses, attributes and methods, or you can first create and then add them via the MOP; whatever fits best.
For the attributes you'll want the Moose kind, which means Moose::Meta::Attribute objects. The constructor to that object is basically the same as using has.
You may want to use Class::MOP, see for example https://metacpan.org/module/Moose::Manual::MOP#ALTERING-CLASSES-WITH-THE-MOP
or
https://metacpan.org/module/Class::MOP::Class#SYNOPSIS
Call extends, with, has, before, after, around, override and augment in the Moose package instead of the ones exported by Moose, and pass the meta object of the class you are creating as an additional first argument.
use strict;
use warnings;
use feature qw( say );
use Moose qw( );
{ # Create MyClass on the fly.
my $meta = Moose->init_meta( for_class => 'MyClass' );
# Moose::with( $meta, 'MyRole' );
Moose::has( $meta, foo => (
is => 'ro',
));
}
say MyClass->new( foo => "Foo" )->foo; # Foo