Class: Predicator::Evaluator

Inherits:
Object
  • Object
show all
Defined in:
lib/predicator/evaluator.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(instructions, context_data = {}) ⇒ Evaluator

Returns a new instance of Evaluator.



7
8
9
10
11
12
# File 'lib/predicator/evaluator.rb', line 7

def initialize instructions, context_data={}
  @instructions = instructions
  @context = context_for context_data
  @stack = []
  @ip = 0
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



5
6
7
# File 'lib/predicator/evaluator.rb', line 5

def context
  @context
end

#instructionsObject (readonly)

Returns the value of attribute instructions.



5
6
7
# File 'lib/predicator/evaluator.rb', line 5

def instructions
  @instructions
end

#stackObject (readonly)

Returns the value of attribute stack.



5
6
7
# File 'lib/predicator/evaluator.rb', line 5

def stack
  @stack
end

Instance Method Details

#blank?(val) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/predicator/evaluator.rb', line 77

def blank? val
  val.respond_to?(:empty?) ? !!val.empty? : !val
end

#compare(comparison) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
# File 'lib/predicator/evaluator.rb', line 99

def compare comparison
  right = stack.pop
  left = stack.pop
  if left.nil? || right.nil?
    stack.push false
  else
    stack.push send("compare_#{comparison}", left, right)
  end
rescue StandardError
  stack.push false
end

#compare_BETWEENObject



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/predicator/evaluator.rb', line 139

def compare_BETWEEN
  max = stack.pop
  min = stack.pop
  val = stack.pop
  if max.nil? || min.nil? || val.nil?
    stack.push false
  else
    result = val.between? min, max
    stack.push result
  end
rescue StandardError
  stack.push false
end

#compare_ENDSWITH(left, right) ⇒ Object



135
136
137
# File 'lib/predicator/evaluator.rb', line 135

def compare_ENDSWITH left, right
  left.end_with? right
end

#compare_EQ(left, right) ⇒ Object



111
112
113
# File 'lib/predicator/evaluator.rb', line 111

def compare_EQ left, right
  left == right
end

#compare_GT(left, right) ⇒ Object



115
116
117
# File 'lib/predicator/evaluator.rb', line 115

def compare_GT left, right
  left > right
end

#compare_IN(left, right) ⇒ Object



123
124
125
# File 'lib/predicator/evaluator.rb', line 123

def compare_IN left, right
  right.include? left
end

#compare_LT(left, right) ⇒ Object



119
120
121
# File 'lib/predicator/evaluator.rb', line 119

def compare_LT left, right
  left < right
end

#compare_NOTIN(left, right) ⇒ Object



127
128
129
# File 'lib/predicator/evaluator.rb', line 127

def compare_NOTIN left, right
  !right.include? left
end

#compare_STARTSWITH(left, right) ⇒ Object



131
132
133
# File 'lib/predicator/evaluator.rb', line 131

def compare_STARTSWITH left, right
  left.start_with? right
end

#context_for(context_data) ⇒ Object



14
15
16
17
# File 'lib/predicator/evaluator.rb', line 14

def context_for context_data
  return context_data unless context_data.kind_of? Hash
  Context.new context_data
end

#date_ago(seconds) ⇒ Object



67
68
69
70
# File 'lib/predicator/evaluator.rb', line 67

def date_ago seconds
  past_time = Time.now - seconds
  to_date past_time.strftime "%Y-%m-%d"
end

#date_from_now(seconds) ⇒ Object



72
73
74
75
# File 'lib/predicator/evaluator.rb', line 72

def date_from_now seconds
  future_time = Time.now + seconds
  to_date future_time.strftime "%Y-%m-%d"
end

#jump_if_false(offset) ⇒ Object



81
82
83
84
85
86
87
88
# File 'lib/predicator/evaluator.rb', line 81

def jump_if_false offset
  if stack[-1] == false
    adjusted_offset = offset - 1
    @ip += adjusted_offset
  else
    stack.pop
  end
end

#jump_if_true(offset) ⇒ Object



90
91
92
93
94
95
96
97
# File 'lib/predicator/evaluator.rb', line 90

def jump_if_true offset
  if stack[-1] == true
    adjusted_offset = offset - 1
    @ip += adjusted_offset
  else
    stack.pop
  end
end

#process(instruction) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/predicator/evaluator.rb', line 27

def process instruction
  case instruction.first
  when "not"             then stack.push !stack.pop
  when "jfalse"          then jump_if_false instruction.last
  when "jtrue"           then jump_if_true instruction.last
  when "lit", "array"    then stack.push instruction.last
  when "load"            then stack.push context[instruction.last]
  when "to_bool"         then stack.push !!stack.pop
  when "to_int"          then stack.push to_int(stack.pop)
  when "to_str"          then stack.push to_str(stack.pop)
  when "to_date"         then stack.push to_date(stack.pop)
  when "date_ago"        then stack.push date_ago(stack.pop)
  when "date_from_now"   then stack.push date_from_now(stack.pop)
  when "blank"           then stack.push blank?(stack.pop)
  when "present"         then stack.push !blank?(stack.pop)
  when "compare"
    if instruction.last == "BETWEEN"
      compare_BETWEEN
    else
      compare instruction.last
    end
  end
end

#resultObject



19
20
21
22
23
24
25
# File 'lib/predicator/evaluator.rb', line 19

def result
  while @ip < instructions.length
    process @instructions[@ip]
    @ip += 1
  end
  stack.pop
end

#to_date(val) ⇒ Object



63
64
65
# File 'lib/predicator/evaluator.rb', line 63

def to_date val
  val.nil? ? nil : Date.parse(val)
end

#to_int(val) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/predicator/evaluator.rb', line 51

def to_int val
  if val.nil? || (val.is_a?(String) && val.empty?)
    nil
  else
    val.to_i
  end
end

#to_str(val) ⇒ Object



59
60
61
# File 'lib/predicator/evaluator.rb', line 59

def to_str val
  val.nil? ? nil : val.to_s
end