We want to have a DSL where we can write statements separated with space. Like this:
|
Robot.new do
a b c
d e
f g h i
j
end.run
|
outputs
|
Go to a
Go to b
Go to c
Go to d
Go to e
Go to f
Go to g
Go to h
Go to i
Go to j
|
Since separating by space means method invocation in Ruby, we need to hack into method_missing.
I am just posting the codes and will not give it further explanation. Look into the details yourself.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
class Robot
attr_accessor :movements
def initialize &block
@movements = []
@last_length = 0
instance_eval &block if block
rearrange
end
def method_missing name, *args
case args.size
when 0
rearrange
@movements.push result = Movement.new(name)
@last_length += 1
result
when 1
@movements.push result = Movement.new(name)
@last_length += 1
result
else
super
end
end
def rearrange
last_movements = @movements.last @last_length
@movements[@movements.size - @last_length..] = last_movements.reverse
@last_length = 0
end
def run
puts @movements
end
class Movement
attr_accessor :target
def initialize target
@target = target
end
def to_s
"Go to #@target"
end
end
end
|
Similar tricks are used in my other Ruby project alda-rb. The codes can be found on GitHub.