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 <[email protected]> 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