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
> > > > > ==========================*/
> > > > >
> > > > >
> > > > >
> > >
>

Reply via email to