Class: StructureMatch::Comparator

Inherits:
Object
  • Object
show all
Defined in:
lib/structurematch.rb

Overview

Comparator handles the actual comparison operations that StructureMatch uses.

Instance Method Summary collapse

Constructor Details

#initialize(op) ⇒ Comparator

Comparators are initialized using a hash with the following structure:

{
  "op" => "operation"
  "match" => "The value that the operation should work with"
  # Optional, defaults to 1 or the length of the matched thing (if array-ish)
  "score" => 1 # The score adjustment a match here gives.
}

Comparator knows about the following tests:

“==”,“!=”,“>”,“<”,“>=”,“<=”

The matching tests from Comparable.

“and”

Returns true if all the submatches return true, false otherwise.

“or”

Returns true if one of the submatches return true, false otherwise. “and” and “or” require that “match” be an array of hashes that Comparator.new can process.

“not”

Inverts its submatch. Requires that “match” be a hash that Comparator.new can process.

“range”

Tests to see if a value is within a range of values. Requires that “match” be a two-element array whose elements can be used to construct a Range.

“regex”

Tests to see if a value matches a regular expression. “match” must be a regex. The score on a matching regex will be the length of the MatchData by default, and the returned value will be matching MatchData.

“member”

Tests to see if a value is within an array. “match” must be the array. If an array is passed to a member test, then scoring and the returned value will be the set intersection of the match array and the tested array.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/structurematch.rb', line 36

def initialize(op)
  raise "#{op.inspect} must be a Hash" unless op.kind_of?(Hash)
  unless ["==","!=",">","<",">=","<=","and","or","not","range","regex","member"].member?(op["op"])
    raise "Operator #{op["op"]} is not one that Comparator knows how to use!"
  end
  raise "#{op.inspect} must have a match key" unless op.has_key?("match")
  @op = op["op"].dup.freeze
  @match = op["match"]
  @score = op["score"].to_i
  @score = nil if @score == 0
  case @op
  when "and","or"
    raise "#{op.inspect} match key must be an array of submatches" unless @match.kind_of?(Array)
    @match.map!{|m|Comparator.new(m)}
  when "not"
    @match = Comparator.new(@match)
  when "range"
    raise "#{@match.inspect} is not a two-element array" unless @match.kind_of?(Array) && @match.length == 2
    @match = Range.new(@match[0],@match[1])
  when "regex" then @match = Regexp.compile(@match)
  end
end

Instance Method Details

#test(v = true) ⇒ Object

Takes a single argument which is the value to be tested.

It returns a two-element array:

[score,val]
score

the score adjustment factor for this test

val

the value that test returns. It is usually the value that was passed in, except for regular expressions (which return the MatchData) and array & array comparisons performed by member (which returns the set intersection of the arrays)



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/structurematch.rb', line 67

def test(v=true)
  case @op
  when "and" then [_t(@match.all?{|m|m.test(v)[0] > 0}),v]
  when "or" then [_t(@match.any?{|m|m.test(v)[0] > 0}),v]
  when "not" then [_t(@match.test(v)[0] < 0),v]
  when "range" then [_t(@match === v),v]
  when "regex"
    r = @match.match(v)
    [r.nil? ? -1 : @score || r.length, r]
  when "member"
    if v.kind_of?(Array)
      r = @match & v
      [r.empty? ? -1 : @score || r.length, r]
    else
      [_t(@match.member?(v)),v]
    end
  when "==" then [_t(@match == v),v]
  when "!=" then [_t(@match != v),v]
  when ">" then [_t(v > @match),v]
  when "<" then [_t(v < @match),v]
  when ">=" then [_t(v >= @match),v]
  when "<=" then [_t(v <= @match),v]
  else
    raise "Comparator cannot handle #{@op}"
  end
end