Hey,

I've read through the MooseX::Types docs many times, but I can't quite seem to get this to work. I've never worked with MooseX::Types before. Could someone show me what I'm missing?

I'm trying to extend MooseX::Types::Set::Object to add two methods (search and find) to allow getting subsets (or objects) based on search criteria. Here's what I have so far, and it doesn't work. I don't really have any broken code to put in here in place of the "???" (because broken implies something even close to working). I tried a bunch of stuff with "extends", "duck_type", "coerce", and "subtype", before realizing I was just sort of flailing around =) I *think* I'm supposed to be using some kind of role (to apply methods only?) but I don't understand the manual or cookbook at all in this area.

The desired functionality:
- define a set of objects as a moose object property.
- use my $results = $obj->set->search(...criteria...) to find a proper subset. - use my $obj = $obj->set->find(...criteria...) to find the first matching object (or undef)

If I get it working, I'm happy to submit a doc patch =)

Thanks,

-Sir

   package MooseX::Types::Set::Object::Searchable;
   use Moose;
   use Moose::Util::TypeConstraints;

   ############################################################
   ### I have absolutely no idea what to put here... I've tried
   ### various things with 'extends', 'duck_type', 'subtype'
   ### and others, but ...
   ############################################################

   ???  somehow I should be extending MooseX::Types::Set::Object here ...

   ############################################################
   ### EOCONFUSION
   ############################################################

   ### Returns all matches (a subset) or an empty set.
   sub search {
       my $self = shift;

       my %args;
       if (scalar(@_) == 1 and ref($_[0]) eq 'HASH') {
          %args = %{$_[0]};
       } else {
          %args = @_;
       }

       ### Create a new set object.  It should be empty by default
   (since it has
       ### nothing unique to itself), but clear it explicitly anyway.
       my $results = $self->unique($self);
       $results->clear();

       ### Loop through the elements in the current set, pushing
   matches into the
       ### result set.
       foreach my $obj ($self->elements) {
          if (_obj_matches_properties($obj, \%args)) {
             $results->insert($obj);
          }
       }

       ### Always returns a Set::Object thing, meaning we can do chaining.
       return $results;
   }

   ### Returns the first matched object or undef.
   sub find {
       my $self = shift;

       my %args;
       if (scalar(@_) == 1 and ref($_[0]) eq 'HASH') {
          %args = %{$_[0]};
       } else {
          %args = @_;
       }

       ### Loop through the elements in the current set, returning the
   first one
       ### that matches completely.
       foreach my $obj ($self->elements) {
          if (_obj_matches_properties($obj, \%args)) {
             return $obj;
          }
       }

       return undef;
   }

   ### Check properties of an object (recursively).
   sub _obj_matches_properties {
       my $obj = shift;
       my $opt = shift;

       foreach my $field (keys(%$opt)) {
          ### If we're matching against a hashref, then it's an object
   with proper
          if (ref($opt->{$field}) eq 'HASH') {
             if (not _obj_matches_properties($obj->$field,
   $opt->{$field})) {
                return 0;
             }
          } else {
             my $opt_version = $opt->{$field};
             my $obj_version = $obj->$field;

             if (not defined $opt_version and not defined $obj_version) {
                ### Do nothing, this counts as a match.
             } elsif (not defined $opt_version or not defined
   $obj_version) {
                ### Only one is undef ... no match.
                return 0;
             } elsif ($opt_version ne $obj_version) {
                return 0;
             }
          }
       }
       return 1;
   }

   1;

The test script (currently broken):

   #!/usr/cisco/bin/perl
   ### Define a package with a Set::Object::Searchable type.
   package Foo;
   use Moose;

   ### My module
   use MooseX::Types::Set::Object::Searchable;

   has set => (
       isa=>'Set::Object::Searchable',
       is => 'rw',
       coerce => 1,
   );

   package main;

   my $foo = Foo->new(set => [
       {a => '123', b => 'abc'},
       {a => '456', b => 'abc'},
       {a => '789', b => 'def'},
   ]);

   print "Original: \n";
   foreach my $el ($foo->set->elements) {
       print "\t", $el->{a}, "\n";
   }

   my $matches = $foo->set->search(a=>'123');

   print "Matching subset: \n";
   foreach my $el ($matches->elements) {
       print "\t", $el->{a}, "\n";
   }

Reply via email to