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

Reply via email to