-
Notifications
You must be signed in to change notification settings - Fork 17
/
dialogue_extension.rb
executable file
·119 lines (104 loc) · 2.97 KB
/
dialogue_extension.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
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
# require 'cocoa'
# TODO make ['HB','berne','geneva'] => :from possible using the splat operator
# add ability to chain dialogs a la chain_dialog :state, <dialog_name>
# superclass for dialog modules
# dialogs move along the moves
# if a state is entered, enter_#{state_name} is called
# if a state is exited, exit_#{state_name} is called
class DialogExtension < Dialog
attr_reader :state
alias :old_initialize :initialize
# every subclass of this class automatically has its state set to :entry on creation
# def initialize(*args)
# puts "Resetting ", self.name, "\n"
# reset
# old_initialize(*args)
# end
# # automatically adds a hook phrase
# # meaning: adds a move from :awake to this hook word
# # and also a method
def initialize
# reset
end
#
# # TODO improve this such that reset doesn't need to be called in each initializer!
def reset
@state = :entry
end
# TODO think about saying something after each method call though like this it is kept simple which is good
def hear(phrase)
# if next state
return nil unless next_state(phrase)
# call exit method
send("exit_#{@state}".intern, phrase) if respond_to?("exit_#{@state}")
# TODO say(response)
# set actual state
@state = self.next_state(phrase)
# call entry method
send("enter_#{@state}".intern) if respond_to?("enter_#{@state}")
end
# next possible phrases
# TODO splat
def expects
self.class.moves[@state].keys
end
def next_state(phrase)
self.class.moves[@state][phrase] if self.class.moves[@state]
end
# returns the possible states of this dialog
def self.possible_states
self.moves.keys
end
# metaprog
# hook words - these define when this dialog is entered
# adds a hooks method
# TODO get hooks from yaml file
def self.hook_words(*hooks)
self.class_eval do
# set entry state correctly
entry = {}
hooks.each do |hook|
entry[hook] = self.initial
end
# add moves class variable
class <<self
attr_accessor :moves
end
self.moves ||= {}
self.moves[:entry] = entry
# define an instance method
define_method(:hooks) do
hooks
end
end
end
# initial state
def self.initial_state(initial)
self.class_eval do
# add accessor for
class <<self
attr_accessor :initial
end
self.initial = initial
end
end
# state definitions like
# state :name, { moves }
def self.state(name, moves)
self.class_eval do
self.moves ||= {}
self.moves[name] ||= {}
# split arrays here instead of handling later specifically
# can change the implementation later if needed
moves.each do |words,state|
[*words].each do |word|
self.moves[name][word] = state
end
end
#
# self.moves[name] = moves
# puts "moves for #{self.name} are #{self.moves.inspect}"
end
# puts "#{self.name} === #{self.moves.inspect}"
end
end