Re: Moose Question

[email protected] ("Christopher Brown")
Newsgroups perl.moose
Message-ID <[email protected]>
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
> > > > > ==========================*/
> > > > >
> > > > >
> > > > >
> > >
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.