Class: Odin::Validation::InvariantEvaluator
- Inherits:
-
Object
- Object
- Odin::Validation::InvariantEvaluator
- Defined in:
- lib/odin/validation/invariant_evaluator.rb
Overview
Recursive-descent evaluator over the invariant grammar:
expression = logic_or
logic_or = logic_and , { "||" , logic_and }
logic_and = equality , { "&&" , equality }
equality = comparison , { ( "==" | "!=" | "=" ) , comparison }
comparison = additive , { ( ">" | "<" | ">=" | "<=" ) , additive }
additive = multiplicative , { ( "+" | "-" ) , multiplicative }
multiplicative = unary , { ( "*" | "/" | "%" ) , unary }
unary = [ "!" ] , primary
primary = path | number | string | "(" , expression , ")"
An expression is parsed to an AST once and cached by its source string; each document validation evaluates the cached AST against that document’s values.
Defined Under Namespace
Classes: Additive, Bool, Compare, Equality, Field, Logic, Multiplicative, Not, Num, Parser, Result, Str, Token
Constant Summary collapse
- EPSILON =
1e-9- MULTI_CHAR_OPS =
%w[== != >= <= && ||].freeze
- SINGLE_CHAR_OPS =
Set.new(%w[+ - * / % > < = !]).freeze
- BOOLEAN_LITERALS =
{ "true" => true, "false" => false }.freeze
- ParseError =
Class.new(StandardError)
- AST_CACHE =
Compiled, document-independent invariant ASTs keyed by source string.
{}
Class Method Summary collapse
-
.parse(expr) ⇒ Object
Return the cached AST for an expression, parsing on first use.
Instance Method Summary collapse
- #evaluate(expr) ⇒ Object
-
#initialize(resolver) ⇒ InvariantEvaluator
constructor
resolver: a callable taking a field name, returning an OdinValue or nil.
Constructor Details
#initialize(resolver) ⇒ InvariantEvaluator
resolver: a callable taking a field name, returning an OdinValue or nil.
51 52 53 |
# File 'lib/odin/validation/invariant_evaluator.rb', line 51 def initialize(resolver) @resolve = resolver end |
Class Method Details
Instance Method Details
#evaluate(expr) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/odin/validation/invariant_evaluator.rb', line 55 def evaluate(expr) ast = self.class.parse(expr) @absent_operand = false @null_operand = false final = eval_node(ast) result = if @null_operand false elsif @absent_operand nil else to_bool(final) end Result.new(result, @null_operand) end |