# Symbol predicates. # Copyright 2007, 2008, 2009, 2010 Kevin Ryde # This file is part of Chart. # # Chart 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 3, or (at your option) any later version. # # Chart 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 Chart. If not, see . package App::Chart::Sympred; use 5.005; use strict; use warnings; use Carp; use Scalar::Util; use List::Util; use App::Chart; =for stopwords ie Eg =head1 NAME App::Chart::Sympred -- symbol predicate objects =head1 SYNOPSIS use App::Chart::Sympred; my $sympred = App::Chart::Sympred::Suffix->new ('.AX'); $sympred->match('FOO.AX') # returns true =head1 DESCRIPTION A C object represents a predicate for use on stock and commodity symbols, ie. a test of whether a symbol has a certain suffix or similar. =head1 FUNCTIONS =over 4 =item $sympred->match ($symbol) Return true if C<$symbol> is matched by the C<$sympred> object. =item App::Chart::Sympred::validate ($obj) Check that C<$obj> is a C object, throw an error if not. =cut sub validate { my ($obj) = @_; if (! (Scalar::Util::blessed ($obj) && $obj->isa (__PACKAGE__))) { croak 'Not a symbol predicate: ' . ($obj||'undef'); } } #------------------------------------------------------------------------------ package App::Chart::Sympred::Equal; use strict; use warnings; use base 'App::Chart::Sympred'; =item App::Chart::Sympred::Equal->new ($suffix) Return a new C object which matches only the given symbol exactly. Eg. my $sympred = App::Chart::Sympred::Equal->new ('FOO.BAR') =cut sub new { my ($class, $suffix) = @_; return bless { suffix => $suffix }, $class; } sub match { my ($self, $symbol) = @_; return ($symbol eq $self->{'suffix'}); } #------------------------------------------------------------------------------ package App::Chart::Sympred::Suffix; use 5.006; use strict; use warnings; use base 'App::Chart::Sympred'; =item App::Chart::Sympred::Suffix->new ($suffix) Return a new C object which matches the given symbol suffix. Eg. my $sympred = App::Chart::Sympred::Suffix->new ('.FOO') =cut sub new { my ($class, $suffix) = @_; if ($suffix =~ /\..*\./) { # two or more dots return App::Chart::Sympred::Regexp->new (qr/\Q$suffix\E$/); } else { return bless { suffix => $suffix }, $class; } } sub match { my ($self, $symbol) = @_; return (App::Chart::symbol_suffix ($symbol) eq $self->{'suffix'}); } #------------------------------------------------------------------------------ package App::Chart::Sympred::Prefix; use strict; use warnings; use base 'App::Chart::Sympred'; =item App::Chart::Sympred::Prefix->new ($prefix) Return a new C object which matches the given symbol prefix. Eg. my $sympred = App::Chart::Sympred::Prefix->new ('^NZ') =cut sub new { my ($class, $prefix) = @_; return bless { prefix => $prefix }, $class; } sub match { my ($self, $symbol) = @_; return ($symbol =~ /^\Q$self->{'prefix'}\E/); } #------------------------------------------------------------------------------ package App::Chart::Sympred::Regexp; use strict; use warnings; use base 'App::Chart::Sympred'; =item App::Chart::Sympred::Regexp->new (qr/.../) Return a new C object which matches the given regexp pattern. Eg. my $sympred = App::Chart::Sympred::Regexp->new (qr/^\^BV|\.SA$/); =cut sub new { my ($class, $pattern) = @_; return bless { pattern => $pattern }, $class; } sub match { my ($self, $symbol) = @_; return ($symbol =~ m/$self->{'pattern'}/); } #------------------------------------------------------------------------------ package App::Chart::Sympred::Proc; use strict; use warnings; use base 'App::Chart::Sympred'; =item App::Chart::Sympred::Proc->new (\&proc) Return a new C object which calls the given C subroutine to test for a match. Eg. sub my_fancy_test { my ($symbol) = @_; return (some zany test on $symbol); } my $sympred = App::Chart::Sympred::Proc->new (\&my_fancy_test); =cut sub new { my ($class, $proc) = @_; return bless { proc => $proc }, $class; } sub match { my ($self, $symbol) = @_; return &{$self->{'proc'}} ($symbol); } #------------------------------------------------------------------------------ package App::Chart::Sympred::Any; use strict; use warnings; use base 'App::Chart::Sympred'; =item App::Chart::Sympred::Any->new ($pred,...) Return a new C object which is true if any of the given C<$pred> predicates is true. Eg. my $nz = App::Chart::Sympred::Suffix->new ('.NZ') my $bc = App::Chart::Sympred::Suffix->new ('.BC') my $sympred = App::Chart::Sympred::Any->new ($nz, $bc); =cut sub new { my ($class, @preds) = @_; foreach my $pred (@preds) { App::Chart::Sympred::validate ($pred); } return bless { preds => \@preds }, $class; } =item $pred->add ($pred,...) Add additional predicates to a C object. =cut sub add { my ($self, @newpreds) = @_; foreach my $pred (@newpreds) { App::Chart::Sympred::validate ($pred); } push @{$self->{'preds'}}, @newpreds; } sub match { my ($self, $symbol) = @_; return List::Util::first { $_->match($symbol) } @{$self->{'preds'}}; } 1; __END__ ==back