Re: Moose Question
[email protected] (Stevan Little)
| Newsgroups | perl.moose |
|---|---|
| Message-ID | <[email protected]> |
Chris,
On Mar 19, 2008, at 5:22 PM, Christopher Brown wrote:
> I do have follow-up questions, though. Suppose I want to generate
> those
> plain old methods dynamically. Is there a simple, moose way to do
> this in
> the BUILD subroutine. On e way to accomplish this is to assign an
> anonymous subroutine to a glob. Like this:
The BUILD method runs every time an object is created (per-instance)
and by altering the symbol table you are adding a method to the class
itself. If the method you add is a closure around a $row (which it
seems that is what you are going for) you will only be able to use
one instance of this class at a time, otherwise the method you add
will override one another.
> package My::App;
>
> use Moose;
> has name => ( is => 'rw', isa=>'Str' );
>
> sub BUILD {
> **__PACKAGE__::method = sub { print "hello world\n"; } ;*
> }
>
> package main;
> my $app = My::App->new( { name => 'Moose' } );
> $app->method;
>
>
> But I don't want to do that. I want to do it the Moose way.
As I said above, this is not really a good idea, but the Moosey way
to do it would be:
sub BUILD {
my $self = shift;
$self->meta->add_method('method' => sub { ... });
}
This is documented in Class::MOP::Class.
> I can hear you ask, but why would you want to do that? Well
> suppose, I
> create an object that wraps a query. If I can iterate over the
> record set I
> can replace the data slot with the new record and still named
> methods that
> act as accessors to the record. This beats the snot out of trying to
> instanciate a row object for each record.
I think, if I understand what you are trying to do correctly, you
should do something like this:
(WARNING: this is completely untested code, but it **should** work)
package RecordSetIterator;
use Moose;
has 'record_set' => (
is => 'ro',
isa => 'RecordSet',
);
# list the fields you want to
# fetch from the current record
my @fields = qw[
first_name
last_name
];
has 'current_record' => (
is => 'ro',
isa => 'Record',
lazy => 1,
default => sub {
my $self = shift;
$self->record_set->next() # grab the first one
},
trigger => sub {
my $self = shift;
# whenever this attribute is
# updated, it will clear all
# the fields for you.
$self->$_() for map { '_clear_' . $_ } @fields;
}
);
# define the attributes
# for all the fields.
has $_ => (
is => 'ro',
# make sure they have a clearer ...
clearer => ('_clear_' . $_)
lazy => 1,
default => sub {
my $self = shift;
# fetch the value from
# the current record
$self->current_record->$_();
},
) for @fields;
sub get_next_record {
my $self = shift;
$self->current_record($self->record_set->next());
}