-
Notifications
You must be signed in to change notification settings - Fork 17
/
visitor.rb
87 lines (78 loc) · 1.95 KB
/
visitor.rb
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
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
module James
# The visitor knows where in the conversation we are.
#
# It also remembers where it has to go back to if
# too much time passes without input.
#
# Note: A visitor should generally be very stupid.
# Note 2: We could call this Hearing, or Ear ;)
#
# TODO Add a timer which resets the state to the
# initial state.
#
class Visitor
attr_reader :initial, :timer
attr_accessor :current
# Pass in an initial state to start from.
#
def initialize initial, timer = nil
@current = initial
@initial = initial
# @timer = timer || Timer.new
end
# Resets the current state back to the initial.
#
def reset
# timer.stop
self.current = initial
end
# We hear a phrase.
#
# Also used to start the whole process.
#
def enter
result = current.__into__
yield result if result && block_given?
result
end
def exit
result = current.__exit__
yield result if result && block_given?
result
end
def transition phrase
state_or_lambda = current.next_for phrase
if state_or_lambda.respond_to?(:call)
current.__transition__ &state_or_lambda # Don't transition.
else
self.current = state_or_lambda
end
end
def check
reset && yield("Whoops. That led nowhere. Perhaps you didn't define the target state?") unless self.current
end
def hear phrase, &block
return unless hears? phrase
# timer.restart
exit_text = exit &block
transition phrase
check &block
into_text = enter &block
exit_text || into_text
end
def hears? phrase
expects.include? phrase
end
def expects
current.phrases
end
# Does the current state allow penetration into another dialog?
#
def chainable?
current.chainable?
end
def to_s
"#{self.class.name}(#{initial}, current: #{current})"
end
end
end