Not quite... We're not changing the default metaclass for everything, but
rather applying a metarole to the metaclass of the consuming class. (I think
that's how it goes -- I'm still not sure of the correct terminology.) And
there's still an attribute "trait" involved there, albeit a minimal one that
adds a "prompt" option to affected attributes. The
new_object/_inline_new_object wrappers simply look for those attributes at
the end of construction and ask the user to fill in the blanks. (If you're
concerned about prompting during cloning and/or reblessing, there'll be a
little more work to do.) Don't know if it's a good approach by Moose Cabal
standards, but it's direct. You'd want to add in other stuff probably, like
mutual exclusion with defaults, etc.
-----Original Message-----
From: Buddy Burden
Sent: Thursday, December 22, 2011 2:40 PM
To: Edward Allen
Cc: [email protected]
Subject: Re: Trying to create an attribute trait that prompts for a value if
none specified
Guys,
I'm still experimenting here, but I had a couple of questions.
ealleniii,
I like your solution; very clever, particularly where you install the
bulder sub as a default instead of a builder, which neatly gets around
the problem that a builder has to be the name of a method of the
class. But the crux of it is here:
# The real magic:
$attr = $attr->clone_and_inherit_options(
default => $builder,
lazy => 1
);
$class->add_attribute($attr);
and my gut instinct is to wonder: doesn't that mean the attribute gets
added to the class twice? Now, admittedly I haven't actually tried it
yet, but it also occurred to me to wonder how you could even _tell_ if
the attribute was installed twice ... could it conceivably generate a
silent failure that just resulted in weirdness down the road? or
something that works today but not tomorrow when Moose guts are
changed?
If the author--or anyone else--has some insight on that issue, I'd
really love to hear it.
Todd,
I'm assuming you replied off-list just because you didn't want the zip
file to land in everyone's inbox, for which I'm sure they're
appreciative. :-) So, after staring at your approach for quite a
while, I finally figured out what's going on: you're actually
_changing_ the default metaclass for everything by applying a new role
to it. Said new role contains this:
around new_object => sub {
my ($orig_method, $self_aka_class) = (shift, shift);
my $instance = $self_aka_class->$orig_method(@_);
for my $attr ($self_aka_class->get_all_attributes) {
next unless $attr->has_prompt;
unless ($attr->has_value($instance)) {
my $prompted_val = Term::Prompt::prompt('x',
$attr->prompt, 'help prompt', 'foo');
$attr->set_value($instance, $prompted_val);
}
}
return $instance;
};
Again, very clever. But definitely very different from the approach I
was going for, which was an attribute trait. (Although the provided
test file proves handily that it really works.) Can you--or
anyone--tell me what the practical differences would be between the
two approaches, and why I might prefer one over the other?
Thanx again for the help guys.
-- Buddy