I had a similar problem. Try this: ============== start
#!/usr/bin/perl -w { package MooseX::Trait::PromptBuilder; use Moose::Role; after 'install_accessors' => sub { my ($attr, $inline, $class) = @_; $attr->create_builder($class); }; # Replace this! Add type checking, color, dancing bears, etc. sub ask_away { my ($attr) = @_; return sub { print "Value for " . $attr->name . ": "; my $resp = <STDIN>; chomp $resp; return ($resp eq "") ? undef : $resp; } } has __ask_builder_built => ( isa => 'Bool', reader => '_has_ask_builder', writer => '_set_has_ask_builder' ); sub create_builder { my $attr = shift; my $class = shift || $attr->associated_class; # To prevent recurssion return if $attr->_has_ask_builder; $attr->_set_has_ask_builder(1); # You do not need this, but someday you may: if ($attr->associated_class->is_immutable) { Moose->throw_error( q{Class }, $attr->associated_class, q{is immutable. Run create_builder before make_immutable}); } my $builder = $attr->ask_away(); if ($attr->has_builder) { $attr->associated_class->add_around_method_modifier($attr->builder, sub { my ($orig,$instance,@params) = @_; for my $code ($builder,$orig) { my $return = $instance->$code(@params); if (defined $return) { return $return } } return; } ); } else { # The real magic: $attr = $attr->clone_and_inherit_options( default => $builder, lazy => 1 ); $class->add_attribute($attr); } } 1; } { package MyApp; use Moose; has toes => ( is => "Int", is => "ro", traits => [ 'MooseX::Trait::PromptBuilder' ], # DO NOT USE default ATTRIBUTE builder => '_build_toes', ); sub _build_toes { 12 } } my $app1 = MyApp->new(); print "I have: ", $app1->toes , "\n"; ==========end I reserve no rights to the above, if you have to ask. ---ealleniii On Wed, Dec 21, 2011 at 8:45 PM, Buddy Burden <barefootco...@gmail.com> wrote: > > Guys, > > Okay, basically what I want is just what the subject says: you might > declare your attribute something like so: > > has value => ( traits => [qw< Promptable >], is => 'rw', isa => > 'Int', prompt => 'Please enter a value:' ); > > then, for each instance, if you provide a value in new(), that's the > value; if you don't, it prompts the user for it. The basic idea is I > can use this with MooseX::App::Cmd for switches that are not provided > on the command-line. > > So, my first approach was to around attach_to_class and just stick a > builder method in. But you can't actually _set_ a builder, because > builder is essentially a read-only attribute of the attribute > metaclass. > > Okay, no problem: I'll just intercept BUILDARGS for the attribute > metaclass and slip a builder in there as if the client had specified > it. No go: > > > The method 'BUILDARGS' was not found in the inheritance hierarchy for > > Moose::Meta::Class::__ANON__::SERIAL::15 at > > /usr/local/lib64/perl5/Class/MOP/Class.pm line 1048 > > I guess roles can't mess with the BUILDARGS for the classes they're > composed into ... ? I could imagine that being a reasonable > restriction. > > Okay, next try: I'll around initialize_slot_instance for the > attribute metaclass and prompt right there, and slip the user-supplied > value into $params before passing it onto $orig (only if not already > there and after validation, natch). But my around method for > initialize_slot_instance is never called, it seems ... not sure why > ... because it's being supplied by a role? because the new() is being > inlined? other? > > So now I'm out of ideas. Can anyone tell me what's wrong with any of > the approaches, or if there's a whole 'nother approach that I should > be using? or maybe there's some helpful module I've missed in my CPAN > searches? Anything? I'd really appreciate it. > > Thanx for all you do, Moosites. Moose makes my job easier every day. > Keep up the good work. > > > -- Buddy