An Easy Way
There are a few simple ways of doing it. You could just have a method that calls the attributes that you want to search, something like this:
sub search_me {
my $self = shift;
my ($search) = @_;
my @results = ();
foreach my $attr ( qw/title message author/ ) {
if ( $self->$attr() =~ m/$search/ ) {
push(@results, { 'name' => $attr, 'value' => $self->$attr() }
+);
}
}
return @results;
}
Which would return something like:
$VAR1 = [
{
'name' => 'title',
'value' => 'My title xyzzy'
}
];
But that's no fun! You'd have to change that method every time you changed your Note class. Plus, this is an excellent chance to do something amusing with Moose attributes! What if you could just mark an attribute as searchable, then have a method that goes through and searches those attributes?
A Harder Way
Well, you could define a 'Searchable' trait, like so:
package Note::Attribute::Trait::Searchable {
use Moose::Role;
Moose::Util::meta_attribute_alias('Searchable');
}
Then have a role that uses that trait to search through your attributes, like so:
package Note::Searchable {
use Moose::Role;
sub search {
my $self = shift;
my ($search_string) = @_;
my $meta = $self->meta;
my @results;
# Go through all attributes on your object
foreach my $attribute ( map { $meta->get_attribute($_) }
sort $meta->get_attribute_list )
{
# Skip attributes unless they're specifically searchable
unless ( $attribute->does('Note::Attribute::Trait::Searcha
+ble') ) {
next;
}
my $reader = $attribute->get_read_method();
my $value = $self->$reader;
if ( $value =~ m/$search_string/ ) {
push( @results,
{ 'name' => $attribute->name, 'value' => $value }
+);
}
}
return @results;
}
}
Then finally, in your class, you mark the traits you want as searchable:
package Note {
use Moose;
with 'Note::Searchable';
# We want to search title, message, and author
has 'title' => ( is => 'rw', isa => 'Str', traits => [qw/Searcha
+ble/] );
has 'message' => ( is => 'rw', isa => 'Str', traits => [qw/Searcha
+ble/] );
has 'author' => ( is => 'rw', isa => 'Str', traits => [qw/Searcha
+ble/] );
# We don't want to search "other"
has 'other' => ( is => 'rw', isa => 'Str' );
no Moose;
}
Then this code returns the same result:
my $note = Note->new(
title => 'My title xyzzy',
message => 'My message',
author => 'me'
);
use Data::Dumper;
say Dumper [ $note->search('xyzzy') ];
...returns...
$VAR1 = [
{
'name' => 'title',
'value' => 'My title xyzzy'
}
];
There's a lot more up-front work, and it's probably overkill for what you want to do. Still, now you can add and delete new attributes as you please, and they'll be searched properly so long as they're marked searchable!
|