Stevan,
Thanks for the quick reply. Please find a test case that fails.
System: Linux 2.6.20-2931.fc7 #1 SMP Mon Aug 13 10:12:37 EDT 2007 i686 i686
i386 GNU/Linux
Perl: v5.10.0 built for i686-linux-thread-multi-64int-ld
I think that what is most interesting is that the meta->add_method does not
report that it is failing, so I suspect that the method is installed
somewhere, but I don't know where or how to find it.
I think that the ability to create instance based attribute is powerful and
common and useful in all sorts of situation. If I could have a vote I would
suggest that it be easier to create and instance class. The
*create_anon_class()->rebless(
$self ) *is not the prettiest syntax. I think that it would be useful to
have a standard mechanism to accomplish this.
$self->make_instance_class;
$self->meta->make_instance_class;
Or something like that.
( I have been taken notes as I learn Moose over the past several weeks. If
you would like me to share my thoughts, I would be happy to send them to you
privately or the list. In no way, should they be taken as harsh criticism.
I still think that Moose is the best thing to happen to Perl in a long time.
)
Best Wishes,
Chris
__TEST CASE:__
use feature 'say';
# PACKAGE: person_1
# simple object with two attributes
package person_1;
use Moose;
has name => (
is => 'ro' ,
isa => 'Str' ,
required=> 1
);
has occupation => (
is => 'rw' ,
isa => 'Str' ,
required=> 0 ,
);
# PACKAGE: person_2
# same as person_1 except it also has a BUILD method that
# dynamically installs a method 'is_cool' based on occupation
# type. ( I know this can be a lazy attribute. This is just
# for illustration purposes. The lazy attribute doesn't work
# when you want instance based methods though. )
package person_2;
use Moose;
has name => (
is => 'ro' ,
isa => 'Str' ,
required=> 1
);
has occupation => (
is => 'rw' ,
isa => 'Str' ,
required=> 0 ,
);
sub BUILD {
my $self = shift;
my $methods = {};
if ( $self->occupation eq 'Moose Programmer' ) {
$methods->{is_cool} =
sub { say $_[0]->name . " is really cool."; } ;
} else {
$methods->{is_cool} =
sub { say $_[0]->name . " is only kinda cool.\n" } ;
}
$self->meta->create_anon_class(
superclasses => [__PACKAGE__],
methods => $methods,
)->rebless_instance($self);
}
# ---------------------------------------------------------
# PACKAGE: main
#
package main;
my $steve = person_1->new( {
name => 'Stevan' ,
occupation => 'Moose Programmer' ,
} );
my $chris = person_2->new( {
name => 'Chris' ,
occupation => 'Regular Programmer' ,
} );
# Let's now add a method to Steve
$steve->meta->add_method( "is_fun", sub { say $_[1]->name . " is fun"; } );
$steve->is_fun; # Stevan is fun.
# Let's try the same thing with Chris. Remember Chris has been reblessed
$chris->meta->add_method( "is_fun", sub { say $_[0]->name . " is fun"; } );
$chris->is_fun; # FAIL!
# Can't locate object method "is_fun" via package
"Class::MOP::Class::__ANON__::SERIAL::2" (perhaps you forgot to load
"Class::MOP::Class::__ANON__::SERIAL::2"?) at test.pl line 90.
On Thu, Mar 27, 2008 at 6:47 PM, Stevan Little <
[EMAIL PROTECTED]> wrote:
> Christopher,
>
> I am not sure I am understanding the error you are describing. Could you
> write up a small failing test for me?
>
> Thanks,
>
> - Stevan
>
>
> On Mar 27, 2008, at 3:09 PM, Christopher Brown wrote:
>
> > Paul and Stevan,
> >
> > Sorry for the late reply. Thanks for both answers. Stevan, I am rely
> > impressed with the rapidity of which you and the other Moose members
> > respond. I am also impressed with you presenting a working prototype of
> > my
> > problem in as little time and code as you did. It is really a testament
> > to
> > Moose's power.
> >
> > In the end, I went with the solution that Paul offered. That is, *
> > create_anon_class()->rebless_instance*. And, I have used this recipe
> > a
> > half-dozen or times since. It is really powerful technique for
> > installing
> > instance methods. I did run into a snag with reblessing instances. It
> > seems that I cannot access the meta object after reblessing. I am not
> > so
> > sure why I have the following work on the reblessed object:
> >
> > $self->meta->add_method( 'test', sub { say "Hello World" } ); #
> > $self
> > is the reblessed self.
> >
> > Interestingly enough, the method does not produce an error.
> >
> > As I am discovering with Moose, there is probably a real simple and
> > elegant
> > solutions of which has eluded me. As always, your help is greatly
> > appreciated.
> >
> > Best,
> >
> > Chris
> >
> >
> >
> >
> >
> >
> > On Thu, Mar 20, 2008 at 8:22 AM, Paul Driver <[EMAIL PROTECTED]>
> > wrote:
> >
> > Chris,
> > >
> > > If you want to add generated methods to the class, it's
> > > __PACKAGE__->meta->add_method(foobar => sub { print "Foo, bar!\n" });
> > > I
> > > don't think you want to do this in BUILD though - just at class
> > > compile
> > > time. I do this a lot when I have a bunch of similar methods and
> > > don't want
> > > to repeat myself.
> > >
> > > If you want to add methods to a particular instance ONLY, the thing to
> > > do
> > > is to create an anonymous subclass and rebless your instance to that
> > > subclass, and add the methods to the subclass.
> > >
> > > Some example code - at BUILD time, add a method named $word that does
> > > say
> > > $word for every word passed into the constructor.
> > >
> > > ---
> > >
> > > use feature q(say);
> > > package Speaker;
> > > use Moose;
> > >
> > > has words => (
> > > is => 'ro',
> > > isa => 'ArrayRef[Str]',
> > > predicate => 'has_words',
> > > );
> > >
> > > # All Speakers know how to say bar
> > > sub bar {
> > > say 'bar';
> > > }
> > >
> > > sub BUILD {
> > > my ($self, $args) = @_;
> > > if ($self->has_words) {
> > > my %methods = map {
> > > my $word = $_;
> > > ($word => sub { say $word})
> > > } @{$self->words};
> > >
> > > $self->meta->create_anon_class(
> > > superclasses => [__PACKAGE__],
> > > methods => \%methods,
> > > )->rebless_instance($self);
> > > }
> > > }
> > >
> > > package main;
> > > my $a = Speaker->new;
> > > my $b = Speaker->new(words => [qw(baz qux)]);
> > > $a->bar; # => "Bar"
> > > $b->bar; # => "Bar"
> > > $b->qux; # => "Qux"
> > > say "A" if $a->isa('Speaker'); # => "A"
> > > say "B" if $b->isa('Speaker'); # => "B"
> > > $a->qux; # Can't locate method "qux" via class "Speaker"
> > >
> > > ----
> > >
> > >
> > > On Mar 19, 2008, at 4:22 PM, Christopher Brown wrote:
> > >
> > > Dave,
> > >
> > > >
> > > > Sorry for taking so long to thank you for your reply. Thanks. On
> > > > further
> > > > t, it was a silly question, using a plain old method is obviously
> > > > the
> > > > solution.
> > > >
> > > > 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:
> > > >
> > > > 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.
> > > >
> > > > 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.
> > > >
> > > > Thanks in Advance,
> > > >
> > > > Chris
> > > >
> > > >
> > > >
> > > >
> > > >
> > > > On Wed, Mar 12, 2008 at 2:41 PM, Dave Rolsky <[EMAIL PROTECTED]>
> > > > wrote:
> > > >
> > > > On Wed, 12 Mar 2008, Christopher Brown wrote:
> > > >
> > > > >
> > > > > Despite the 'lazy' evaluation, it appears as if the attribute
> > > > > value
> > > > >
> > > > > > is
> > > > > >
> > > > > > being
> > > > >
> > > > > cached instead of being re-evaluated when the accessor is being
> > > > > > called.
> > > > > >
> > > > > >
> > > > > Lazy just means "don't generate the attribute from the default sub
> > > > > until
> > > > > the _first_ time it is requested". It's still cached.
> > > > >
> > > > > If you want to return a different value each time then you just
> > > > > want a
> > > > > plain old method, not an attribute.
> > > > >
> > > > >
> > > > > -dave
> > > > >
> > > > > /*==========================
> > > > > VegGuide.Org
> > > > > Your guide to all that's veg
> > > > > ==========================*/
> > > > >
> > > > >
> > > > >
> > >
>