Class: Lita::Wizard

Inherits:
Object
  • Object
show all
Defined in:
lib/lita/wizard.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(robot, message, data = {}) ⇒ Wizard

Returns a new instance of Wizard.



7
8
9
10
11
12
13
14
15
# File 'lib/lita/wizard.rb', line 7

def initialize(robot, message, data = {})
  @id = data['id'] || SecureRandom.hex(3)
  @robot = robot
  @message = message
  @user_id = message.user.id
  @current_step_index = (data['current_step_index'] || -1).to_i
  @values = data['values'] || []
  @meta = data['meta']
end

Instance Attribute Details

#current_step_indexObject

Returns the value of attribute current_step_index.



5
6
7
# File 'lib/lita/wizard.rb', line 5

def current_step_index
  @current_step_index
end

#idObject

Returns the value of attribute id.



5
6
7
# File 'lib/lita/wizard.rb', line 5

def id
  @id
end

#messageObject

Returns the value of attribute message.



5
6
7
# File 'lib/lita/wizard.rb', line 5

def message
  @message
end

#metaObject

Returns the value of attribute meta.



5
6
7
# File 'lib/lita/wizard.rb', line 5

def meta
  @meta
end

#robotObject

Returns the value of attribute robot.



5
6
7
# File 'lib/lita/wizard.rb', line 5

def robot
  @robot
end

#user_idObject

Returns the value of attribute user_id.



5
6
7
# File 'lib/lita/wizard.rb', line 5

def user_id
  @user_id
end

#valuesObject

Returns the value of attribute values.



5
6
7
# File 'lib/lita/wizard.rb', line 5

def values
  @values
end

Class Method Details

.cancel_wizard(user_id) ⇒ Object



187
188
189
# File 'lib/lita/wizard.rb', line 187

def cancel_wizard(user_id)
  Lita.redis.del "pending-wizard-#{user_id.downcase}"
end

.handle_message(robot, message) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
# File 'lib/lita/wizard.rb', line 163

def handle_message(robot, message)
  return false unless pending_wizard?(message.user.id)
  wizard = restore(robot, message)
  if wizard
    wizard.handle_message
    true
  else
    cancel_wizard(message.user.id)
    false
  end
end

.pending_wizard?(user_id) ⇒ Boolean

Returns:

  • (Boolean)


183
184
185
# File 'lib/lita/wizard.rb', line 183

def pending_wizard?(user_id)
  Lita.redis["pending-wizard-#{user_id.downcase}"]
end

.restore(robot, message) ⇒ Object



175
176
177
178
179
180
181
# File 'lib/lita/wizard.rb', line 175

def restore(robot, message)
  data = MultiJson.load(Lita.redis["pending-wizard-#{message.user.id.downcase}"])
  klass = eval(data['class'])
  klass.new(robot, message, data)
rescue
  nil
end

.start(robot, message, meta = {}) ⇒ Object



156
157
158
159
160
161
# File 'lib/lita/wizard.rb', line 156

def start(robot, message, meta = {})
  return false if pending_wizard?(message.user.id)
  wizard = new(robot, message, 'meta' => meta)
  wizard.advance
  true
end

.step(name, options = {}) ⇒ Object



191
192
193
# File 'lib/lita/wizard.rb', line 191

def step(name, options = {})
  steps << OpenStruct.new(options.merge(name: name))
end

.stepsObject



195
196
197
# File 'lib/lita/wizard.rb', line 195

def steps
  @steps ||= []
end

Instance Method Details

#abort_messageObject



133
134
135
# File 'lib/lita/wizard.rb', line 133

def abort_message
  "Aborting. Resume your normal operations"
end

#abort_wizardObject



144
145
# File 'lib/lita/wizard.rb', line 144

def abort_wizard
end

#advanceObject



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/lita/wizard.rb', line 17

def advance
  self.current_step_index += 1
  save
  if final_step?
    finish_wizard
    send_message final_message
    destroy
  elsif run_current_step?
    if first_step?
      start_wizard
      send_message initial_message
    end
    message = step[:label]
    message = "#{message} (Write done when finished)" if step[:multiline]
    send_message message
  else
    advance
  end
end

#as_jsonObject



77
78
79
80
81
82
83
84
85
86
# File 'lib/lita/wizard.rb', line 77

def as_json
  {
    'class' => self.class.name,
    'id' => id,
    'user_id' => user_id,
    'current_step_index' => current_step_index,
    'values' => values,
    'meta' => meta
  }
end

#destroyObject



69
70
71
# File 'lib/lita/wizard.rb', line 69

def destroy
  Lita.redis.del "pending-wizard-#{user_id.downcase}"
end

#final_messageObject



137
138
139
# File 'lib/lita/wizard.rb', line 137

def final_message
  "You're done!"
end

#final_step?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/lita/wizard.rb', line 100

def final_step?
  current_step_index == steps.size
end

#finish_wizardObject



147
148
# File 'lib/lita/wizard.rb', line 147

def finish_wizard
end

#first_step?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/lita/wizard.rb', line 104

def first_step?
  current_step_index == 0
end

#handle_messageObject



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
# File 'lib/lita/wizard.rb', line 37

def handle_message
  if message.body == "abort"
    send_message abort_message
    abort_wizard
    destroy
  elsif step.nil?
    send_message "Some error occured. Aborting."
    destroy
  elsif message.body == "done" && step[:multiline]
    save
    advance
  elsif valid_response?
    if step[:multiline]
      values[current_step_index] ||= ""
      values[current_step_index] << "\n"
      values[current_step_index] << message.body
      values[current_step_index].strip!
      save
    else
      values[current_step_index] = message.body
      save
      advance
    end
  else
    send_message @error_message
  end
end

#initial_messageObject



128
129
130
131
# File 'lib/lita/wizard.rb', line 128

def initial_message
  "Great! I'm going to ask you some questions. During this time I cannot take regular commands. " \
  "You can abort at any time by writing abort"
end

#run_current_step?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/lita/wizard.rb', line 96

def run_current_step?
  step[:if].nil? || instance_eval(&step[:if])
end

#saveObject



65
66
67
# File 'lib/lita/wizard.rb', line 65

def save
  Lita.redis["pending-wizard-#{user_id.downcase}"] = to_json
end

#send_message(body) ⇒ Object



150
151
152
# File 'lib/lita/wizard.rb', line 150

def send_message(body)
  message.reply body
end

#start_wizardObject



141
142
# File 'lib/lita/wizard.rb', line 141

def start_wizard
end

#stepObject



88
89
90
# File 'lib/lita/wizard.rb', line 88

def step
  steps[current_step_index]
end

#step_index(step_name) ⇒ Object



112
113
114
# File 'lib/lita/wizard.rb', line 112

def step_index(step_name)
  steps.index { |step| step.name == step_name }
end

#stepsObject



92
93
94
# File 'lib/lita/wizard.rb', line 92

def steps
  self.class.steps
end

#to_jsonObject



73
74
75
# File 'lib/lita/wizard.rb', line 73

def to_json
  MultiJson.dump(as_json)
end

#valid_response?Boolean

Returns:

  • (Boolean)


116
117
118
119
120
121
122
123
124
125
126
# File 'lib/lita/wizard.rb', line 116

def valid_response?
  if step[:validate] && !step[:validate].match(message.body)
    @error_message = 'Invalid format'
    false
  elsif step[:options] && !step[:options].include?(message.body)
    @error_message = "Invalid response. Valid options: #{step[:options].join(', ')}"
    false
  else
    true
  end
end

#value_for(step_name) ⇒ Object



108
109
110
# File 'lib/lita/wizard.rb', line 108

def value_for(step_name)
  values[step_index(step_name)]
end