Skip to content

Doodling with Moose (part 1)

March 12, 2008
tags: , , ,

While perusing my RSS I came across Doodle in an article at Ruby Inside

event = Event "Festival" do
  date '2008-04-01'
  place "The muddy field"
  place "Beer tent" do
    event "Drinking"
  end
end

Looks good hey. But it got even more interesting when I saw how the class is defined…

require 'rubygems'
require 'date'
require 'pp'
require 'doodle'

class Location  String
  has :events, :init => [], :collect => :Event
end

class Event
  # or if you want to inherit from another class
  include Doodle::Helper
  include Doodle::Factory

  has :name, :kind => String
  has :date do
    kind Date
    default { Date.today }
    must 'be >= today' do |value|
      value >= Date.today
    end
    from String do |s|
      Date.parse(s)
    end
  end
  has :locations, :init => [], :collect => {:place => "Location"}
end

This looks a lot like Moose… a Perl Object system.

Anyway been meaning to get into Moose for ages now and so far only used it to subclass an old library I had.
So as a good way of getting me feet dirty I went ahead and done the above Doodle stuff in Moose….

my $event = Event->new( 
    name  => 'Festival',
    date  => '2008-04-01', 
    locations => [ 
      { place=>'The muddy field' }, 
      { place=>'Beer Tent',events=>['Drinking'] } 
    ],
);

I’m not sure if the Doodle example is a bit contrived but I decided to replicate how the objects worked in exactly same way. However I slightly amended the contructor because it was i) simpler to do this way in Perl! & ii) Probably more accurate as an interface spec!! (changes are… locations & events are clearly defined as a list of things).

package Location;
use Moose;

has 'name'  => ( is => 'rw', isa => 'Str' );
has 'event' => ( is => 'rw', isa => 'ArrayRef[Object]');


package Event;
use Moose;
use Moose::Util::TypeConstraints;
require DateTime;

subtype 'DateTime'
    => as 'Object'
    => where { $_->isa( 'DateTime' ) };

subtype 'EventDate'
    => as 'DateTime'
    => where { $_ >= DateTime->now }
    => message { 'date must be >= today' };

subtype 'Places'
    => as 'ArrayRef[Object]';
            
coerce 'EventDate'
    => from 'Str'
    => via { 
        # below should be DateManip (some strange formatting bug in syntaxhighlighter!)
        require DateTime::Format::dateManip;
        DateTime::Format::dateManip->parse_datetime( $_ );
    };

coerce 'Places'
    => from 'ArrayRef[HashRef]'
    => via {
        my $array_ref = [];
        
        # Go thru all locations in Places
        for my $location ( @{ $_ } ) {
            # events assigned to this location
            my $events_ref = [];
            @$events_ref = map { Event->new( name => $_ )  } @{ $location->{events} }
                 if exists $location->{events};
                    
            push @$array_ref, 
                Location->new( name => $location->{place}, event => $events_ref ) }
        
        return $array_ref;
    };
    
has 'name'  => ( is => 'rw', isa => 'Str' );

has 'date'  => (
   is          => 'rw', 
   isa        => 'EventDate', 
   coerce   => 1, 
   default  => sub { DateTime->now } );
                 
has 'locations' => ( 
   is         => 'rw', 
   isa       => 'Places', 
   coerce  => 1 );
                     

And there we go. The Moose example produced twice as many lines! However this isn’t the fault of Moose but mainly because I had to manually format stuff due to issues with the WordPress syntax highlighter with the Perl code ;-(

More in part 2.

11 Comments leave one →
  1. March 20, 2008 9:34 pm

    Cool post, it’s interesting to see how Moose and Ruby compare.

    > The Moose example produced twice as many lines!

    I think actually most of the code size difference seems to be in the coercion. Of course it could probably be golfed down a bit, but that kills maintainability so probably not worth it.

    The “Collector” feature in Doodle actually looks very cool, and would make an excellent Moose extension (MooseX:: module).

  2. March 24, 2008 11:01 am

    Hi Stevan.

    Many thanks for the comment and keep up the excellent work on Moose.

    Yes the “Collector” feature in Doodle does look interesting and so the coerce on ‘Places’ required extra lines in this Moose example to mimic it. And I totally agree with u about the coercions & code size… it shouldn’t be changed because they’re beautifully declarative.

    When I get around to “Part 2” (yeah… dream on!) I was hoping to mention that they might be a “Collector” equivalent in Moose but u’ve now answered that question ;-( Still perhaps a MooseX Collector module is around the corner from one of us!

    /I3az/

    PS. I did first look at Moose back in 2006. However at the time I had just initiated a style guide policy using PBP for all our code and so was using Class::Std everywhere. Anyway got some big projects with a new startup and I plan to use Moose from now on in.

  3. March 24, 2008 1:38 pm

    Barry,

    You should come by #moose on irc.perl.org and discuss a MooseX:: collector module of some kind. There were several other people interested in a more automagic coercion solution, and the collector idea would fit in right nicely with this I think.

    – Stevan

  4. March 30, 2008 2:18 pm

    Hi Stevan,

    Yes I look forward to popping into #moose IRC in the near future. After my last comment I did subscribe to the Moose mailing list so perhaps u will see my head pop up there pretty soon.

    This collector doesn’t (necessarily) scratch an immediate production itch for me but there’s plenty of other Moose stuff that I need to get my teeth into.

    Barry

    PS. Did have a quick look at how Doodle collector worked. From what I can see it uses an eval string to do all its magic. Hmmm… not sure if this is the route u would want to use in Moose?

  5. March 30, 2008 3:33 pm

    Barry,

    No I didn’t look too closely at the implementation of the collectors. Ruby people don’t seem to have a problem with “sting eval as metaprogramming” as much as the Perl community does.

    It seems to me that it’s primarily just “inline” coercions, rather then the more global type centric coercions that Moose offers.

    – Stevan

  6. June 19, 2008 3:39 pm

    Somehow i missed the point. Probably lost in translation 🙂 Anyway … nice blog to visit.

    cheers, Enquire!!!!

  7. August 15, 2008 7:12 am

    “String eval as metaprogramming” – problem with Ruby in this regard is that you run into the “You must use string eval” wall surprisingly quickly. There’s always people who’ll tell you that you should use string eval because it’s faster, but they’re just idiots. Some of the stuff in Ruby 1.9 means that Ruby metaprogrammers will hit that wall a good deal later, but it’s still problematic.

  8. February 20, 2009 9:39 pm

    Hi Piers,

    Just want to to say I really enjoyed your MooseX::Declare presentation at the London Perl Mongers tech talk last night.

    Unfortunately didn’t get chance to introduce myself because had to leave straight after the event. By the sounds of your rekindled joy for using MooSex… sorry Perl 😉 …. then we may still bump into each other at some point in the near future.

    regards Barry

  9. February 24, 2009 8:58 am

    Hi,

    Most rubyists do subscribe to the notion that ‘eval is evil’ but as Piers points out there are some limitations in ruby 1.8.6 that sometimes force you to use it.

    doodle uses string eval only to get around a limitation of ruby 1.8.6’s define_method which does not allow blocks as arguments. Otherwise, there’s nothing in the collector code that couldn’t be done cleanly (though the current implementation pragmatically takes advantage of the fact that the line has already been crossed). The upcoming revision of doodle for ruby 1.8.7 and 1.9.1 will not have to use any string evals.

    Regards,
    Sean

  10. February 24, 2009 1:10 pm

    Hi Sean,

    I suppose there is a good reason why “eval” sounds and looks so similar to “evil” 😉 .    But yes there are times when you just have to be “evil” with your code!!

    Keep up the good work on Doodle. It could be a useful module to have in ones toolbox when switching between Perl & Ruby code in the future!

    regards Barry

Trackbacks

  1. Perl Coding School » Blog Archive » perl code [2008-03-13 00:30:09]

Leave a comment