File: //usr/local/share/perl5/Text/Query.pm
#
# Copyright (C) 1999 Eric Bohlman, Loic Dachary
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version. You may also use, redistribute and/or modify it
# under the terms of the Artistic License supplied with your Perl
# distribution
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
#
#
# $Header: /usr/local/cvsroot/Text-Query/lib/Text/Query.pm,v 1.3 1999/06/16 10:35:44 loic Exp $
#
package Text::Query;
use strict;
use vars qw($VERSION);
$VERSION = "0.07";
use Carp;
sub new {
my($class) = shift;
my($self) = {};
bless $self,$class;
if(@_ % 2) {
my($qstring) = shift;
$self->configure(@_);
return defined($qstring) ? $self->prepare($qstring, @_) : $self;
} else {
$self->configure(@_);
return $self;
}
}
sub configure {
my($self, %args) = @_;
$self->{-verbose} = $args{-verbose} || 0 if(!defined($self->{-verbose}));
my(%defconfigs) = (
simple_text =>
{ -parse => 'Text::Query::ParseSimple',
-build => 'Text::Query::BuildSimpleString',
-optimize => 'Text::Query::Optimize',
-solve => 'Text::Query::SolveSimpleString'
},
advanced_text =>
{ -parse => 'Text::Query::ParseAdvanced',
-build => 'Text::Query::BuildAdvancedString',
-optimize => 'Text::Query::Optimize',
-solve => 'Text::Query::SolveAdvancedString'
},
);
my $default=(defined $args{-mode})?$args{-mode}:'simple_text';
my($key);
foreach $key (keys(%{$defconfigs{$default}})) {
my($package) = $args{$key} ? $args{$key} : $defconfigs{$default}{$key};
my($load) = !exists($self->{'packages'}{$key}) || $self->{'packages'}{$key} ne $package;
if($load) {
$self->{$key} = $self->loader($package);
$self->{$key}->{-verbose} = $self->{-verbose};
warn("loaded $package => $self->{$key}") if($self->{-verbose});
$self->{'packages'}{$key} = $package;
}
}
$self->{-parse}->{-build} = $self->{-build};
}
sub loader {
my($self, $package) = @_;
eval "package Text::Query::_firesafe; require $package";
if ($@) {
my($advice) = "";
if($@ =~ /Can't find loadable object/) {
$advice = "Perhaps $package was statically linked into a new perl binary."
."\nIn which case you need to use that new perl binary."
."\nOr perhaps only the .pm file was installed but not the shared object file."
} elsif ($@ =~ /Can't locate.*?.pm/) {
$advice = "Perhaps the $package perl module hasn't been installed\n";
}
croak("$package failed: $@$advice\n");
}
my($object);
$object = eval { $package->new() };
croak("$@") if(!defined($object));
return $object;
}
sub matchexp {
my($self) = @_;
return $self->{matchexp};
}
sub matchstring {
my($self) = @_;
return $self->{-build}->matchstring();
}
#
# Parse interface
#
sub prepare {
my($self) = shift;
$self->{matchexp} = $self->{-optimize}->optimize($self->{-parse}->prepare(@_));
return $self;
}
#
# Solve interface
#
sub match {
my($self) = shift;
croak("solve undefined") if(!$self->{-solve});
return $self->{-solve}->match($self->{matchexp}, @_);
}
sub matchscalar {
my($self) = shift;
croak("solve undefined") if(!$self->{-solve});
return $self->{-solve}->matchscalar($self->{matchexp}, @_);
}
#
# Accessors
#
sub build {
my($self) = shift;
return $self->{-build};
}
sub parse {
my($self) = shift;
return $self->{-parse};
}
sub solve {
my($self) = shift;
return $self->{-solve};
}
sub optimize {
my($self) = shift;
return $self->{-optimize};
}
1;
__END__
=head1 NAME
Text::Query - Query processing framework
=head1 SYNOPSIS
use Text::Query;
# Constructor
$query = Text::Query->new([QSTRING] [OPTIONS]);
# Methods
$query->prepare(QSTRING [OPTIONS]);
$query->match([TARGET]);
$query->matchscalar([TARGET]);
=head1 DESCRIPTION
This module provides an object that matches a data source
against a query expression.
Query expressions are compiled into an internal form when a new object is created
or the C<prepare> method is
called; they are not recompiled on each match.
The class provided by this module uses four packages to process the query.
The query parser parses the question and calls a query expression
builder (internal form of the question). The optimizer is then called
to reduce the complexity of the expression. The solver applies the expression
on a data source.
The following parsers are provided:
=over 4
=item Text::Query::ParseAdvanced
=item Text::Query::ParseSimple
=back
The following builders are provided:
=over 4
=item Text::Query::BuildAdvancedString
=item Text::Query::BuildSimpleString
=back
The following solver is provided:
=over 4
=item Text::Query::SolveSimpleString
=item Text::Query::SolveAdvancedString
=back
=head1 EXAMPLES
use Text::Query;
my $q=new Text::Query('hello and world',
-parse => 'Text::Query::ParseAdvanced',
-solve => 'Text::Query::SolveAdvancedString',
-build => 'Text::Query::BuildAdvancedString');
die "bad query expression" if not defined $q;
print if $q->match;
...
$q->prepare('goodbye or adios or ta ta',
-litspace => 1,
-case => 1);
#requires single space between the two ta's
if($q->match($line)) {
#doesn't match "Goodbye"
...
$q->prepare('"and" or "or"');
#quoting operators for literal match
...
$q->prepare('\\bintegrate\\b', -regexp => 1);
#won't match "disintegrated"
=head1 CONSTRUCTOR
=over 4
=item new ([QSTRING] [OPTIONS])
This is the constructor for a new Text::Query object. If a C<QSTRING> is
given it will be compiled to internal form.
C<OPTIONS> are passed in a hash like fashion, using key and value pairs.
Possible options are:
B<-parse> - Package name of the parser. Default is Text::Query::ParseSimple.
B<-build> - Package name of the builder. Default is Text::Query::Build.
B<-optimize> - Package name of the optimizer. Default is Text::Query::Optimize.
B<-solve> - Package name of the solver. Default is Text::Query::Solve.
B<-mode> - Name of predefined group of packages to use. Options are
currently C<simple_text> and C<advanced_text>.
These options are handled by the C<configure> method.
All other options are passed to the parser C<prepare> function.
See the corresponding manual pages for a description.
If C<QSTRING> is undefined, the prepare function is not called.
The constructor will croak if a C<QSTRING> was supplied and had
illegal syntax.
=back
=head1 METHODS
=over 4
=item configure ([OPTIONS])
Set the C<parse>, C<build>, C<optimize> or C<solve> packages. See the
C<CONSTRUCTOR> description for explanations.
=item prepare (QSTRING [OPTIONS])
Compiles the query expression in C<QSTRING> to internal form and sets any
options (same as in the constructor). C<prepare> may be used to change
the query expression and options for an existing query object. If
C<OPTIONS> are omitted, any options set by a previous call to
C<prepare> are persistent.
The optimizer (-optimize) is called with the result of the parser (-parse).
The parser uses the builder (-build) to construct the internal form.
This method returns a reference to the query object if the syntax of the
expression was legal, or croak if not.
=item match ([TARGET])
Calls the match method of the solver (-solve).
=item matchscalar ([TARGET])
Calls the matchscalar method of the solver (-solve).
=back
=head1 SEE ALSO
Text::Query::ParseAdvanced(3),
Text::Query::ParseSimple(3),
Text::Query::BuildSimpleString(3),
Text::Query::BuildAdvanedString(3),
Text::Query::SolveSimpleString(3),
Text::Query::SolveAdvancedString(3),
Text::Query::Build(3),
Text::Query::Parse(3),
Text::Query::Solve(3),
Text::Query::Optimize(3)
=head1 AUTHORS
Eric Bohlman (ebohlman@netcom.com)
Loic Dachary (loic@senga.org)
=cut
# Local Variables: ***
# mode: perl ***
# End: ***