class CSVDecision::Matchers::Symbol

Match cell against a symbolic expression - e.g., :column, > :column. Can also call a Ruby method pn the column value - e.g, .blank? or !.blank?

Constants

COMPARE
EQUALITY

These procs compare one input hash value to another, and so do not coerce numeric values. Note that we do not check +hash.key?(symbol)+, so a nil value will match a missing hash key.

SYMBOL_COMPARATORS
SYMBOL_COMPARE

Column symbol comparison - e.g., > :column or != :column. Can also be a method call - e.g., .present? or .blank?

SYMBOL_COMPARE_RE

Symbol comparision regular expression.

Public Class Methods

matches?(cell) click to toggle source

@param (see Matchers::Matcher#matches?) @return (see Matchers::Matcher#matches?)

# File lib/csv_decision/matchers/symbol.rb, line 132
def self.matches?(cell)
  return false unless (match = SYMBOL_COMPARE_RE.match(cell))

  comparator = match['comparator']
  type = match['type']
  return false if comparator.nil? && type.nil?

  comparator_type(comparator: comparator || '=', type: type, name: match['name'].to_sym)
end

Private Class Methods

comparator_type(comparator:, name:, type:) click to toggle source
# File lib/csv_decision/matchers/symbol.rb, line 118
def self.comparator_type(comparator:, name:, type:)
  if type == ':'
    comparison(comparator: comparator, name: name)

  # Method call - e.g, .blank? or !.present?
  # Can also take the forms: := .blank? or !=.present?
  else
    method_call(comparator: comparator, name: name, type: type || '.')
  end
end
compare_proc(sym) click to toggle source
# File lib/csv_decision/matchers/symbol.rb, line 36
def self.compare_proc(sym)
  proc do |symbol, value, hash|
    Matchers.compare?(lhs: value, compare: sym, rhs: hash[symbol])
  end
end
comparison(comparator:, name:) click to toggle source

E.g., > :col, we get comparator: >, name: col

# File lib/csv_decision/matchers/symbol.rb, line 79
def self.comparison(comparator:, name:)
  function = COMPARE[comparator]
  Matchers::Proc.new(type: :symbol, function: function[name], symbols: name)
end
method_call(comparator:, name:, type:) click to toggle source

E.g., !.nil?, we get comparator: !, name: nil?, type: .

# File lib/csv_decision/matchers/symbol.rb, line 86
def self.method_call(comparator:, name:, type:)
  negate = negated_comparator?(comparator: comparator)
  return false if negate.nil?

  # Check for double negation - e.g., != !blank?
  negate = type == '!' ? !negate : negate
  method_function(name: name, negate: negate)
end
method_function(name:, negate:) click to toggle source

E.g., !.nil?, we get comparator: !, name: nil?

# File lib/csv_decision/matchers/symbol.rb, line 109
def self.method_function(name:, negate:)
  # Allowed Ruby method names are a bit stricter than allowed decision table column names.
  return false unless METHOD_NAME_RE.match?(name)

  function = COMPARE[negate ? '!.' : '.']
  Matchers::Proc.new(type: :proc, function: function[name])
end
method_proc(negate:) click to toggle source
# File lib/csv_decision/matchers/symbol.rb, line 48
def self.method_proc(negate:)
  if negate
    proc { |symbol, value| !value_method(value, symbol) }
  else
    proc { |symbol, value|  value_method(value, symbol) }
  end
end
negated_comparator?(comparator:) click to toggle source
# File lib/csv_decision/matchers/symbol.rb, line 96
def self.negated_comparator?(comparator:)
  # Do we have an equality comparator?
  if EQUALS_RE.match?(comparator)
    false

  # If do not have equality, do we have inequality?
  elsif INEQUALITY_RE.match?(comparator)
    true
  end
end
value_method(value, method) click to toggle source
# File lib/csv_decision/matchers/symbol.rb, line 43
def self.value_method(value, method)
  value.respond_to?(method) && value.send(method)
end

Public Instance Methods

matches?(cell) click to toggle source

@param (see Matcher#matches?) @return (see Matcher#matches?)

# File lib/csv_decision/matchers/symbol.rb, line 144
def matches?(cell)
  Symbol.matches?(cell)
end