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());
}