class CSVDecision::Matchers::Range

Match cells against Ruby-like range expressions or their negation - e.g., 0...10 or +!a..z+.

Constants

ALNUM_RANGE

Alphanumeric range, e.g., a...z or +!a..c+.

NUMERIC_RANGE
TYPE

Range types are .. or ....

Public Class Methods

matches?(cell) click to toggle source

Match a table data cell string against a Ruby-like range expression.

(see Matcher#matches?)

# File lib/csv_decision/matchers/range.rb, line 17
def self.matches?(cell)
  if (match = NUMERIC_RANGE.match(cell))
    return range_proc(match: match, coerce: :to_numeric)
  end

  if (match = ALNUM_RANGE.match(cell))
    return range_proc(match: match)
  end

  false
end

Private Class Methods

alnum_range(negate, range) click to toggle source

Build the lambda proc for an alphanumeric range.

# File lib/csv_decision/matchers/range.rb, line 73
def self.alnum_range(negate, range)
  return ->(value) { range.include?(value) } unless negate
  ->(value) { !range.include?(value) }
end
convert(value, method) click to toggle source

Coerce the string into a numeric value if required.

# File lib/csv_decision/matchers/range.rb, line 50
def self.convert(value, method)
  method ? Matchers.send(method, value) : value
end
numeric_range(negate, range) click to toggle source

Build the lambda proc for a numeric range.

# File lib/csv_decision/matchers/range.rb, line 66
def self.numeric_range(negate, range)
  return ->(value) { range.include?(Matchers.numeric(value)) } unless negate
  ->(value) { !range.include?(Matchers.numeric(value)) }
end
range(match, coerce: nil) click to toggle source
# File lib/csv_decision/matchers/range.rb, line 55
def self.range(match, coerce: nil)
  negate = match['negate'] == Matchers::NEGATE
  min = convert(match['min'], coerce)
  type = match['type']
  max = convert(match['max'], coerce)

  [negate, type == '...' ? min...max : min..max]
end
range_proc(match:, coerce: nil) click to toggle source
# File lib/csv_decision/matchers/range.rb, line 79
def self.range_proc(match:, coerce: nil)
  negate, range = range(match, coerce: coerce)
  method = coerce ? :numeric_range : :alnum_range
  function = Range.send(method, negate, range).freeze
  Proc.new(type: :proc, function: function)
end
range_re(value) click to toggle source

Range expression looks like 0...10 or a..z. Can also be negated - e.g., +! 0..10+ or +!a..z+.

# File lib/csv_decision/matchers/range.rb, line 35
def self.range_re(value)
  Matchers.regexp(
    "(?<negate>#{NEGATE}?)\\s*(?<min>#{value})(?<type>#{TYPE})(?<max>#{value})"
  )
end

Public Instance Methods

matches?(cell) click to toggle source

Ruby-like range expressions or their negation - e.g., 0...10 or +!a..z+.

@return (see Matcher#matches?)

# File lib/csv_decision/matchers/range.rb, line 90
def matches?(cell)
  Range.matches?(cell)
end