Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??

One of the core ideas behind Moose is that of metaprogramming. That is; don't write programs - write programs which write programs.

For example, rather than defining our attributes the old-fashioned way, like:

sub some_attribute { my $self = shift; $self->{some_attribute} = shift if @_; return $self->{some_attribute}; }

We just write:

has some_attribute => (is => 'rw');

The has function is a "program which writes programs". It makes our sub some_attribute for us!

So the solution is to write something that does the same sort of job as has, but has some domain-specific knowledge about grabbing raw data, unpacking it, etc. Here's an example (untested):

{ package Binary::Humax::HmtData; use DateTime; use Moose; has raw_data_block => ( is => 'rw', isa => 'Str', required => 1, ); # Shortcut function for defining attributes # sub _my_has { my ($name, %spec) = @_; my $meta = __PACKAGE__->meta; # Default attribute to 'rw' $spec{is} //= 'rw'; # Set up lazy builder if (my $unpack = delete $spec{unpack}) { $spec{lazy} //= 1; $spec{builder} //= "_build_$name"; if (my $postprocess = delete $spec{postprocess}) { $meta->add_method($spec{builder}, sub { my $self = shift; local $_ = unpack($unpack, $self->raw_data_block); $postprocess->(); }); } else { $meta->add_method($spec{builder}, sub { my $self = shift; return unpack($unpack, $self->raw_data_block); }); } } $meta->add_attribute($name, \%spec); } # Now use that shortcut to define each attribute. # _my_has last_play => (isa => 'Int', unpack => '@5 S'); _my_has chan_num => (isa => 'Int', unpack => '@17 S'); _my_has start_time => ( isa => 'DateTime', unpack => '@5 S', postprocess => sub { DateTime->from_epoch(epoch => $_, time_zone => 'GMT'); }, ); _my_has file_name => (isa => 'Str', unpack => '@33 A512'); # Create an alternative constructor which wraps "new". # sub new_from_file { my ($class, $filename) = @_; open my $fh, '>', $filename; my $slurp = do { local $/ = <$fh> }; return $class->new(r); } } # # USAGE # my $hmt_data = Binary::Humax::HmtData->new_from_file($path_name); my $field = $hmt_data->start_time;

"Secondly, when complete, I plan to upload the module to CPAN. Have I chosen a good name for it, or should it live in a different name space?"

No, it seems like a bad name. You're putting it in "Binary" because it's a binary file format. But presumably end users of your module won't care whether it's a binary file format, a text-based one, or XML-based; they don't care about the file format at all, because they've downloaded your module to abstract those sort of details away, haven't they?

I would have thought something in the "TV" namespace more fitting.

UPDATE:; we can go even "more meta" by replacing our has workalike with an attribute trait. This has the advantage of allowing introspection of each attribute to read back its "unpack" code.

{ package Binary::Humax::HmtData::Trait::Attribute; use Moose::Role; has unpack => (is => 'ro', isa => 'Str'); has postprocess => (is => 'ro', isa => 'CodeRef'); before _process_options => sub { my ($meta, $name, $spec) = @_; if ($spec->{unpack}) { $spec->{lazy} //= 1; $spec->{builder} //= "_build_$name"; $spec->{is} //= 'rw'; } }; after attach_to_class => sub { my $attr = shift; my $class = $attr->associated_class; my $unpack = $attr->unpack or return; if (my $postprocess = $attr->postprocess) { $class->add_method($attr->builder, sub { my $self = shift; local $_ = unpack($unpack, $self->raw_data_block); $postprocess->(); }); } else { $class->add_method($attr->builder, sub { my $self = shift; return unpack($unpack, $self->raw_data_block); }); } }; } { package Binary::Humax::HmtData; use DateTime; use Moose; use constant MAGIC => 'Binary::Humax::HmtData::Trait::Attribute'; has raw_data_block => ( is => 'rw', isa => 'Str', required => 1, ); has last_play => ( traits => [ MAGIC ], isa => 'Int', unpack => '@5 S', ); has chan_num => ( traits => [ MAGIC ], isa => 'Int', unpack => '@17 S', ); has start_time => ( traits => [ MAGIC ], isa => 'DateTime', unpack => '@5 S', postprocess => sub { DateTime->from_epoch(epoch => $_, time_zone => 'GMT'); }, ); has file_name => ( traits => [ MAGIC ], isa => 'Str', unpack => '@33 A512', ); } # Attribute introspection print Binary::Humax::HmtData->meta->get_attribute('start_time')->unpac +k, "\n";

The slight ugliness with this method is that the attribute trait has some knowledge of the class it's being applied to - it knows that the class has a raw_data_block attribute. With a little more work that problem could be eliminated.

perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

In reply to Re: Binary data structure to moose class. by tobyink
in thread Binary data structure to moose class. by chrestomanci

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!
  • 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, 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, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • Outside of code tags, you may need to use entities for some characters:
            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.
  • Log In?
    Username:
    Password:

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

    How do I use this? | Other CB clients
    Other Users?
    Others pondering the Monastery: (5)
    As of 2014-09-24 04:03 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      How do you remember the number of days in each month?











      Results (245 votes), past polls