lib/csv_decision/matchers/range.rb in csv_decision-0.0.6 vs lib/csv_decision/matchers/range.rb in csv_decision-0.0.7
- old
+ new
@@ -1,36 +1,55 @@
# frozen_string_literal: true
# CSV Decision: CSV based Ruby decision tables.
-# Created December 2017 by Brett Vickers
+# Created December 2017.
+# @author Brett Vickers <brett@phillips-vickers.com>
# See LICENSE and README.md for details.
module CSVDecision
- # Methods to assign a matcher to data cells
+ # Methods to assign a matcher to data cells.
+ # @api private
class Matchers
- # Match cell against a Ruby-like range
+ # Match cells against Ruby-like range expressions or their negation -
+ # e.g., +0...10+ or +!a..z+.
class Range < Matcher
- # Range types are .. or ...
+ # Match a table data cell string against a Ruby-like range expression.
+ #
+ # @param (see Matcher#matches?)
+ # @return (see Matcher#matches?)
+ 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
+
+ # Range types are +..+ or +...+.
TYPE = '(\.\.\.|\.\.)'
private_constant :TYPE
+ # Range expression looks like +0...10+ or +a..z+.
+ # Can also be negated - e.g., +! 0..10+ or +!a..z+.
def self.range_re(value)
Matchers.regexp(
"(?<negate>#{NEGATE}?)\\s*(?<min>#{value})(?<type>#{TYPE})(?<max>#{value})"
)
end
private_class_method :range_re
NUMERIC_RANGE = range_re(Matchers::NUMERIC)
private_constant :NUMERIC_RANGE
- # One or more alphanumeric characters
- ALNUM = '[[:alnum:]][[:alnum:]]*'
- private_constant :ALNUM
-
- ALNUM_RANGE = range_re(ALNUM)
+ # Alphanumeric range, e.g., +a...z+ or +!a..c+.
+ ALNUM_RANGE = range_re('[[:alnum:]][[:alnum:]]*')
private_constant :ALNUM_RANGE
+ # Coerce the string into a numeric value if required.
def self.convert(value, method)
method ? Matchers.send(method, value) : value
end
private_class_method :convert
@@ -42,16 +61,18 @@
[negate, type == '...' ? min...max : min..max]
end
private_class_method :range
+ # Build the lambda proc for a numeric range.
def self.numeric_range(negate, range)
return ->(value) { range.include?(Matchers.numeric(value)) } unless negate
->(value) { !range.include?(Matchers.numeric(value)) }
end
private_class_method :numeric_range
+ # Build the lambda proc for an alphanumeric range.
def self.alnum_range(negate, range)
return ->(value) { range.include?(value) } unless negate
->(value) { !range.include?(value) }
end
private_class_method :alnum_range
@@ -62,26 +83,13 @@
function = Range.send(method, negate, range).freeze
Proc.with(type: :proc, function: function)
end
private_class_method :range_proc
- # @param (see Matchers::Matcher#matches?)
- # @return (see Matchers::Matcher#matches?)
- 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
-
- # Range expression - e.g., +0...10+ or +a..z+
- # @param (see Matchers::Matcher#matches?)
- # @return (see Matchers::Matcher#matches?)
+ # Ruby-like range expressions or their negation - e.g., +0...10+ or +!a..z+.
+ #
+ # @param (see Matcher#matches?)
+ # @return (see Matcher#matches?)
def matches?(cell)
Range.matches?(cell)
end
end
end
\ No newline at end of file