About Kent Cowgill
Articles filed under...
abs ab_ripper andylester arms back baggyshorts bestpractices biceps bike birthday blog bugs bus calculator cardio catalyst cgi chart chest chinups code cpan datamodel dbi doctor documentation exercise exhaustion fitness flattire flat_tire google gps heart_rate helmet history home houston html humor journal kate kenpo kenpo_x kettlebell knees lazy legs lisa lisanne maps math matthew michaelmckenna mom montreal motivation movie mysql oops orm P90X pain park patellar_tendonitis patrick pdf perl phb photos physical_therapy plyometrics poor_gait presentation procrastination progress pullups pushups pyramid rabbits racecondition rant refactor rest ribs ride route running shoulders situps slides sore spike sql statistics syntax test testing textile timex training triceps ups versioncontrol video vim vimrc walk warren work workouts yapc yapcna2007 yoga youtube

A R C H I V E S

(3)
(1)
(3)
(2)
(7)
(15)
(16)
(25)
(3)
(4)
(2)
(4)
(11)
(1)
(1)
(3)
(2)
(2)
(10)
(5)
(2)
(3)
(4)
(9)
(21)
(3)
(3)
(1)
(6)
(4)
(1)
(4)
(3)
(2)
(1)


    Is Kent Cowgill Online?
    View Kent Cowgill's profile on LinkedIn
    Add to Technorati Favorites

    Recent Entries...

    Re: Catching up through week 7

    testing video ...

    Re: Porting a non-Moose object to Moose

    Wow, look what I found, greedy genius ...

    Re: Porting a non-Moose object to Moose

    Kevin, You're right, that does seem a little confusing. ...

    Re: Porting a non-Moose object to Moose

    Wait. I'm confused. Moose isn't the tool to reach for. So...

    Re: Porting a non-Moose object to Moose

    You should switch to MooseX::Types to declare your Typed and...

    Porting a non-Moose object to Moose

    I'm currently working with a lot of legacy code in an envi...

    Testing strategy for mocking code

    I keep finding myself using the following idiom for writing ...

    Re: Library Woes on OSX

    Have you considered changing your hosts file so it connects ...

    Re: Library Woes on OSX

    Right now the tests for Device::USB are failing. I've turne...

    Re: Library Woes on OSX

    What's the USB device you are trying to connect?...

    weblog | `web·lôg -läg |
    noun
    Another term for BLOG
    ORIGIN 1990s: from web in the sense [World Wide Web] and log in the sense [regular record of incidents.]
    blog | bläg |
    noun
    A web site on which an individual or group of users produces an ongoing narrative.
    ORIGIN a shortening of WEBLOG.

    Porting a non-Moose object to Moose

    Kent Cowgill

    I'm currently working with a lot of legacy code in an environment where the other developers haven't been brought up to speed on things like Moose just yet. I've been tasked with writing some modules in support of this legacy code on a legacy platform - so Moose probably isn't the first choice of tools to reach for.

    The module I created is a lightweight wrapper around PDF::API2 that handles a very specific case - adding an image to an existing PDF file. Naturally, Moose is installed on my laptop, so after creating a recent module in older style perl with a hash based object I decided to re-implement it in Moose.

    The first comparison I'll look at is object instantiation.

    use constant ARGS => qw/pdf_template image new_filename/;

    sub new {
      my( $class, $arg_ref ) = @_;
      
      my( $pdf_template, $image_file, $new_filename )
        = ref $arg_ref eq 'HASH'
          ? @{ $arg_ref }{ ( ARGS ) }
          : ( $arg_ref );

      my $self = {};
      bless $self, $class;
      $self->_clear_saved;
      
      die "Can't read PDF template - $!" unless $pdf_template && -r $pdf_template;

      $self->_set_pdf( PDF::API2->open( $pdf_template ) );
      $self->add_image( $image_file ) if $image_file;
      $self->save( $new_filename ) if $image_file && $new_filename;

      return $self;
    }

    sub _set_pdf {
      my( $self, $pdf ) = @_;
      die "Invalid PDF object" unless $pdf && ( ref $pdf ) =~ /^PDF::API2/;
      $self->{pdf} = $pdf;
      $self->_set_page( $self->_load_page );
      $self->_set_gfx( $self->_load_gfx );
      $self->_set_dimensions( $self->_load_dimensions );
      return;
    }

    There's really just a few things to point out here.

    I've designed the object so that it will either accept a single string as an argument, or a hashref containing key => value pairs of the pieces of data used to setup the object; in this case a PDF template filename, an image filename, and a new filename to save a resultant file as. To make this module as easy as possible to use, I have it setup so that if all arguments are passed in the constructor, the object knows enough about what's needed from it and does everything - even saves the new file.

    I've included the _set_pdf() method because that one is always called for my definition of a successful object instantiation. As you can see, once it sets the private object member {pdf} to the new PDF::API2 object passed in, it also sets a few other object member data based on the PDF::API2 object.

    After setting these in _set_pdf(), the code checks to see if there's an image file and a new filename. We'll get to that part later.

    One way to create the analog to the above code using Moose :

    use Moose;
    use Moose::Util::TypeConstraints;

    has 'pdf_template' => (
      is => 'rw',
      isa => 'Str',
      required => 1
    );

    has 'image_file' => (
      is => 'rw',
      isa => 'Str'
    );

    has 'new_filename' => (
      is => 'rw',
      isa => 'Str'
    );

    has 'image' => (
      is => 'rw',
      isa => 'PDF::API2::Resource::XObject::Image::JPEG'
    );

    subtype 'MyPDF'
      => as 'PDF::API2';
      
    coerce 'MyPDF'
      => from 'Str'
      => via { PDF::API2->open( $_ ) };
      
    has 'pdf' => (
      is => 'ro',
      isa => 'MyPDF',
      coerce => 1,
      lazy_build => 1,
    );

    sub _build_pdf { shift->pdf_template }

    sub BUILD {
      my $self = shift;

      if( my $image = $self->image_file ){
        $self->image( $image );
        if( my $filename = $self->new_filename ){
          $self->save( $filename );
        }
      }
    }

    The first item of interest is that I'm letting Moose::Util::TypeConstriants handle the coercion of a string (the PDf filename) to a PDF::API2 object. I'm also setting the pdf attribute to lazy_build. A little more on that later.

    Additionally - for the rest of the attributes, most of the work is done for me by Moose - I only need to tell it what attributes my class is going to have, and Moose does all the setting and type checking for me.

    Notice there's no new() subroutine - that's because Moose takes care of creating a default constructor, which will take care of parsing the argument(s) to the constructor for us.

    Because I am creating a literal translation of the previous object in Moose , I decided to give it the exact same behavior. I originally started adding the extra functionality to the constructor by creating an after() modifier, but that had a couple of problems - the first of which was the fact that I could no longer follow the Moose best practice of making the class immutable .

    I also ran into an issue using after() with deep recursion - notice how after setting the pdf attribute I use it (the pdf attribute) again to set the page attribute. This had the fun effect of calling after() again, after accessing the pdf attribute. Oops :)

    I then tried around() but that had also didn't let me set the class to be immutable. So I settled on using a BUILD() method.

    I originally had a few more calls to other attributes' setup inside my BUILD() subroutine, but Chris Prather suggested I move those pieces to lazy_build attributes , in which advice (and the accompanying documentation) I found great wisdom. The thinking is that the value for these attributes depend on another attribute - so these attributes /must/ be lazy. I've left out those definitions, but I'll get to those in a later post.

    Related Photos: perl

    Slides for my first talk posted

    Kent Cowgill

    So, I finally decided to stop putting it off and upload the slides from my testing talk onto slideshare.net. Click here to view these slides, as well as any future slides I make public.

    Unfortunately, this presentation/slide set was heavy with screencasts, which don't survive the transition to PDFs very well. I'm considering hosting the screencasts elsewhere.

    Enjoy!

    Related Photos: perl yapc

    Main Page | Login

    Do you want to buy me ? Find more gift ideas at my wishlist