hat-trick 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Changelog +17 -3
- data/README.md +44 -19
- data/app/assets/javascripts/hat-trick.js.coffee +214 -123
- data/lib/hat-trick.rb +0 -2
- data/lib/hat_trick/config.rb +10 -11
- data/lib/hat_trick/controller_helpers.rb +18 -4
- data/lib/hat_trick/controller_hooks.rb +37 -23
- data/lib/hat_trick/dsl.rb +144 -50
- data/lib/hat_trick/engine.rb +6 -0
- data/lib/hat_trick/form_helper.rb +1 -1
- data/lib/hat_trick/model_methods.rb +14 -3
- data/lib/hat_trick/step.rb +24 -11
- data/lib/hat_trick/step_definition.rb +162 -36
- data/lib/hat_trick/version.rb +1 -1
- data/lib/hat_trick/wizard.rb +105 -46
- data/lib/hat_trick/wizard_definition.rb +18 -9
- data/lib/hat_trick/wizard_steps.rb +12 -3
- data/spec/lib/hat_trick/dsl_spec.rb +11 -10
- data/spec/lib/hat_trick/step_definition_spec.rb +106 -0
- data/spec/lib/hat_trick/wizard_definition_spec.rb +18 -9
- data/spec/lib/hat_trick/wizard_spec.rb +22 -17
- data/spec/spec_helper.rb +6 -0
- data/vendor/assets/javascripts/array.filter.js +22 -0
- data/vendor/assets/javascripts/history.html4.js +658 -0
- data/vendor/assets/javascripts/history.js +1991 -0
- data/vendor/assets/javascripts/jquery.form.wizard.js +162 -145
- data/vendor/assets/javascripts/jquery.history.js +77 -1
- data/vendor/assets/javascripts/json.js +480 -0
- metadata +10 -4
@@ -1,8 +1,10 @@
|
|
1
1
|
module HatTrick
|
2
2
|
class StepDefinition
|
3
3
|
attr_reader :callbacks, :include_data_key
|
4
|
-
attr_accessor :name, :fieldset, :
|
5
|
-
attr_writer :skipped
|
4
|
+
attr_accessor :name, :fieldset, :wizard
|
5
|
+
attr_writer :skipped, :first
|
6
|
+
|
7
|
+
delegate :config, :to => :wizard
|
6
8
|
|
7
9
|
def initialize(args={})
|
8
10
|
args.each_pair do |k,v|
|
@@ -12,15 +14,53 @@ module HatTrick
|
|
12
14
|
end
|
13
15
|
end
|
14
16
|
@callbacks = {}
|
15
|
-
@buttons =
|
16
|
-
|
17
|
+
@buttons = [
|
18
|
+
{ next: default_button(:next) },
|
19
|
+
{ back: default_button(:back) }
|
20
|
+
]
|
21
|
+
@skipped ||= false
|
22
|
+
@last ||= false
|
23
|
+
@first ||= false
|
24
|
+
end
|
25
|
+
|
26
|
+
def buttons
|
27
|
+
# We should check for a new translation every time because the user may
|
28
|
+
# have changed their desired localization.
|
29
|
+
@buttons.map do |b|
|
30
|
+
button_type = b.keys.first
|
31
|
+
if b[button_type][:default]
|
32
|
+
b[button_type][:label] = button_label(button_type)
|
33
|
+
end
|
34
|
+
b
|
35
|
+
end
|
17
36
|
end
|
18
37
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
38
|
+
def next_button
|
39
|
+
get_button(:next)
|
40
|
+
end
|
41
|
+
|
42
|
+
def back_button
|
43
|
+
get_button(:back)
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_button(type)
|
47
|
+
button = buttons.detect { |b| b.keys.first == type.to_sym }
|
48
|
+
button[type.to_sym] unless button.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
def default_button(type)
|
52
|
+
{ :label => button_label(type), :default => true }
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_button(button)
|
56
|
+
@buttons.delete_if do |b|
|
57
|
+
b.keys.first == button.keys.first && b[b.keys.first][:default]
|
58
|
+
end
|
59
|
+
@buttons << button
|
60
|
+
end
|
61
|
+
|
62
|
+
def delete_button(type)
|
63
|
+
@buttons.delete_if { |b| b.keys.first == type }
|
24
64
|
end
|
25
65
|
|
26
66
|
def name=(name)
|
@@ -35,14 +75,27 @@ module HatTrick
|
|
35
75
|
@fieldset or name
|
36
76
|
end
|
37
77
|
|
38
|
-
def repeat?
|
39
|
-
!repeat_of.nil?
|
40
|
-
end
|
41
|
-
|
42
78
|
def skipped?
|
43
79
|
@skipped
|
44
80
|
end
|
45
81
|
|
82
|
+
def last=(_last)
|
83
|
+
@last = _last
|
84
|
+
if @last
|
85
|
+
@buttons.delete_if { |b| b.keys.include?(:next) }
|
86
|
+
else
|
87
|
+
@buttons << { :next => default_next_button }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def last?
|
92
|
+
@last
|
93
|
+
end
|
94
|
+
|
95
|
+
def first?
|
96
|
+
@first
|
97
|
+
end
|
98
|
+
|
46
99
|
def to_s
|
47
100
|
str = "<HatTrick::Step:0x%08x :#{name}" % (object_id * 2)
|
48
101
|
str += " fieldset: #{fieldset}" if fieldset != name
|
@@ -54,19 +107,12 @@ module HatTrick
|
|
54
107
|
name.to_sym
|
55
108
|
end
|
56
109
|
|
57
|
-
def
|
58
|
-
|
59
|
-
json[:repeatOf] = repeat_of.as_json if repeat?
|
60
|
-
json[:buttons] = buttons unless buttons.empty?
|
61
|
-
json
|
62
|
-
end
|
63
|
-
|
64
|
-
def before_callback=(blk)
|
65
|
-
callbacks[:before] = blk
|
110
|
+
def before_callback=(block)
|
111
|
+
callbacks[:before] = block
|
66
112
|
end
|
67
113
|
|
68
|
-
def after_callback=(
|
69
|
-
callbacks[:after] =
|
114
|
+
def after_callback=(block)
|
115
|
+
callbacks[:after] = block
|
70
116
|
end
|
71
117
|
|
72
118
|
def include_data=(hash)
|
@@ -74,31 +120,111 @@ module HatTrick
|
|
74
120
|
@include_data_key = hash.keys.first
|
75
121
|
end
|
76
122
|
|
123
|
+
def step_contents_callback=(block)
|
124
|
+
callbacks[:step_contents] = block
|
125
|
+
end
|
126
|
+
|
127
|
+
def step_contents(context, model)
|
128
|
+
contents = run_step_contents_callback(context, model)
|
129
|
+
{
|
130
|
+
:hatTrickStepContents => {
|
131
|
+
name.to_s.camelize(:lower).to_sym => contents
|
132
|
+
}
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
def include_data(context, model)
|
137
|
+
inc_data = run_include_data_callback(context, model)
|
138
|
+
return {} unless inc_data.respond_to?(:as_json)
|
139
|
+
key = include_data_key.to_s.camelize(:lower)
|
140
|
+
{ key => camelize_hash_keys(inc_data) }
|
141
|
+
end
|
142
|
+
|
143
|
+
def before_callbacks
|
144
|
+
before_callbacks = [callbacks[:before]]
|
145
|
+
if wizard.before_callback_for_all_steps
|
146
|
+
before_callbacks << wizard.before_callback_for_all_steps
|
147
|
+
end
|
148
|
+
before_callbacks
|
149
|
+
end
|
150
|
+
|
77
151
|
def run_before_callback(context, model)
|
78
|
-
|
152
|
+
Rails.logger.info "Running before callback for #{name}"
|
153
|
+
run_callbacks(before_callbacks, context, model)
|
79
154
|
end
|
80
155
|
|
81
156
|
def run_include_data_callback(context, model)
|
82
|
-
|
157
|
+
run_callbacks([callbacks[:include_data]], context, model)
|
158
|
+
end
|
159
|
+
|
160
|
+
def run_step_contents_callback(context, model)
|
161
|
+
run_callbacks([callbacks[:step_contents]], context, model)
|
162
|
+
end
|
163
|
+
|
164
|
+
def after_callbacks
|
165
|
+
after_callbacks = [callbacks[:after]]
|
166
|
+
if wizard.after_callback_for_all_steps
|
167
|
+
after_callbacks << wizard.after_callback_for_all_steps
|
168
|
+
end
|
169
|
+
after_callbacks
|
83
170
|
end
|
84
171
|
|
85
172
|
def run_after_callback(context, model)
|
86
|
-
|
173
|
+
run_callbacks(after_callbacks, context, model)
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def button_label(type)
|
179
|
+
config.send("#{type}_button_label") or
|
180
|
+
if i18n_key = config.send("#{type}_button_label_i18n_key")
|
181
|
+
I18n.t i18n_key
|
182
|
+
end or
|
183
|
+
default_button_label(type)
|
87
184
|
end
|
88
185
|
|
89
|
-
|
186
|
+
def default_button_label(type)
|
187
|
+
translate_button_label(type)
|
188
|
+
end
|
90
189
|
|
91
|
-
def
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
190
|
+
def translate_button_label(type)
|
191
|
+
default_label = type.to_s.humanize
|
192
|
+
begin
|
193
|
+
label = I18n.t("wizard.buttons.#{type}", :default => default_label)
|
194
|
+
rescue NameError
|
195
|
+
label = default_label
|
196
|
+
end
|
197
|
+
label
|
198
|
+
end
|
199
|
+
|
200
|
+
def run_callbacks(callbacks, context, model)
|
201
|
+
result = nil
|
202
|
+
callbacks.each do |callback|
|
203
|
+
if callback && callback.is_a?(Proc)
|
204
|
+
if callback.arity > 0
|
205
|
+
unless model.nil? || model.is_a?(ActiveModel::Errors)
|
206
|
+
result = context.instance_exec model, &callback
|
207
|
+
end
|
208
|
+
else
|
209
|
+
result = context.instance_eval &callback
|
97
210
|
end
|
98
|
-
else
|
99
|
-
context.instance_eval &callback
|
100
211
|
end
|
101
212
|
end
|
213
|
+
|
214
|
+
# return the last result; mainly for include_data
|
215
|
+
result
|
216
|
+
end
|
217
|
+
|
218
|
+
def camelize_hash_keys(_hash)
|
219
|
+
hash = {}
|
220
|
+
if _hash.respond_to?(:each)
|
221
|
+
_hash.each do |k,v|
|
222
|
+
hash[k.to_s.camelize(:lower)] = v
|
223
|
+
end
|
224
|
+
else
|
225
|
+
hash = _hash
|
226
|
+
end
|
227
|
+
hash
|
102
228
|
end
|
103
229
|
end
|
104
230
|
end
|
data/lib/hat_trick/version.rb
CHANGED
data/lib/hat_trick/wizard.rb
CHANGED
@@ -6,12 +6,15 @@ module HatTrick
|
|
6
6
|
class Wizard
|
7
7
|
include WizardSteps
|
8
8
|
|
9
|
-
attr_accessor :controller, :model
|
9
|
+
attr_accessor :controller, :model, :external_redirect_url
|
10
10
|
attr_reader :current_step, :wizard_def, :steps
|
11
11
|
|
12
|
+
delegate :config, :to => :wizard_def
|
13
|
+
|
12
14
|
def initialize(wizard_def)
|
13
15
|
@wizard_def = wizard_def
|
14
16
|
@steps = @wizard_def.steps.map { |s| HatTrick::Step.new(s, self) }
|
17
|
+
@current_step = first_step
|
15
18
|
end
|
16
19
|
|
17
20
|
def controller=(new_controller)
|
@@ -20,15 +23,12 @@ module HatTrick
|
|
20
23
|
|
21
24
|
def model=(new_model)
|
22
25
|
@model = new_model
|
23
|
-
unless @model.class.included_modules.include?(HatTrick::ModelMethods)
|
24
|
-
@model.class.send(:include, HatTrick::ModelMethods)
|
25
|
-
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def current_step=(_step)
|
29
29
|
raise "Don't set current_step to nil" if _step.nil?
|
30
30
|
step = find_step(_step)
|
31
|
-
raise "#{
|
31
|
+
raise StepNotFound, "#{_step} is not a member of this wizard" unless step
|
32
32
|
@current_step = step
|
33
33
|
end
|
34
34
|
|
@@ -72,7 +72,7 @@ module HatTrick
|
|
72
72
|
def next_step
|
73
73
|
step = find_next_step
|
74
74
|
while step.skipped? do
|
75
|
-
step =
|
75
|
+
step = step_after(step)
|
76
76
|
end
|
77
77
|
step
|
78
78
|
end
|
@@ -91,11 +91,64 @@ module HatTrick
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def start
|
94
|
-
|
94
|
+
reset_step_session_data
|
95
95
|
self.current_step ||= first_step
|
96
96
|
run_before_callback
|
97
97
|
end
|
98
98
|
|
99
|
+
def steps_before_current
|
100
|
+
steps_before(current_step)
|
101
|
+
end
|
102
|
+
|
103
|
+
def steps_after_current
|
104
|
+
steps_after(current_step)
|
105
|
+
end
|
106
|
+
|
107
|
+
def visited_steps
|
108
|
+
session["hat-trick.visited_steps"] ||= []
|
109
|
+
end
|
110
|
+
|
111
|
+
def skipped_steps
|
112
|
+
session["hat-trick.skipped_steps"] ||= []
|
113
|
+
end
|
114
|
+
|
115
|
+
def percent_complete(step=current_step)
|
116
|
+
percent = (steps_before_current.count.to_f / total_step_count) * 100
|
117
|
+
if percent > 100.0
|
118
|
+
100
|
119
|
+
elsif percent <= 0
|
120
|
+
0
|
121
|
+
elsif percent < 5.0
|
122
|
+
5
|
123
|
+
else
|
124
|
+
percent
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def steps_remaining=(count)
|
129
|
+
self.override_step_count = steps_before_current.count + count
|
130
|
+
end
|
131
|
+
|
132
|
+
def steps_remaining
|
133
|
+
total_step_count - steps_before_current.count
|
134
|
+
end
|
135
|
+
|
136
|
+
def override_step_count=(count)
|
137
|
+
if count.nil?
|
138
|
+
session.delete('hat-trick.override_step_count')
|
139
|
+
else
|
140
|
+
session['hat-trick.override_step_count'] = count
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def override_step_count
|
145
|
+
session['hat-trick.override_step_count']
|
146
|
+
end
|
147
|
+
|
148
|
+
def total_step_count
|
149
|
+
override_step_count or steps.count
|
150
|
+
end
|
151
|
+
|
99
152
|
def run_before_callback(step=current_step)
|
100
153
|
step.run_before_callback(controller, model)
|
101
154
|
end
|
@@ -104,13 +157,29 @@ module HatTrick
|
|
104
157
|
step.run_after_callback(controller, model)
|
105
158
|
end
|
106
159
|
|
160
|
+
def redirect_to_step(step)
|
161
|
+
redirect_from = current_step.fieldset
|
162
|
+
self.current_step = step
|
163
|
+
current_step.redirect_from = redirect_from
|
164
|
+
end
|
165
|
+
|
107
166
|
def advance_step(next_step_name=nil)
|
108
167
|
# clean up current step
|
109
|
-
current_step.
|
168
|
+
current_step.mark_as_visited
|
169
|
+
before_callback_next_step = current_step.next_step
|
110
170
|
run_after_callback
|
171
|
+
after_callback_next_step = current_step.next_step
|
111
172
|
|
112
|
-
#
|
113
|
-
|
173
|
+
# return if any redirects were requested
|
174
|
+
return if external_redirect_url.present?
|
175
|
+
|
176
|
+
# if after callback changed the next step, go to that one
|
177
|
+
requested_next_step = if after_callback_next_step != before_callback_next_step
|
178
|
+
after_callback_next_step
|
179
|
+
else
|
180
|
+
# use argument, if there was one
|
181
|
+
find_step(next_step_name) unless next_step_name.nil?
|
182
|
+
end
|
114
183
|
|
115
184
|
# finish if we're on the last step
|
116
185
|
if current_step == last_step && !requested_next_step
|
@@ -122,72 +191,62 @@ module HatTrick
|
|
122
191
|
run_before_callback
|
123
192
|
# if the step was explicitly requested, we ignore #skipped?
|
124
193
|
else
|
125
|
-
Rails.logger.info "Advancing to step: #{next_step}"
|
126
194
|
self.current_step = next_step
|
127
195
|
run_before_callback
|
128
196
|
# Running the before callback may have marked current_step as skipped
|
129
197
|
while current_step.skipped?
|
130
198
|
self.current_step = next_step
|
131
199
|
run_before_callback
|
200
|
+
# make sure we don't loop forever
|
201
|
+
break if current_step == last_step
|
132
202
|
end
|
203
|
+
Rails.logger.info "Advancing to step: #{current_step}"
|
133
204
|
end
|
134
205
|
end
|
135
206
|
end
|
136
207
|
|
137
208
|
def include_data
|
209
|
+
include_data_for_step(current_step)
|
210
|
+
end
|
211
|
+
|
212
|
+
def include_data_for_step(step)
|
138
213
|
return {} if model.nil?
|
139
|
-
inc_data =
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
next if step_data.nil? || !step_data.respond_to?(:as_json)
|
144
|
-
step_key = step.include_data_key.to_s.camelize(:lower)
|
145
|
-
begin
|
146
|
-
inc_data[step_key] = camelize_hash_keys(step_data)
|
147
|
-
rescue NoMethodError => e
|
148
|
-
Rails.logger.error "Unable to serialize data for step #{step}: #{e}"
|
149
|
-
end
|
150
|
-
end
|
214
|
+
inc_data = step.include_data(controller, model)
|
215
|
+
contents = step.step_contents(controller, model)
|
216
|
+
inc_data.merge! contents
|
217
|
+
inc_data.delete_if { |k,v| v.nil? }
|
151
218
|
inc_data
|
152
219
|
end
|
153
220
|
|
154
221
|
def alias_action_methods
|
155
222
|
action_methods = controller.action_methods.reject do |m|
|
156
|
-
/^render/ =~ m.to_s
|
157
|
-
|
223
|
+
/^render/ =~ m.to_s or
|
224
|
+
m.to_s.include?('!') or
|
225
|
+
controller.respond_to?("#{m}_without_hat_trick", :include_private)
|
158
226
|
end
|
159
227
|
HatTrick::ControllerHooks.def_action_method_aliases(action_methods)
|
160
|
-
action_methods.each do |
|
161
|
-
|
162
|
-
controller.class.send(:
|
228
|
+
action_methods.each do |m|
|
229
|
+
Rails.logger.info "Aliasing #{m}"
|
230
|
+
controller.class.send(:alias_method_chain, m, :hat_trick)
|
231
|
+
controller.class.send(:private, "#{m}_without_hat_trick")
|
163
232
|
end
|
164
233
|
end
|
165
234
|
|
166
235
|
private
|
167
236
|
|
237
|
+
def reset_step_session_data
|
238
|
+
# TODO: Move this into a StepCollection class (maybe subclass Set)
|
239
|
+
visited_steps = []
|
240
|
+
skipped_steps = []
|
241
|
+
end
|
242
|
+
|
168
243
|
def fake_session
|
244
|
+
Rails.logger.warn "Using a fake session object!"
|
169
245
|
@fake_session ||= {}
|
170
246
|
end
|
171
247
|
|
172
248
|
def find_next_step
|
173
|
-
find_step(current_step.next_step)
|
174
|
-
end
|
175
|
-
|
176
|
-
def find_step_after(step)
|
177
|
-
next_path_step = step_after step
|
178
|
-
next_path_step or find_next_active_step(step)
|
179
|
-
end
|
180
|
-
|
181
|
-
def camelize_hash_keys(_hash)
|
182
|
-
hash = {}
|
183
|
-
if _hash.respond_to?(:each)
|
184
|
-
_hash.each do |k,v|
|
185
|
-
hash[k.to_s.camelize(:lower)] = v
|
186
|
-
end
|
187
|
-
else
|
188
|
-
hash = _hash
|
189
|
-
end
|
190
|
-
hash
|
249
|
+
find_step(current_step.next_step) || step_after(current_step)
|
191
250
|
end
|
192
251
|
end
|
193
252
|
end
|
@@ -6,19 +6,28 @@ module HatTrick
|
|
6
6
|
class WizardDefinition
|
7
7
|
include WizardSteps
|
8
8
|
|
9
|
-
|
9
|
+
attr_reader :config
|
10
|
+
attr_accessor :before_callback_for_all_steps, :after_callback_for_all_steps
|
10
11
|
|
11
|
-
def initialize
|
12
|
+
def initialize(config)
|
13
|
+
@config = config
|
12
14
|
@steps = []
|
13
15
|
end
|
14
16
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
def make_wizard_for(controller)
|
18
|
+
Rails.logger.info "Making new wizard instance"
|
19
|
+
wizard = HatTrick::Wizard.new(self)
|
20
|
+
wizard.controller = controller
|
21
|
+
wizard.alias_action_methods
|
22
|
+
wizard
|
23
|
+
end
|
24
|
+
|
25
|
+
def configured_create_url
|
26
|
+
config.create_url
|
27
|
+
end
|
28
|
+
|
29
|
+
def configured_update_url
|
30
|
+
config.update_url
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
module HatTrick
|
2
|
+
class StepNotFound < StandardError; end
|
3
|
+
|
2
4
|
module WizardSteps
|
3
5
|
include Enumerable
|
4
6
|
attr_reader :steps
|
@@ -26,9 +28,11 @@ module HatTrick
|
|
26
28
|
def steps_after(_step)
|
27
29
|
step = find_step(_step)
|
28
30
|
return [] unless step
|
31
|
+
return [] if step.last? && !step.skipped?
|
29
32
|
step_index = steps.index(step)
|
30
33
|
max_index = steps.count - 1
|
31
|
-
|
34
|
+
return [] if step_index >= max_index
|
35
|
+
after_index = step_index + 1
|
32
36
|
steps[after_index .. -1]
|
33
37
|
end
|
34
38
|
|
@@ -40,7 +44,8 @@ module HatTrick
|
|
40
44
|
step = find_step(_step)
|
41
45
|
return [] unless step
|
42
46
|
step_index = steps.index(step)
|
43
|
-
|
47
|
+
return [] if step_index <= 0
|
48
|
+
before_index = step_index - 1
|
44
49
|
steps[0 .. before_index]
|
45
50
|
end
|
46
51
|
|
@@ -48,10 +53,14 @@ module HatTrick
|
|
48
53
|
if step.is_a?(HatTrick::Step) || step.is_a?(HatTrick::StepDefinition)
|
49
54
|
new_step = step
|
50
55
|
else
|
51
|
-
step_args = args.merge(:name => step)
|
56
|
+
step_args = args.merge(:name => step, :wizard => self)
|
52
57
|
new_step = HatTrick::StepDefinition.new(step_args)
|
53
58
|
end
|
54
59
|
|
60
|
+
if steps.count == 0
|
61
|
+
new_step.first = true
|
62
|
+
end
|
63
|
+
|
55
64
|
steps << new_step
|
56
65
|
|
57
66
|
new_step
|
@@ -1,26 +1,27 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
# will automatically get HatTrick::DSL included
|
4
|
-
class FakeController < ActionController::Base; end
|
5
|
-
|
6
3
|
describe HatTrick::DSL do
|
7
|
-
|
4
|
+
subject(:controller) {
|
5
|
+
Class.new.send(:include, HatTrick::DSL).tap do |c|
|
6
|
+
c.stubs(:before_filter)
|
7
|
+
c.any_instance.stubs(:render)
|
8
|
+
end
|
9
|
+
}
|
8
10
|
|
9
|
-
# save some typing
|
10
|
-
def dsl(&block)
|
11
|
-
controller_class.instance_eval &block
|
12
|
-
end
|
13
|
-
|
14
11
|
describe HatTrick::DSL::ClassMethods do
|
15
12
|
describe "#step" do
|
16
13
|
it "should call Wizard#add_step" do
|
17
14
|
HatTrick::WizardDefinition.any_instance.expects(:add_step).with(:foo, {})
|
18
|
-
|
15
|
+
controller.instance_eval do
|
19
16
|
wizard do
|
20
17
|
step :foo
|
21
18
|
end
|
22
19
|
end
|
23
20
|
end
|
21
|
+
|
22
|
+
it "raises an error if called outside a wizard block" do
|
23
|
+
expect { controller.step :foo }.to raise_error
|
24
|
+
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|