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














Reply via email to