Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

Good idea. I don't know why I didn't think of initializers. The Moose cabal aren't especially big fans of initializers, and consider them to be a bit of a misfeature, but this is the kind of niche area they seem to come in handy.

Let's take your initializer technique and add some metaprogramming.

First some test cases...

use v5.14; use Test::More; package Foo { use Moose; has foo => ( traits => ['MooseX::IgnoreFalse::Trait::Attribute'], is => 'ro', default => 'whatever', ); } is(Foo->new(foo => 'xyz')->foo, 'xyz'); is(Foo->new(foo => '0')->foo, 'whatever'); is(Foo->new(foo => '')->foo, 'whatever'); is(Foo->new(foo => undef)->foo, 'whatever'); done_testing;

When those tests all pass, then we're done.

Now, a first stab at the metatrait. For attribute metatraits, after _process_options can be a very handy place to hook onto. It effectively allows you to rewrite a has declaration before the attribute gets created. If you're not doing anything to deeply modify how Moose internals work, then that's often sufficient.

Here we'll just hook after _process_options to add an initializer that does the following:

  1. If the value passed into the constructor was true, then set it.
  2. Otherwise, if there is a default, set the attribute value to the default value.
  3. Otherwise, if there is a builder, set the attribute value to the built value.
  4. Otherwise, don't set the attribute at all.

How does that look?

use v5.14; package MooseX::IgnoreFalse::Trait::Attribute { use Moose::Role; after _process_options => sub { my ($class, $name, $options) = @_; $options->{initializer} = sub { my ($instance, $value, $setter) = @_; my $meta = $instance->meta->get_attribute($name); $value ? $setter->( $value ) : $meta->has_default ? $setter->( $meta->default($instance) +) : $meta->has_builder ? $setter->( $meta->_call_builder($inst +ance) ) : (); } }; }

This is sufficient to pass our test case; yay! However, the keen eyed may have noticed that if the attribute already had an initializer, that will be replaced with our new initializer. So let's make our hook a little smarter to supplement any existing initializer...

use v5.14; package MooseX::IgnoreFalse::Trait::Attribute { use Moose::Role; after _process_options => sub { my ($class, $name, $options) = @_; if (my $orig = $options->{initializer}) { $options->{initializer} = sub { my ($instance, $value, $setter) = @_; my $meta = $instance->meta->get_attribute($name); $value ? $orig->( $instance, $value, $sett +er ) : $meta->has_default ? $orig->( $instance, $meta->defaul +t($instance), $setter ) : $meta->has_builder ? $orig->( $instance, $meta->_call_ +builder($instance), $setter ) : (); } } else { $options->{initializer} = sub { my ($instance, $value, $setter) = @_; my $meta = $instance->meta->get_attribute($name); $value ? $setter->( $value ) : $meta->has_default ? $setter->( $meta->default($instan +ce) ) : $meta->has_builder ? $setter->( $meta->_call_builder($ +instance) ) : (); } } }; }

That's a fairly gentle introduction to attribute metaprogramming.

For completeness, here's everything in one file.

package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name

In reply to Re^2: Moose and default values by tobyink
in thread Moose and default values by morgon

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2024-04-19 20:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found