I am implementing a class in Perl Moose on a bigger project.
The issue that I am having is the following:
Lets assume that I have a class method called GetValue() returning an HashRef and an attribute called Value, which is an HashRef.
This is what I am trying to do:
sub GetValue
{
#do something
return \%something;
}
has Value => (
is=>'ro',
isa => 'HashRef',
reader => "Value",
builder => '_Value_builder',
);
sub _Value_builder
{
my $self = shift;
return $self->GetValue();
}
This does not seem to work, Since I am on really big project the error coming out is just a very long stack trace that to my opinion does not hold too much information.
In the real case the function GetValue is a TCP call too a server, socket is part of the class attributes. For what I understand the issue seems to be that the call to GetValue takes place before the builder created the socket, but I am not sure.
Can this syntax work at all? In case the TCP communication is the issue, is there a workaround?
As discussed in the comments already the issue is solved declaring the attribute as lazy:
sub GetValue
{
#do something
return \%something;
}
has Value => (
is=>'ro',
isa => 'HashRef',
reader => "Value",
lazy => 1,
builder => '_Value_builder',
);
sub _Value_builder
{
my $self = shift;
return $self->GetValue();
}
Related
What I am tring to do is the following:
I am writing a perl Moose Class and I want ot have a class attribute that is an Hash and is initialized to default values upon building.
My attempt:
has sweep_prop_configuration => (
is=>'rw',
isa => 'Hash',
reader => 'sweep_prop_configuration',
writer => '_sweep_prop_configuration',
builder => '_build_sweep_prop_configuration',
predicate => 'has_sweep_prop_configuration',
);
sub _build_sweep_prop_configuration {
my $self = shift;
my %hash;
$hash{point_number}=0;
$hash{number_of_sweep}=0;
$hash{backwards}=-1;
$hash{at_end}=-1;
$hash{at_end_val}=0;
$hash{save_all}=-1;
return %hash;
}
I am new to Moose and perl in general, excuse me if I missed something in the documentation.
Moose doesn't define Hash as a type (see Moose::Manual::Types).
It defines HashRef, though. In order to use it, change the builder's last line to
return \%hash
and change the type constraint to
isa => 'HashRef',
It still defines an instance attribute, not a class attribute. To define class attributes, use MooseX::ClassAttribute.
I have a class with an attribute set up as follows:
has _data => (
is => 'ro',
lazy => 1,
builder => '_load',
);
sub _load {
my $self = shift;
return retrieve $self->_file;
}
However I now want to call a method already defined on the class before returning the data.
In old-school Perl OO, I'd be doing something like this:
sub _load {
# Assuming laziness is implemented somewhere else.
my $self = shift;
$self->{_data} = retrieve $self->_file;
$self->refresh; # which does something with $self->{_data}
return $self->{_data};
}
But I can't figure out a 'clean' way to do this in Moose.
I've considered the following, but think they are quite ugly, and that there must be a better way of doing this.
If I make _data read-write, I could potentially write the data to the accessor, call the method then return the value from the accessor for Moose to write back to the accessor.
If I turn it into a plain old method then I'd have to define another attribute, say _raw_data, store the data in there, modify refresh() to use that attribute, and everything else uses _data().
Violate encapsulation and access the underlying $self->{_data} directly.
I tried an after '_load' => \&refresh;, but that just created an endless loop.
This would be a nice use of triggers:
has _data => (
is => 'ro',
lazy => 1,
builder => '_load',
trigger => sub { shift->refresh },
);
Except that triggers don't work on default/built values - only on values passed to the constructor explicitly, or passed to a writer/accessor method. Sad face. :-(
One solution would be to rewrite your refresh method so that instead of operating on $self->_data, it can accept a parameter (perhaps falling back to operating on $self->_data if no parameter is given.
sub _load {
my $self = shift;
my $tmp = retrieve $self->_file;
$self->refresh($tmp);
return $tmp;
}
sub refresh {
my $self = shift;
my $data = scalar(#_) ? $_[0] : $self->_data;
# do something with $data
}
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 );
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.
I'm working on a serialization tool using Moose to read and write a file that conforms to a nonstandard format. Right now, I determine how to load the next item based on the default values for the objects in the class, but that has its own drawbacks. Instead, I'd like to be able to use information in the attribute meta-class to generate a new value of the right type. I suspect that there's a way to determine what the 'isa' restriction is and derive a generator from it, but I saw no particular methods in Moose::Meta::Attribute or Class::MOP::Attribute that could help me.
Here's a bit further of an example. Let's say I have the following class:
package Example;
use Moose;
use My::Trait::Order;
use My::Class;
with 'My::Role::Load', 'My::Role::Save';
has 'foo' => (
traits => [ 'Order' ],
isa => 'Num',
is => 'rw',
default => 0,
order => 1,
);
has 'bar' => (
traits => [ 'Order' ],
isa => 'ArrayRef[Str]',
is => 'rw',
default => sub { [ map { "" } 1..8 ] }
order => 2,
);
has 'baz' => (
traits => [ 'Order' ],
isa => 'Custom::Class',
is => 'rw',
default => sub { Custom::Class->new() },
order => 3,
);
__PACKAGE__->meta->make_immutable;
1;
(Further explanation: My::Role::Load and My::Role::Save implement the serialization roles for this file type. They iterate over the attributes of the class they're attached to, and look at the attribute classes for an order to serialize in.)
In the My::Role::Load role, I can iterate over the meta object for the class, looking at all the attributes available to me, and picking only those that have my Order trait:
package My::Role::Load;
use Moose;
...
sub load {
my ($self, $path) = #_;
foreach my $attribute ( $self->meta->get_all_attributes ) {
if (does_role($attribute, 'My::Trait::Order') ) {
$self->load_attribute($attribute) # do the loading
}
}
}
Now, I need to know the isa of the attribute that the meta-attribute represents. Right now, I test that by getting an instance of it, and testing it with something that's kind of like this:
use 5.010_001; # need smartmatch fix.
...
sub load_attribute {
my ($self, $attribute, $fh) = #_;
my $value = $attribute->get_value($self); # <-- ERROR PRONE PROBLEM HERE!
if (ref($value) && ! blessed($value)) { # get the arrayref types.
given (ref($value)) {
when('ARRAY') {
$self->load_array($attribute);
}
when('HASH') {
$self->load_hash($attribute);
}
default {
confess "unable to serialize ref of type '$_'";
}
}
}
else {
when (\&blessed) {
confess "don't know how to load it if it doesn't 'load'."
if ! $_->can('load');
$_->load();
}
default {
$attribute->set_value($self, <$fh>);
}
}
}
But, as you can see at # <-- ERROR PRONE PROBLEM HERE!, this whole process relies on there being a value in the attribute to begin with! If the value is undef, I have no indication as to what to load. I'd like to replace the $attribute->get_value($self) with a way to get information about the type of value that needs to be loaded instead. My problem is that the docs I linked to above for the Class::MOP::Attribute and the Moose::Meta::Attribute don't seem to have any way of getting at the type of object that the attribute is supposed to get.
The type information for an attribute is basically what I'm trying to get at.
(Note to future readers: the answer here got me started, but is not the final solution in of itself. You will have to dig into the Moose::Meta::TypeConstraint classes to actually do what I'm looking for here.)
Not sure I follow what you are after and perhaps Coercions might do what you want?
However to get the attributes isa:
{
package Foo;
use Moose;
has 'bar' => ( isa => 'Str', is => 'rw' );
}
my $foo = Foo->new;
say $foo->meta->get_attribute('bar')->type_constraint; # => 'Str'
/I3az/
Out of curiosity why not use/extend MooseX::Storage? It does Serialization, and has for about two and a half years. At the very least MooseX::Storage will help you by showing how a (well tested and production ready) serialization engine for Moose is written.
I'm not quite sure I understand (perhaps you can include some pseudocode that demonstrates what you are looking for), but it sounds like you could possibly get the behaviour you want by defining a new attribute trait: set up your attribute so that a bunch of methods on the class delegate to the attribute's object (isa => 'MySerializer', handles => [ qw(methods) ]).
You might possibly also need to subclass Moose::Meta::Class (or better, add a role to it) which augments the behaviour of add_attribute().
Edit: If you look at the source for Moose::Meta::Attribute (specifically the _process_options method), you will see that the isa option is processed by Moose::Util::TypeConstraints to return the actual type to be stored in the type_constraint field in the object. This will be a Moose::Meta::TypeConstraint::Class object, which you can make calls like is_a_type_of() against.
This field is available via the type_constraint method in Moose::Meta::Attribute. See Moose::Meta::TypeConstraint for all the interfaces available to you for checking an attributes's type.