Class: Tml::RulesEngine::Evaluator
- Inherits:
-
Object
- Object
- Tml::RulesEngine::Evaluator
- Defined in:
- lib/tml/rules_engine/evaluator.rb
Instance Attribute Summary collapse
-
#env ⇒ Object
readonly
Returns the value of attribute env.
-
#vars ⇒ Object
readonly
Returns the value of attribute vars.
Instance Method Summary collapse
- #apply(fn, args) ⇒ Object
- #evaluate(expr) ⇒ Object
-
#initialize ⇒ Evaluator
constructor
A new instance of Evaluator.
- #regexp_from_string(str) ⇒ Object
- #reset! ⇒ Object
Constructor Details
#initialize ⇒ Evaluator
Returns a new instance of Evaluator.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/tml/rules_engine/evaluator.rb', line 39 def initialize @vars = {} @env = { # McCarthy's Elementary S-functions and Predicates 'label' => lambda { |l, r| @vars[l] = r }, 'quote' => lambda { |expr| expr }, 'car' => lambda { |list| list[1] }, 'cdr' => lambda { |list| list.drop(1) }, 'cons' => lambda { |e, cell| [e] + cell }, 'eq' => lambda { |l, r| l == r }, 'atom' => lambda { |expr| [Symbol, String, Fixnum, Float].include?(expr.class) }, 'cond' => lambda { |c, t, f| evaluate(c) ? evaluate(t) : evaluate(f) }, # Tml Extensions '=' => lambda { |l, r| l == r }, # ['=', 1, 2] '!=' => lambda { |l, r| l != r }, # ['!=', 1, 2] '<' => lambda { |l, r| l < r }, # ['<', 1, 2] '>' => lambda { |l, r| l > r }, # ['>', 1, 2] '+' => lambda { |l, r| l + r }, # ['+', 1, 2] '-' => lambda { |l, r| l - r }, # ['-', 1, 2] '*' => lambda { |l, r| l * r }, # ['*', 1, 2] '%' => lambda { |l, r| l % r }, # ['%', 14, 10] 'mod' => lambda { |l, r| l % r }, # ['mod', '@n', 10] '/' => lambda { |l, r| (l * 1.0) / r }, # ['/', 1, 2] '!' => lambda { |expr| not expr }, # ['!', ['true']] 'not' => lambda { |val| not val }, # ['not', ['true']] '&&' => lambda { |*expr| expr.all?{|e| evaluate(e)} }, # ['&&', [], [], ...] 'and' => lambda { |*expr| expr.all?{|e| evaluate(e)} }, # ['and', [], [], ...] '||' => lambda { |*expr| expr.any?{|e| evaluate(e)} }, # ['||', [], [], ...] 'or' => lambda { |*expr| expr.any?{|e| evaluate(e)} }, # ['or', [], [], ...] 'if' => lambda { |c, t, f| evaluate(c) ? evaluate(t) : evaluate(f) }, # ['if', 'cond', 'true', 'false'] 'let' => lambda { |l, r| @vars[l] = r }, # ['let', 'n', 5] 'true' => lambda { true }, # ['true'] 'false' => lambda { false }, # ['false'] 'date' => lambda { |date| Date.strptime(date, '%Y-%m-%d') }, # ['date', '2010-01-01'] 'today' => lambda { Time.now.to_date }, # ['today'] 'time' => lambda { |expr| Time.strptime(expr, '%Y-%m-%d %H:%M:%S') }, # ['time', '2010-01-01 10:10:05'] 'now' => lambda { Time.now }, # ['now'] 'append' => lambda { |l, r| r.to_s + l.to_s }, # ['append', 'world', 'hello '] 'prepend' => lambda { |l, r| l.to_s + r.to_s }, # ['prepend', 'hello ', 'world'] 'match' => lambda { |search, subject| # ['match', /a/, 'abc'] search = regexp_from_string(search) not search.match(subject).nil? }, 'in' => lambda { |values, search| # ['in', '1,2,3,5..10,20..24', '@n'] search = search.to_s.strip values.split(',').each do |e| if e.index('..') bounds = e.strip.split('..') return true if (bounds.first.strip..bounds.last.strip).include?(search) end return true if e.strip == search end false }, 'within' => lambda { |values, search| # ['within', '0..3', '@n'] bounds = values.split('..').map{|d| Integer(d)} (bounds.first..bounds.last).include?(search) }, 'replace' => lambda { |search, replace, subject| # ['replace', '/^a/', 'v', 'abc'] # handle regular expression if /\/i$/.match(search) replace = replace.gsub(/\$(\d+)/, '\\\\\1') # for compatibility with Perl notation end search = regexp_from_string(search) subject.gsub(search, replace) }, 'count' => lambda { |list| # ['count', '@genders'] (list.is_a?(String) ? vars[list] : list).count }, 'all' => lambda { |list, value| # ['all', '@genders', 'male'] list = (list.is_a?(String) ? vars[list] : list) list.is_a?(Array) ? list.all?{|e| e == value} : false }, 'any' => lambda { |list, value| # ['any', '@genders', 'female'] list = (list.is_a?(String) ? vars[list] : list) list.is_a?(Array) ? list.any?{|e| e == value} : false }, } end |
Instance Attribute Details
#env ⇒ Object (readonly)
Returns the value of attribute env.
37 38 39 |
# File 'lib/tml/rules_engine/evaluator.rb', line 37 def env @env end |
#vars ⇒ Object (readonly)
Returns the value of attribute vars.
37 38 39 |
# File 'lib/tml/rules_engine/evaluator.rb', line 37 def vars @vars end |
Instance Method Details
#apply(fn, args) ⇒ Object
140 141 142 143 |
# File 'lib/tml/rules_engine/evaluator.rb', line 140 def apply(fn, args) raise "undefined symbols #{fn}" unless @env.keys.include?(fn) @env[fn].call(*args) end |
#evaluate(expr) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/tml/rules_engine/evaluator.rb', line 145 def evaluate(expr) if @env['atom'].call(expr) return @vars[expr] if expr.is_a?(String) and @vars[expr] return expr end fn = expr[0] args = expr.drop(1) unless %w(quote car cdr cond if && || and or true false let count all any).member?(fn) args = args.map { |a| self.evaluate(a) } end apply(fn, args) end |
#regexp_from_string(str) ⇒ Object
122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/tml/rules_engine/evaluator.rb', line 122 def regexp_from_string(str) return Regexp.new(/#{str}/) unless /^\//.match(str) str = str.gsub(/^\//, '') if /\/i$/.match(str) str = str.gsub(/\/i$/, '') return Regexp.new(/#{str}/i) end str = str.gsub(/\/$/, '') Regexp.new(/#{str}/) end |
#reset! ⇒ Object
136 137 138 |
# File 'lib/tml/rules_engine/evaluator.rb', line 136 def reset! @vars = {} end |