sub verify_args {
my $defaults = shift; # leave the rest of @_ intact.
# Verify that args came in pairs.
croak "Expecting key => value pairs, but got odd number of args"
if @_ % 2;
# Verify keys, ignore values.
while (@_) {
my ($var, undef) = (shift, shift);
croak "Invalid parameter: '$var'"
unless exists $defaults->{$var};
}
}
####
my %convert_defaults = (
from => 'here'
to => 'eternity'
thing => undef,
);
sub convert {
verify_args(\%convert_defaults, @_);
my %args = (%convert_defaults, @_);
...
}
##
##
package KinoSearch::Util::Class;
use KinoSearch::Util::ToolSet; # strict, warnings, Carp, etc.
use Clone 'clone';
use KinoSearch::Util::VerifyArgs qw( verify_args );
our %instance_vars = ();
sub new {
my $class = shift; # leave the rest of @_ intact.
# Clone the instance_vars hash and bless it.
$class = ref($class) || $class;
my $defaults;
{
no strict 'refs';
$defaults = \%{ $class . '::instance_vars' };
}
my $self = clone($defaults);
bless $self, $class;
# Verify argument labels.
eval { verify_args( $defaults, @_ ) };
if ($@) {
my ( $package, $filename, $line ) = caller;
die "ERROR during attempt to create object of class '$class' \n"
. " at $filename line $line:\n"
. " $@\n";
}
# Merge var => val pairs into object.
%$self = ( %$self, @_ );
$self->init_instance;
return $self;
}
sub init_instance { }
# Class method to build the %instance_vars hash
sub init_instance_vars {
my $package = shift;
no strict 'refs';
my $first_isa = ${ $package . '::ISA' }[0];
return ( %{ $first_isa . '::instance_vars' }, @_ );
}
# use to define an abstract method
sub abstract_death {
my ( undef, $filename, $line, $methodname ) = caller(1);
die "ERROR: $methodname', called at $filename line $line, is an "
. "abstract method and must be defined in a subclass.";
}
##
##
package KinoSearch::Analysis::Analyzer;
use KinoSearch::Util::ToolSet;
use base qw( KinoSearch::Util::Class );
our %instance_vars = __PACKAGE__->init_instance_vars( language => '', );
sub analyze { shift->abstract_death }
1;
##
##
package KinoSearch::Analysis::PolyAnalyzer;
use KinoSearch::Util::ToolSet;
use base qw( KinoSearch::Analysis::Analyzer );
use KinoSearch::Analysis::LCNormalizer;
use KinoSearch::Analysis::Tokenizer;
use KinoSearch::Analysis::Stemmer;
our %instance_vars = __PACKAGE__->init_instance_vars( analyzers => undef, );
sub init_instance {
my $self = shift;
my $language = $self->{language} = lc( $self->{language} );
if ( !defined $self->{analyzers} ) {
croak("Must specify either 'language' or 'analyzers'")
unless $language;
$self->{analyzers} = [
KinoSearch::Analysis::LCNormalizer->new( language => $language ),
KinoSearch::Analysis::Tokenizer->new( language => $language ),
KinoSearch::Analysis::Stemmer->new( language => $language ),
];
}
}
sub analyze {
my ( $self, $field ) = @_;
$_->analyze($field) for @{ $self->{analyzers} };
}
1;