To the members of the body monktorate, greetings.

I seek your wisdom. I am trying to teach myself to use Moose (or the associated variations, such as Mouse, Moo, Mo, etc.). For my learning project, I wanted to do something I felt more useful than the Animal example, so for my purposes I wanted to represent a particle. I created a StationaryParticle, then extended it to a MoveableParticle. Because I want it to move within a limited rectangular space, I began trying to add a Boundary object to the system, which I added as a singleton for now (because in most cases particles would have the same boundaries). This is when I came to my problem.

In my way of thinking I would either group a boundary based on aggregation (min/max) then dimension (x/y), or vice versa, so I might define either of the following:

my $boundary_aggregation_first = ( min => { x => 0, y => 0, }, max => { x => 639, y => 479, }, ); my $boundary_dimension_first = ( x => { min => 0, max => 639, }, y => { min => 0, max => 479, }, );
(For the remainder of the code, I will go with the aggregation-first model, although the issue occurs either way.)

When I try to code that into Moo (or Moose), I'm not sure how best to handle that object. I would think I should be able to add the limit through a method, but I cannot seem to reason out what that method should look like. If I break encapsulation I could it could be as easy as $wall->limit->{min}{x} = 0, but I don't want to be *that guy* who tromps through code (and for whom it blows up if the Boundary objects change later.)

package Boundary; use strictures 2; use namespace::clean; use Data::Dumper; use Moo; use MooX::Types::MooseLike::Base qw/ HashRef Int Maybe /; with q{MooX::Singleton}; has q{limit} => ( is => q{rw}, isa => HashRef [ HashRef [ Maybe [Int] ] ], traits => [ q{Hash}, ], default => sub { {} }, );

I then tried a 'before' call to try to allow me to hand it a HoH and set the values there, or pass in a HoH with an undefined value to hopefully return the value:

before q{limit} => sub { my $self = shift; if ( scalar @_ ) { my $val = shift; if ( ref $val eq q{HASH} ) { foreach my $k ( keys %{$val} ) { if ( defined $val->{$k}->{$l} ) { $self->limit->{$k}{$l} = $val->{$k}->{$l}; } else { my $result = $self->limit->{$k}{$l}; return $result; } } } } }; __PACKAGE__->meta->make_immutable; 1; package main; my $wall = Boundary->instance(); $wall->limit( { min => { x => 0, y => 0, }, max => { x => 639, y => 478, }, }, ); # ... say $wall->limit( { min => { x => undef, }, }, ); # Expected: 0 # Actual: HASH(0x801a440b8) say $wall->limit( { max => { x => undef, }, }, ); # Expected: 639 # Actual: HASH(0x801a44160)

What I see with this is that I appear to be replacing the singleton when I try to use the undef setting to retrieve the value.

What is the proper way to do what I am trying to accomplish?

Thank you for your time and attention, and any guidance/assistance you may provide. Have a great day, and stay safe!

sscce.pl:

use strict; use warnings; use 5.014; use Moo; use strictures 2; use namespace::clean; package Boundary; use Data::Dumper; use Moo; use MooX::Types::MooseLike::Base qw/ HashRef Int Maybe /; with q{MooX::Singleton}; has 'limit' => ( is => q{rw}, isa => HashRef [ HashRef [ Maybe [Int] ] ], traits => [ q{Hash}, ], default => sub { {} }, ); before q{limit} => sub { my $self = shift; if ( scalar @_ == 1 ) { my $val = shift; if ( ref $val eq q{HASH} ) { foreach my $k ( keys %{$val} ) { foreach my $l ( keys %{ $val->{$k} } ) { if ( defined $val->{$k}->{$l} ) { $self->limit->{$k}{$l} = $val->{$k}->{$l}; } else { my $result = $self->limit->{$k}{$l}; return $result; } } } } } }; __PACKAGE__->meta->make_immutable; 1; package main; # use Boundary; my $wall = Boundary->instance(); $wall->limit( { min => { x => 0, y => 0, }, max => { x => 320, y => 240, }, }, ); say $wall->limit->{min}{x}; say $wall->limit->{min}{y}; say $wall->limit->{max}{x}; say $wall->limit->{max}{y}; # $wall->limit->{max}{x} = 325; # $wall->limit->{max}{y} = 245; say __LINE__ . q{: }, $wall->limit( { max => { x => 325, y => 245, }, }, ); say __LINE__ . q{: }, $wall->limit( { max => { q{x} => undef, }, }, ); say __LINE__ . q{: }, $wall->limit( { max => { q{y} => undef, }, }, ); # $wall->limit->{max}{x} = 320; # $wall->limit->{max}{y} = 240; $wall->limit( { max => { x => 320, y => 240, }, }, ); __END__

In reply to Question regarding proper handling of a Hash/HashRef structure in Moose-variants by atcroft

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



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.