start work on complex condition
[god.git] / lib / god / conditions / complex.rb
blob50dd8ed48c2583a57c890483467e2847fc8bdd44
1 module God
2   module Conditions
3     
4     class Complex < PollCondition
5       AND = 0x1 
6       OR  = 0x2
7       NOT = 0x4
8         
9       def initialize()
10         super
11         
12         @oper_stack = []
13         @op_stack = []
14         
15         @this = nil
16       end
17       
18       def valid?
19         @oper_stack.inject(true) { |acc, oper| acc & oper.valid? }
20       end
21       
22       def prepare
23         @oper_stack.each { |oper| oper.prepare }
24       end
25       
26       def new_oper(kind, op)
27         oper = Condition.generate(kind, self.watch)
28         @oper_stack.push(oper)
29         @op_stack.push(op)
30         oper
31       end
32       
33       def this(kind)
34         @this = Condition.generate(kind, self.watch)
35         yield @this if block_given?
36       end
37       
38       def and(kind)
39         oper = new_oper(kind, 0x1)
40         yield oper if block_given?
41       end
42       
43       def and_not(kind)
44         oper = new_oper(kind, 0x5)
45         yield oper if block_given?
46       end
47       
48       def or(kind)
49         oper = new_oper(kind, 0x2)
50         yield oper if block_given?
51       end
52       
53       def or_not(kind)
54         oper = new_oper(kind, 0x6)
55         yield oper if block_given?
56       end
57       
58       def test
59         if @this.nil?
60           # Although this() makes sense semantically and therefore
61           # encourages easy-to-read conditions, being able to omit it
62           # allows for more DRY code in some cases, so we deal with a
63           # nil @this here by initially setting res to true or false,
64           # depending on whether the first operator used is AND or OR
65           # respectively.
66           if 0 < @op_stack[0] & AND
67             res = true
68           else
69             res = false
70           end
71         else
72           res = @this.test
73         end
74         
75         @op_stack.each do |op|
76           cond = @oper_stack.shift
77           eval "res " + ((0 < op & AND) ? "&&" : "||") + "= " + ((0 < op & NOT) ? "!" : "") + "cond.test"
78           @oper_stack.push cond
79         end
80         
81         res
82       end
83     end
84     
85   end
86 end