class StructureMatch::Comparator
Comparator
handles the actual comparison operations that StructureMatch
uses.
Public Class Methods
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.
# 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
Public Instance Methods
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)
# 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
Private Instance Methods
# File lib/structurematch.rb, line 95 def _t(v) v ? @score || 1 : -1 end