Class: Factbase::Term
- Inherits:
-
Object
- Object
- Factbase::Term
- Defined in:
- lib/factbase/term.rb
Overview
Term.
This is an internal class, it is not supposed to be instantiated directly.
It is possible to use for testing directly, for example to make a term with two arguments:
require 'factbase/fact'
require 'factbase/term'
f = Factbase::Fact.new({ 'foo' => [42, 256, 'Hello, world!'] })
t = Factbase::Term.new(:lt, [:foo, 50])
assert(t.evaluate(f))
The design of this class may look ugly, since it has a large number of methods, each of which corresponds to a different type of a Term
. A much better design would definitely involve many classes, one per each type of a term. It’s not done this way because of an experimental nature of the project. Most probably we should keep current design intact, since it works well and is rather simple to extend (by adding new term types). Moreover, it looks like the number of possible term types is rather limited and currently we implement most of them.
It is NOT thread-safe!
- Author
-
Yegor Bugayenko (yegor256@gmail.com)
- Copyright
-
Copyright © 2024-2025 Yegor Bugayenko
- License
-
MIT
Instance Attribute Summary collapse
-
#op ⇒ Symbol
readonly
The operator of this term.
-
#operands ⇒ Array
readonly
The operands of this term.
Instance Method Summary collapse
-
#abstract? ⇒ Boolean
Does it have any variables (+$foo+, for example) inside?.
- #at(fact, maps, fb) ⇒ Object
-
#evaluate(fact, maps, fb) ⇒ Boolean
Does it match the fact?.
-
#initialize(operator, operands) ⇒ Term
constructor
Ctor.
-
#predict(maps, _params) ⇒ Array<Hash>
Try to predict which facts from the provided list should be evaluated.
-
#redress!(type, **args) ⇒ Object
Extend it with the module.
-
#simplify ⇒ Factbase::Term
Simplify it if possible.
-
#static? ⇒ Boolean
Does it have any dependencies on a fact?.
-
#to_s ⇒ String
Turns it into a string.
Methods included from Debug
Methods included from System
Methods included from Defn
Methods included from Ordering
Methods included from Aliases
Methods included from Meta
#absent, #exists, #many, #nil, #one, #size, #type
Methods included from Casting
#to_float, #to_integer, #to_string, #to_time
Methods included from Strings
Methods included from Aggregates
#_best, #agg, #count, #empty, #first, #max, #min, #nth, #sum
Methods included from Logical
#_only_bool, #always, #and, #and_or_simplify, #and_simplify, #either, #never, #not, #or, #or_simplify, #when
Methods included from Math
#_arithmetic, #_cmp, #div, #eq, #gt, #gte, #lt, #lte, #minus, #plus, #times, #zero
Constructor Details
#initialize(operator, operands) ⇒ Term
Ctor.
83 84 85 86 |
# File 'lib/factbase/term.rb', line 83 def initialize(operator, operands) @op = operator @operands = operands end |
Instance Attribute Details
#op ⇒ Symbol (readonly)
The operator of this term
41 42 43 |
# File 'lib/factbase/term.rb', line 41 def op @op end |
#operands ⇒ Array (readonly)
The operands of this term
45 46 47 |
# File 'lib/factbase/term.rb', line 45 def operands @operands end |
Instance Method Details
#abstract? ⇒ Boolean
Does it have any variables (+$foo+, for example) inside?
154 155 156 157 158 159 160 |
# File 'lib/factbase/term.rb', line 154 def abstract? @operands.each do |o| return true if o.is_a?(Factbase::Term) && o.abstract? return true if o.is_a?(Symbol) && o.to_s.start_with?('$') end false end |
#at(fact, maps, fb) ⇒ Object
180 181 182 183 184 185 186 187 188 189 |
# File 'lib/factbase/term.rb', line 180 def at(fact, maps, fb) assert_args(2) i = _values(0, fact, maps, fb) raise "Too many values (#{i.size}) at first position, one expected" unless i.size == 1 i = i[0] return nil if i.nil? v = _values(1, fact, maps, fb) return nil if v.nil? v[i] end |
#evaluate(fact, maps, fb) ⇒ Boolean
Does it match the fact?
117 118 119 120 121 122 123 |
# File 'lib/factbase/term.rb', line 117 def evaluate(fact, maps, fb) send(@op, fact, maps, fb) rescue NoMethodError => e raise "Probably the term '#{@op}' is not defined at #{self}:\n#{Backtrace.new(e)}" rescue StandardError => e raise "#{e.} at #{self}:\n#{Backtrace.new(e)}" end |
#predict(maps, _params) ⇒ Array<Hash>
Try to predict which facts from the provided list should be evaluated. If no prediction can be made, the same list is returned.
108 109 110 |
# File 'lib/factbase/term.rb', line 108 def predict(maps, _params) maps end |
#redress!(type, **args) ⇒ Object
Extend it with the module.
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/factbase/term.rb', line 91 def redress!(type, **args) extend type args.each { |k, v| send(:instance_variable_set, :"@#{k}", v) } @operands.map do |op| if op.is_a?(Factbase::Term) op.redress!(type, **args) else op end end end |
#simplify ⇒ Factbase::Term
Simplify it if possible.
127 128 129 130 131 132 133 134 |
# File 'lib/factbase/term.rb', line 127 def simplify m = "#{@op}_simplify" if respond_to?(m, true) send(m) else self end end |
#static? ⇒ Boolean
Does it have any dependencies on a fact?
If a term is static, it will return the same value for evaluate
, no matter what is the fact given.
142 143 144 145 146 147 148 149 |
# File 'lib/factbase/term.rb', line 142 def static? return true if @op == :agg @operands.each do |o| return false if o.is_a?(Factbase::Term) && !o.static? return false if o.is_a?(Symbol) && !o.to_s.start_with?('$') end true end |
#to_s ⇒ String
Turns it into a string.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/factbase/term.rb', line 164 def to_s items = [] items << @op items += @operands.map do |o| if o.is_a?(String) "'#{o.gsub("'", "\\\\'").gsub('"', '\\\\"')}'" elsif o.is_a?(Time) o.utc.iso8601 else o.to_s end end "(#{items.join(' ')})" end |