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";
}