The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Data::Predicate::Predicates

SYNOPSIS

  use Data::Predicate::Predicates qw(:all);
  # we also support :logic :defaults :tests as groups for imports
  
  my $predicate = p_and(p_defined(), p_is_number(), p_numeric_equals(1));
  
  $predicate->apply(1); #Returns true
  $predicate->apply(2); #Returns false
  $predicate->apply(undef); #Returns false
  $predicate->apply('a'); #Returns false
  
  my @data = (1, 2, 3, 4, undef, 'a', 5, 1);
  my $new_data = $predicate->filter(\@data);
  #New data will == [1,1]

DESCRIPTION

Try using this class first before going off & building your own Predicate.

This module is a set of useful ready built predicates. All predicates defined here use Data::Predicate::ClosurePredicate and build themselves by creating a closure and passing it into a constructor. Those which require no user input when calling the methods will be built when the class is first used. Otherwise the others have closures built on the fly to fit your needs.

If your logic is too complex for these predicates or too slow then build your own by using Data::Predicate and implementing apply() or by creating your own closure & an instance of Data::Predicate::ClosurePredicate.

All methods are prefixed with a p_ to avoid problems with other modules importing into this name space and to avoid clashes with built-in homonyms.

EXPORT OPTIONS

all

Exports all methods into your scope

logic

Imports the logic operators p_and, p_or and p_not

defaults

Imports the p_always_true and p_always_false

tests

Imports the methods not imported by logic or default tags. This means anything which is used to test a Perlism like blessed references.

SUBROUTINES/METHODS

p_and()

  p_and(p_defined(), p_is_number())->apply(1) #Returns true
  

Combine multiple predicates into one predicate instance. The code iterates through all predicates and will exit the moment one predicate returns false.

p_or()

  p_or(p_defined(), p_is_number())-apply('a') #Would return true because 'a' is defined 
  

Combine multiple predicates into one predicate instance which will return the moment one predicate in the list returns true.

p_not()

  p_or(p_defined())->apply(undef) #Returns true
  

Reverses the logic of the given predicate so the above really means return true if the object tested is undefined

p_always_true()

  p_always_true()
  

Will always return true; useful for when you just want to pass everything

p_always_false()

Will always return false; useful for when you just want to fail everything

p_defined()

  p_defined()->apply(1) #Returns true

Will only return true when the given value is defined

p_undef()

  p_undef()->apply(undef) #Returns true

Will only return true when the given value is undefined

p_is_number()

  p_is_number()->apply(1) #Returns true
  

Returns true if the given value is a number

p_blessed()

  p_blessed()->apply(bless({})) #returns true

Returns true if the given value was a blessed value.

p_isa()

  p_isa('My::Objs::Dog')->apply($dog) #Returns true if $dog was an extension of My::Objs::Dog

Returns true according to the rules of isa when called on an object. The predicate will also test to see if the object was a blessed one before calling isa.

This differs from most predicates as you must tell the method what kind of Object you are expecting. This is recorded in curried in a closure & then used during evaluation.

p_can()

  p_can('howl')->apply($dog) #Returns true if $dog had a subroutine for howl()

Returns true if the given object could respond to the given subroutine message. The predicate assumes the reference must be blessed for it to find a subroutine via a reference.

This differs from most predicates as you must tell the method what kind of subrotuine you are expecting to find. This is recorded in curried in a closure & then used during evaluation.

p_ref_type()

  p_ref_type('ARRAY')->apply([]) #Returns true if the given reference was what you originally said

Returns true if the given ref equalled the originally stated reference.

p_string_equals()

  #Assume an object called Dog with the method howl which returns a string
  p_string_equals('a')->apply('a') #returns true
  p_string_equals('a')->apply('b') #returns false
  
  #would return true if $dog had a subroutine called howl & it returned the specified string
  p_string_equals('rrroouggghh', 'howl')->apply($dog)

Applies the eq test for strings. In it's basic form you can specify a String and it will only return true if the given value eq that String.

There is a more advanced mode which lets you call a subrotuine on the given reference and then evaluate the returned value. This allows you to use this subroutine with Objects rather than having to write a custom one for basic evaluation.

p_numeric_equals()

  #Assume an object called Dog with the method age which returns a number
  p_numeric_equals(1)->apply(1) #returns true
  p_numeric_equals(1)->apply(2) #returns false
  
  #would return true if $dog had a subroutine called age & it returned the specified number
  p_numeric_equals(7, 'age')->apply($dog)

Applies the == test for numbers. In it's basic form you can specify a number and it will only return true if the given value == that number. Will also return false if it was given a String (which is passed into p_is_number())

There is a more advanced mode which lets you call a subrotuine on the given reference and then evaluate the returned value. This allows you to use this subroutine with Objects rather than having to write a custom one for basic evaluation.

p_regex()

  #Assume an object called Dog with the method howl which returns a String
  p_regex(qr/A/)->apply('Aaaa') #returns true
  p_regex(qr/A/)->apply('bA') #returns true
  p_regex(qr/A/)->apply('b') #returns false
  
  p_regex(qr/rrr/, 'howl')->apply($dog) #Returns true if the string from howl matched /rrr/

Behaves identitcally to p_string_equals() and p_numeric_equals() allowing for basic regular expression matches using a compiled regex or by supplementing it with a subroutine to run the match on. This does not apply any numeric tests since it's quite valid to regex against a number. However it will return false if the value retrieved or evaluated was undefined.

p_substring()

  p_substring('world')->apply('hello world'); #returns true
  p_substring('o')->apply('hello world'); #returns true
  p_substring('goodbye')->apply('hello world'); #returns false
  
  #Again assume our Dog object returns arrooowww
  p_substring('ooo', 'howl')->apply($dog);

This is another type of test which when looking for substrings is far more performant than using p_regex(). The logic is to use your first variable as the substring to look for in the given value. If the index is greater than -1 we return true.

In micro-benchmarks we can see a 4x improvement in speed in using the substring style predicate over using regular expressions. Substring also has the advantage that you cannot have your substring mis-interpreted as a regular expression control character e.g. a period or braces

DEPENDENCIES

Scalar::Util
Readonly

AUTHOR

Andrew Yates

LICENCE

Copyright (c) 2010 - 2010 European Molecular Biology Laboratory.

Author: Andrew Yates (ayatesattheebi - remove the relevant sections accordingly)

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright 
      notice, this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright 
      notice, this list of conditions and the following disclaimer in the 
      documentation and/or other materials provided with the distribution.
   3. Neither the name of the Genome Research Ltd nor the names of its 
      contributors may be used to endorse or promote products derived from 
      this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.