How can I make all lazy Moose features be built? - perl

I have a bunch of lazy features in a Moose object.
Some of the builders require some time to finish.
I would like to nvoke all the builders (the dump the "bomplete" object).
Can I make all the lazy features be built at once, or must I call each feature manually to cause it builder to run?

If you want to have "lazy" attributes with builders, but ensure that their values are constructed before new returns, the usual thing to do is to call the accessors in BUILD.
sub BUILD {
my ($self) = #_;
$self->foo;
$self->bar;
}
is enough to get the job done, but it's probably best to add a comment as well explaining this apparently useless code to someone who doesn't know the idiom.

Maybe you could use the meta class to get list of 'lazy' attributes. For example:
package Test;
use Moose;
has ['attr1', 'attr2'] => ( is => 'rw', lazy_build => 1);
has ['attr3', 'attr4'] => ( is => 'rw',);
sub BUILD {
my $self = shift;
my $meta = $self->meta;
foreach my $attribute_name ( sort $meta->get_attribute_list ) {
my $attribute = $meta->get_attribute($attribute_name);
if ( $attribute->has_builder ) {
my $code = $self->can($attribute_name);
$self->$code;
}
}
}
sub _build_attr1 { 1 }
sub _build_attr2 { 1 }

I've had this exact requirement several times in the past, and today I actually had to do it from the metaclass, which meant no BUILD tweaking allowed. Anyway I felt it would be good to share since it basically does exactly what ether mentioned:
'It would allow marking attributes "this is lazy, because it depends
on other attribute values to be built, but I want it to be poked
before construction finishes."'
However, derp derp I have no idea how to make a CPAN module so here's some codes:
https://gist.github.com/TiMBuS/5787018
Put the above into Late.pm and then you can use it like so:
package Thing;
use Moose;
use Late;
has 'foo' => (
is => 'ro',
default => sub {print "setting foo to 10\n"; 10},
);
has 'bar' => (
is => 'ro',
default => sub {print 'late bar being set to ', $_[0]->foo*2, "\n"; $_[0]->foo*2},
late => 1,
);
#If you want..
__PACKAGE__->meta->make_immutable;
1;
package main;
Thing->new();
#`bar` will be initialized to 20 right now, and always after `foo`.
#You can even set `foo` to 'lazy' or 'late' and it will still work.

Related

Moose's attribute vs simple sub?

How to decide - what is the recommended way for the next code fragment?
I have a Moose-based module, where some data is a simple HashRef.
It is possible to write - as a Mooseish HashRef, like:
package Some;
has 'data' => (
isa => 'HashRef',
builder => '_build_href',
init_arg => undef,
lazy => 1,
);
sub _build-href {
my $href;
$href = { a=>'a', b=>'b'}; #some code what builds a href
return $href;
}
vs
sub data {
my $href;
$href = { a=>'a', b=>'b'}; #some code what builds a href
return $href;
}
What is the difference? I'm asking because when calling:
my $obj = Some->new;
my $href = $obj->data;
In both case I get a correct HashRef. So when is it recommended to use a Moose-ish has construction (which is longer) vs a simple data sub?
PS: probably this question is so simple for an average perl programmer, but please, keep in mind, I'm still only learning perl.
If you have an attribute, then whoever is constructing the object can set the hashref in the constructor:
my $obj = Some->new(data => { a => 'c', b => 'd' });
(Though in your example, you've used init_arg => undef which would disable that ability.)
Also, in the case of the attribute, the builder is only run once per object while with a standard method, the method might be called multiple times. If building the hashref is "expensive", that may be an important concern.
Another difference you'll notice is with this:
use Data::Dumper;
my $obj = Some->new;
$obj->data->{c} = 123;
print Dumper( $obj->data );

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.

How can I create internal (private) Moose object variables (attributes)?

I would like some attributes (perhaps this is the wrong term in this context) to be private, that is, only internal for the object use - can't be read or written from the outside.
For example, think of some internal variable that counts the number of times any of a set of methods was called.
Where and how should I define such a variable?
The Moose::Manual::Attributes shows the following way to create private attributes:
has '_genetic_code' => (
is => 'ro',
lazy => 1,
builder => '_build_genetic_code',
init_arg => undef,
);
Setting init_arg means this attribute cannot be set at the constructor. Make it a rw or add writer if you need to update it.
/I3az/
You can try something like this:
has 'call_counter' => (
is => 'ro',
writer => '_set_call_counter',
);
is => 'ro' makes the attribute read only. Moose generates a getter. Your methods will use the getter for incrementing the value, like so:
sub called {
my $self = shift;
$self->_set_call_counter( $self->call_counter + 1 );
...
}
writer => '_set_call_counter' generates a setter named _set_call_counter. Moose does not support true private attributes. Outside code can, technically, call _set_call_counter. By convention, though, applications do not call methods beginning with an underscore.
I think you want MooseX::Privacy.
The perldoc tells you all you should need - it adds a new trait to your attributes allowing you to declare them as private or protected:
has config => (
is => 'rw',
isa => 'Some::Config',
traits => [qw/Private/],
);
I haven't been able to figure out a way to make Moose attributes completely private. Whenever I use has 'name' => (...); to create an attribute, it is always exposed to reading at a minimum. For items I want to be truly private, I'm using standard "my" variables inside the Moose package. For a quick example, take the following module "CountingObject.pm".
package CountingObject;
use Moose;
my $cntr = 0;
sub add_one { $cntr++; }
sub get_count { return $cntr; }
1;
Scripts that use that module have no direct access to the $cntr variable. They must use the "add_one" and "get_count" methods which act as an interface to the outside world. For example:
#!/usr/bin/perl
### Call and create
use CountingObject;
my $co = CountingObject->new();
### This works: prints 0
printf( "%s\n", $co->get_count() );
### This works to update $cntr through the method
for (1..10) { $co->add_one(); }
### This works: prints 10
printf( "%s\n", $co->get_count() );
### Direct access won't work. These would fail:
# say $cntr;
# say $co->cntr;
I'm new to Moose, but as far as I can tell, this approach provides completely private variables.
Alan W. Smith provided a private class variable with a lexical variable, but it is shared by all objects in the class. Try adding a new object to the end of the example script:
my $c1 = CountingObject->new();
printf( "%s\n", $c1->get_count() );
# also shows a count of 10, same as $co
Using MooseX:Privacy is a good answer, though if you can't, you can borrow a trick from the inside-out object camp:
package CountingObject;
use Moose;
my %cntr;
sub BUILD { my $self = shift; $cntr{$self} = 0 }
sub add_one { my $self = shift; $cntr{$self}++; }
sub get_count { my $self = shift; return $cntr{$self}; }
1;
With that, each object's counter is stored as an entry in a lexical hash. The above can be implemented a little more tersely thus:
package CountingObject;
use Moose;
my %cntr;
sub add_one { $cntr{$_[0]}++ }
sub get_count { return $cntr{$_[0]}||0 }
1;

Modify Moose attribute methods

I'm creating a list of attributes (more than the three shown below), all of which share common methods. Is it possible to then add a trigger to one of the methods:
# Create a bunch of attributes
for my $attr ( qw( title name address ) ) {
has $attr => ( is => 'rw', isa => 'Str' );
around $attr => sub {
# more stuff here.
}
}
# Add a trigger
has_another_method 'title' => ( trigger => \&_trigger_title );
I know I can get meta information about attributes, but I haven't found anything that would enable me to change the attribute methods (and perhaps for good reason). Being able to do this would help keep my code clean, and mean that the common bits are all defined in one place. If not, I can just create the attribute separately, and include the trigger method.
Update
The answers have made it clear that changing the attribute after it has been created is not a good idea. Instead, I've opted for a different method which allows me to keep all the attribute options in one place. This example is a little simplistic, but it demonstrates the idea:
# Create a bunch of attributes
for my $attr ( qw( title name address ) ) {
my %options = ( is => 'rw', isa => 'Str' );
# Add a trigger to the title attribute.
$options{ 'trigger' } = \&_trigger_title
if $attr eq 'title';
has $attr => ( %options );
around $attr => sub {
# more stuff here.
}
}
Triggers are just an attribute on the attribute, but they are defined to be read only. You could find_meta( $attribute )->get_attribute('trigger')->set_value( $attribute, sub { new trigger }), but you're really breaking encapsulation here.
I would just declare all common attributes in my for loop, and then declare the special cases elsewhere.
Attribute methods are composed when they are constructed, so it is generally a good practice to have all the options available when you create it with the has directive. However, currently there is nothing special being done with trigger methods, so you could do this, to get around the read-onlyness of the 'trigger' option:
my $attr = __PACKAGE__->meta->get_attribute('title')->meta->get_attribute('trigger')->set_raw_value('_trigger_sub_name');
However this is delving rather excessively into the innards of Moose; if the implementation ever changes, you can be SOL (plus you would be violating constraints that are there for a reason). So it would be much better to set up your triggers as:
has $_ => (
is => 'rw', isa => 'Str',
trigger => '_trigger_' . $_,
) for (qw(title name address));
sub _trigger_title {
# implementation here
}
sub _trigger_name {
# implementation here
}
sub _trigger_address {
# implementation here
}

Setting Up Perl Module Structure

I'm having trouble figuring out how to structure Perl modules in an object oriented way so I can have one parent module with a number of submodules and only the specific submodules that are needed would be loaded by a calling script. For example I want to be able to make method calls like so:
use Example::API;
my $api = Example::API->new();
my $user = {};
$user->{'id'} = '12345';
$api->Authenticate();
$user->{'info'} = $api->Users->Get($user->{'id'});
$user->{'friends'} = $api->Friends->Get($user->{'id'});
In terms of file structure I'd like to have the modules setup as follows or in whatever structure is required to make everything work correctly:
api.pm
users.pm
friends.pm
...
The reason I want to do this in the first place is so that if someone just wants to authenticate against the API they don't have to load all the other modules. Similarly, if someone just wants to get a user's information, they wouldn't have to load the friends.pm module, just the users.pm. I'd appreciate it if you could provide the necessary example Perl code for setting up each module as well as explain how the file structure should be setup. If I'm going about this all wrong to accomplish what I'm try to accomplish I'd appreciate an explanation of the best way to do this and some example code on how it should be setup.
From your example, in your main module I assume you will be providing accessor methods to get at the subclasses. So all you have to do is include require Sub::Module; at the top of that method. Nothing will happen at compile time, but the first time that code is run, perl will load the module. After the first load, the line require Sub::Module; will become a no-op.
If all of your code is object oriented, you won't need to worry about importing functions. But if you do, the statement use Module qw(a b c); is interpreted as:
BEGIN {
require Module;
Module->import(qw(a b c));
}
BEGIN makes it happen at compile time, but there is nothing stopping you from using the internals at run time. Any subroutines you import at runtime must be called with parenthesis, and prototypes will not work, so unless you know what you are doing, runtime imports are probably a bad idea. Runtime requires and access via package methods are completely safe though.
So your $api->Users method might work something like this:
# in package 'Example::API' in the file 'Example/API.pm'
sub Users {
require Example::API::Users; # loads the file 'Example/API/Users.pm'
return Example::API::Users->new( #_ ); # or any other arguments
}
In my examples above, I showed two translations between package names and the files they were in. In general, all :: are changed to / and .pm is added to the end. Then perl will search for that file in all of the directories in the global variable #INC. You can look at the documentation for require for all of the details.
Update:
One way to cache this method would be to replace it at runtime with a function that simply returns the value:
sub Users {
require Example::API::Users;
my $users = Example::API::Users->new;
no warnings 'redefine';
*Users = sub {$users};
$users
}
Here's a big ugly Moose example that selectively applies roles to an API driver instance.
script.pl
use Example::User;
# User object creates and authenticates a default API object.
my $user = Example::User->new( id => '12345' );
# When user metadata is accessed, we automatically
# * Load the API driver code.
# * Get the data and make it available.
print "User phone number is: ", $user->phone_number, "\n";
# Same thing with Friends.
print "User has ", $user->count_friends, " friends\n";
print "User never logged in\n" unless $user->has_logged_in;
Example/API.pm - the basic protocol driver class:
package Example::API;
use Moose;
has 'host' => (
is => 'ro',
default => '127.0.0.1',
);
sub Authenticate {
return 1;
}
# Load the user metadata API driver if needed.
# Load user metadata
sub GetUserInfo {
my $self = shift;
require Example::API::Role::UserInfo;
Example::API::Role::UserInfo->meta->apply($self)
unless $self->does('Example::API::Role::UserInfo');
$self->_Get_UserInfo(#_);
}
# Load the friends API driver if needed.
# Load friends data and return an array ref of Friend objects
sub GetFriends {
my $self = shift;
#require Example::API::Role::Friends;
Example::API::Role::Friends->meta->apply($self)
unless $self->does('Example::API::Role::Friends');
$self->_Get_Friends(#_);
}
The user metadata and friends data drivers are built as 'roles' which are dynamically applied to an API driver instance as needed.
Example/API/Role/UserInfo.pm:
package Example::API::Role::UserInfo;
use Moose::Role;
sub _Get_UserInfo {
my $self = shift;
my $id = shift;
my $ui = Example::API::User::MetaData->new(
name => 'Joe-' . int rand 100,
phone_number => int rand 999999,
);
return $ui;
}
Example/API/Role/Friends.pm:
use Moose::Role;
sub _Get_Friends {
my $self = shift;
my $id = shift;
my #friends = map {
Example::API::Friend->new(
friend_id => "$id-$_",
name => 'John Smith'
);
} 1 .. (1 + int rand(5));
return \#friends;
}
A friend object:
Example/API/Friend.pm
package Example::API::Friend;
use Moose;
has 'friend_id' => (
is => 'ro',
isa => 'Str',
required => 1,
);
has 'name' => ( isa => 'Str', is => 'ro', required => 1 );
And a user metadata object.
Example/API/User/MetaData.pm
package Example::API::User::MetaData;
use Moose;
has 'name' => (
is => 'ro',
isa => 'Str',
);
has 'phone_number' => (
is => 'ro',
isa => 'Str',
);
has 'last_login' => (
is => 'ro',
isa => 'DateTime',
predicate => 'has_logged_in',
);
And finally a user object. I've used many Moose features to make this a very capable object with only a small amount of imperative code.
package Example::User;
use Moose;
has 'id' => (
is => 'ro',
isa => 'Int',
required => 1,
);
has 'server_connection' => (
is => 'ro',
isa => 'Example::API',
builder => '_build_server_connection',
);
# Work with a collection of friend objects.
has 'friends' => (
is => 'ro',
isa => 'ArrayRef[Example::API::Friend]',
traits => ['Array'],
handles => {
all_friends => 'elements',
map_friends => 'map',
filter_friends => 'grep',
find_option => 'first',
get_option => 'get',
join_friends => 'join',
count_friends => 'count',
has_no_friends => 'is_empty',
sorted_friends => 'sort',
},
lazy_build => 1,
);
has 'user_info' => (
is => 'ro',
isa => 'Example::API::User::MetaData',
handles => {
name => 'name',
last_login => 'last_login',
phone_number => 'phone_number',
has_logged_in => 'has_logged_in',
},
lazy_build => 1,
);
sub _build_server_connection {
my $api = Example::API->new();
$api->Authenticate();
return $api;
}
sub _build_friends {
my $self = shift;
$self->server_connection->GetFriends( $self->id );
}
sub _build_user_info {
my $self = shift;
$self->server_connection->GetUserInfo( $self->id );
}
This example makes use of a lot of Moose magic, but you wind up with a very simple interface for those using the objects. While this is close to 200 lines of formatted code, we get a huge amount done.
Adding type coercion would give an even easier interface. Raw string dates can be automatically parsed into DateTime objects. Raw IP addresses and server names can be converted into API servers.
I hope this inspires you to take a look at Moose. The documentation is excellect, check out the Manual and the Cookbooks, in particular.
Managing the exports is tricky, but you could use an AUTOLOAD solution to this problem. If perl doesn't recognize the subroutine name you are trying to call, it can pass it to a sub called AUTOLOAD. Suppose we did this:
use Example::API;
sub AUTOLOAD {
my $api = shift;
eval "require $AUTOLOAD"; # $api->Foo->... sets $AUTOLOAD to "Example::API::Foo"
die $# if $#; # fail if no Example::API::Foo package
$api;
}
Then this code:
$api = new Example::API;
$api->Foo->bar(#args);
will (assuming we haven't imported Example::API::Foo first) call our AUTOLOAD method, attempt to load the Example::API::Foo module, and then try to call the method Example::API::Foo::bar with the $api object and the other arguments you provide.
Or in the worst case,
$api->Foo->bar(#args)
causes this code to be invoked
eval "require Example::API::Foo";
die $# if $#;
&Example::API::Foo::bar($api,#args);
Depending on how you use this feature, it might be a lot more overhead than just importing everything you need.
There are a number of tools that can be used to quickly build an skeletal structure for your new module development.
h2xs comes with the standard Perl distribution. Its primary focus is on building XS code for interfacing with C libraries. However, it does provide basic support for laying out pure Perl projects: h2xs -AX --skip-exporter -n Example::API
I use Module::Starter to build a beginning layout for my module development. It does a lot that h2xs doesn't do. module-starter --module=Example::API,Example::Friends,Example::Users --author="Russel C" --email=russel#example.com
Dist::Zilla is a new tool that handles many tasks related to maintaining a Perl module distribution. It is amazingly powerful and flexible. But it is new and the docs are a bit rough. The unavoidable complexity that comes with all that power and flexibility means that learning to use it is a project. It looks very interesting, but I haven't taken the time to dive in, yet.
If you need to limit the number of methods loaded, you can use AutoLoader or SelfLoader to load subroutines as they are called. This will lead to a slight overhead when a method is called for the first time. In my experience, this approach is rarely needed.
The best thing is to keep your objects small and strictly defined so that they embody a simple concept. Do not allow ambiguity or half-way concepts into your objects, instead consider using composition and delegation to handle areas of potential confusion. For example, instead of adding date formatting methods to handle a user's last login, assign DateTime objects to the last_login attribute.
In the interest of making composition and delegation easy, consider using Moose to build your objects. It removes much of the drudgery involved in Perl OOP and object composition and delegation in specific.