antmico has asked for the wisdom of the Perl Monks concerning the following question:

Hello wise ones. I'm playing around with Moose, with a view to using a class to represent an XML element and ultimately to generate the XML itself. The below code works but I am not entirely happy with the use of the predicate method to determine if each attribute (the majority of which are optional) needs to be included in the resulting XML. Is there a better way I can approach this? I have considered trigger and after methods to record the attributes that have been set but both feel equally clumsy. Many thanks.
package Button; use Moose; use namespace::autoclean; use XML::Writer; has 'name' => ( is => 'rw', isa => 'Str', required => 1); has 'x' => ( is => 'rw', isa => 'Int', predicate => 'has_x'); has 'y' => ( is => 'rw', isa => 'Int', predicate => 'has_y'); has 'w' => ( is => 'rw', isa => 'Int', predicate => 'has_w'); has 'h' => ( is => 'rw', isa => 'Int', predicate => 'has_h'); sub to_xml { my ($self) = @_; my %attr; $attr{name} = $self->name; $attr{x} = $self->x if $self->has_x; $attr{y} = $self->y if $self->has_y; $attr{w} = $self->w if $self->has_w; $attr{h} = $self->h if $self->has_h; my $writer = XML::Writer->new( OUTPUT => 'self' ); $writer->emptyTag('button', %attr); return $writer->to_string; } __PACKAGE__->meta->make_immutable;

Replies are listed 'Best First'.
Re: Moose attribute predicate alternative
by choroba (Cardinal) on Jul 04, 2013 at 13:16 UTC
    I do not know Moose in detail, so I cannot comment on the design. To not repeat yourself (DRY), though, you can use method names in variables:
    for my $att (qw/x y w h/) { my $predicate = "has_$att"; $attr{$att} = $self->$att if $self->$predicate; }
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Or even:

      $attr{$_} = $self->$_ if $self->${\"has_$_"} for qw/x y w h/;
      package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
      Thanks for the suggestion, that removes the repetition that was primarily bothering me. Thanks all.
Re: Moose attribute predicate alternative
by tobyink (Canon) on Jul 04, 2013 at 14:36 UTC

    As well as what choroba said, take a look at XML::Rabbit which is designed to simply mapping between Moose objects and XML.

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