class Enumpath::Operator::FilterExpression
Implements JSONPath filter expression operator syntax. See {file:README.md#label-Filter+expression+operator} for syntax and examples
Constants
- COMPARISON_OPERATOR_REGEX
- LOGICAL_OPERATORS_REGEX
- OPERATOR_REGEX
Public Class Methods
detect?(operator)
click to toggle source
Whether the operator matches {Enumpath::Operator::FilterExpression::OPERATOR_REGEX}
@param operator (see Enumpath::Operator::Base.detect?
) @return (see Enumpath::Operator::Base.detect?
)
# File lib/enumpath/operator/filter_expression.rb, line 19 def detect?(operator) !(operator =~ OPERATOR_REGEX).nil? end
Public Instance Methods
apply(remaining_path, enum, resolved_path, &block)
click to toggle source
Yields to the block once for each member of the enumerable that passes the filter expression
@param (see Enumpath::Operator::Base#apply
) @yield (see Enumpath::Operator::Base#apply
) @yieldparam remaining_path [Array] remaining_path @yieldparam enum [Enumerable] the member of the enumerable that passed the filter @yieldparam resolved_path [Array] resolved_path plus the key for each member of the enumerable that passed
the filter
# File lib/enumpath/operator/filter_expression.rb, line 32 def apply(remaining_path, enum, resolved_path, &block) Enumpath.log('Evaluating filter expression') { { expression: operator, to: enum } } _match, unpacked_operator = OPERATOR_REGEX.match(operator).to_a expressions = unpacked_operator.split(LOGICAL_OPERATORS_REGEX).map(&:strip) keys(enum).each { |key| apply_to_key(key, expressions, remaining_path, enum, resolved_path, &block) } end
Private Instance Methods
apply_to_key(key, expressions, remaining_path, enum, resolved_path) { |remaining_path, value, resolved_path + [key]| ... }
click to toggle source
# File lib/enumpath/operator/filter_expression.rb, line 41 def apply_to_key(key, expressions, remaining_path, enum, resolved_path) value = Enumpath::Resolver::Simple.resolve(key, enum) Enumpath.log('Applying filter to key') { { key: key, enum: value } } return unless pass?(expressions.dup, value) Enumpath.log('Applying filtered key') { { 'filtered key': key, 'filtered enum': value } } yield(remaining_path, value, resolved_path + [key.to_s]) end
evaluate(expression, enum, logical_operator = nil, running_result = nil)
click to toggle source
# File lib/enumpath/operator/filter_expression.rb, line 61 def evaluate(expression, enum, logical_operator = nil, running_result = nil) property, operator, operand = expression.split(COMPARISON_OPERATOR_REGEX).map(&:strip) value = resolve(property, enum) expression_result = test(operator, operand, value) Enumpath.log('Evaluated filter') do { property => value, operator: operator, operand: operand, result: expression_result, logical_operator: logical_operator }.compact end running_result(logical_operator, running_result, expression_result) end
pass?(expressions, enum)
click to toggle source
# File lib/enumpath/operator/filter_expression.rb, line 50 def pass?(expressions, enum) running_result = evaluate(expressions.shift, enum) Enumpath.log('Initial result') { { result: running_result } } while expressions.any? logical_operator, expression = expressions.shift(2) running_result = evaluate(expression, enum, logical_operator, running_result) Enumpath.log('Running result') { { result: running_result } } end running_result end
resolve(property, enum)
click to toggle source
# File lib/enumpath/operator/filter_expression.rb, line 72 def resolve(property, enum) return enum if property == '@' value = Enumpath::Resolver::Simple.resolve(property.gsub(/^@\./, ''), enum) value = Enumpath::Resolver::Property.resolve(property.gsub(/^@\./, ''), enum) if value.nil? value end
running_result(logical_operator, running_result, expression_result)
click to toggle source
# File lib/enumpath/operator/filter_expression.rb, line 109 def running_result(logical_operator, running_result, expression_result) if logical_operator == '&&' Enumpath.log('&&=') running_result && expression_result elsif logical_operator == '||' Enumpath.log('||=') running_result || expression_result else expression_result end end
test(operator, operand, value)
click to toggle source
# File lib/enumpath/operator/filter_expression.rb, line 80 def test(operator, operand, value) return (value ? true : false) if operator.nil? || operand.nil? typecast_operand = variable_typecaster(operand) value.public_send(operator.to_sym, typecast_operand) ? true : false rescue NoMethodError Enumpath.log('Filter could not be evaluated!') false end
variable_typecaster(variable)
click to toggle source
# File lib/enumpath/operator/filter_expression.rb, line 90 def variable_typecaster(variable) # rubocop:disable Metrics/MethodLength if variable =~ /\A('|").+\1\z/ # It quacks like a string variable.gsub(/\A('|")|('|")\z/, '') elsif variable =~ /^:.+/ # It quacks like a symbol variable.gsub(/\A:/, '').to_sym elsif variable =~ /true|false|nil/i # It quacks like an unquoted boolean operator variable == 'true' elsif (regexp = variable.to_regexp(literal: false, detect: false)) # It quacks like a regex regexp else # Otherwise treat it as a number variable.to_f end end