remarkable_rails 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG +81 -0
  2. data/LICENSE +20 -0
  3. data/README +2 -0
  4. data/lib/remarkable_rails/action_controller/base.rb +31 -0
  5. data/lib/remarkable_rails/action_controller/macro_stubs.rb +518 -0
  6. data/lib/remarkable_rails/action_controller/matchers/assign_to_matcher.rb +94 -0
  7. data/lib/remarkable_rails/action_controller/matchers/filter_params_matcher.rb +41 -0
  8. data/lib/remarkable_rails/action_controller/matchers/redirect_to_matcher.rb +119 -0
  9. data/lib/remarkable_rails/action_controller/matchers/render_template_matcher.rb +147 -0
  10. data/lib/remarkable_rails/action_controller/matchers/respond_with_matcher.rb +125 -0
  11. data/lib/remarkable_rails/action_controller/matchers/route_matcher.rb +94 -0
  12. data/lib/remarkable_rails/action_controller/matchers/set_session_matcher.rb +108 -0
  13. data/lib/remarkable_rails/action_controller/matchers/set_the_flash_matcher.rb +55 -0
  14. data/lib/remarkable_rails/action_controller.rb +22 -0
  15. data/lib/remarkable_rails/action_view/base.rb +7 -0
  16. data/lib/remarkable_rails/action_view.rb +18 -0
  17. data/lib/remarkable_rails/active_orm.rb +19 -0
  18. data/lib/remarkable_rails.rb +30 -0
  19. data/locale/en.yml +87 -0
  20. data/spec/action_controller/assign_to_matcher_spec.rb +143 -0
  21. data/spec/action_controller/filter_params_matcher_spec.rb +64 -0
  22. data/spec/action_controller/macro_stubs_spec.rb +196 -0
  23. data/spec/action_controller/redirect_to_matcher_spec.rb +102 -0
  24. data/spec/action_controller/render_template_matcher_spec.rb +251 -0
  25. data/spec/action_controller/respond_with_matcher_spec.rb +223 -0
  26. data/spec/action_controller/route_matcher_spec.rb +75 -0
  27. data/spec/action_controller/set_session_matcher_spec.rb +135 -0
  28. data/spec/action_controller/set_the_flash_matcher_spec.rb +95 -0
  29. data/spec/application/application.rb +15 -0
  30. data/spec/application/examples/_example.html.erb +0 -0
  31. data/spec/application/examples/example.html.erb +0 -0
  32. data/spec/application/examples/example.xml.builder +0 -0
  33. data/spec/application/examples/new.html.erb +0 -0
  34. data/spec/application/layouts/examples.html.erb +0 -0
  35. data/spec/application/projects/new.html.erb +0 -0
  36. data/spec/application/tasks_controller.rb +34 -0
  37. data/spec/functional_builder.rb +93 -0
  38. data/spec/rcov.opts +2 -0
  39. data/spec/spec.opts +4 -0
  40. data/spec/spec_helper.rb +44 -0
  41. metadata +134 -0
data/CHANGELOG ADDED
@@ -0,0 +1,81 @@
1
+ [TODO] Port views matchers from rspec to Remarkable to provide I18n.
2
+
3
+ # v3.0.0
4
+
5
+ [ENHANCEMENT] redirect_to and render_template were ported from rspec-rails to
6
+ remarkable to provide I18n. The second was also extended to deal with :with,
7
+ :layout and :content_type as options.
8
+
9
+ render_with_layout, render_without_layout delegate their logic to render_template
10
+ so they share the same options.
11
+
12
+ respond_with_content_type and respond_wity_body delegate their logic to
13
+ respond_with matcher, so they also share the same options.
14
+
15
+ :set_the_flash was also redesign to inherit from :set_session, providing a
16
+ consistent API.
17
+
18
+ [ENHANCEMENT] remarkable_rails now ships with a new feature, called macro stubs.
19
+ This allows you to declare just once your mocks and/or expectations, and each
20
+ matcher will know how to deal with properly. A TasksController could have your
21
+ specs for a destroy action rewritten like this:
22
+
23
+ describe :delete => :destroy, :id => 37 do
24
+ expects :find, :on => Task, :with => '37', :returns => proc { mock_task }
25
+ expects :destroy, :on => mock_task
26
+
27
+ should_assign_to :task, :with => proc { mock_task }
28
+ should_redirect_to { tasks_url }
29
+ end
30
+
31
+ This will generate two tests, the first one will assert the assignment of
32
+ :task and the second will assert if the action is redirecting to tasks_url.
33
+
34
+ But before doing the assertions, each macros run the expectations declared and
35
+ perform the action automatically. In other words, should assign to macro is
36
+ doing:
37
+
38
+ it 'should assign to task' do
39
+ Task.should_receive(:find).with('37').and_return(mock_task)
40
+ mock_task.should_receive(:destroy)
41
+ delete :destroy, :id => '37'
42
+ assigns(:task).should == mock_task
43
+ end
44
+
45
+ On the other hand, should render template is doing something like this:
46
+
47
+ it 'should render template show' do
48
+ Task.stub!(:find).and_return(mock_task)
49
+ mock_task.should_receive(:destroy)
50
+ delete :destroy, :id => '37'
51
+ response.should render_template('show')
52
+ end
53
+
54
+ But how each macro knows if they should perform expectations or stubs? By default,
55
+ only should_assign_to macro performs expectations (check macro stubs documentation
56
+ to change this behavior).
57
+
58
+ Finally, you don't need to play with procs all the time. There is a convenience
59
+ method called mock_models that generates both class and instance method. So
60
+ doing this:
61
+
62
+ describe ProjectsController do
63
+ mock_models :project
64
+ end
65
+
66
+ Is the same as:
67
+
68
+ def self.mock_project
69
+ proc { mock_project }
70
+ end
71
+
72
+ def mock_project(stubs={})
73
+ @project ||= mock_model(Project, stubs)
74
+ end
75
+
76
+ For more options, information and configuration, check macro stubs documentation.
77
+
78
+ # v2.x
79
+
80
+ [ENHANCMENT] Added assign_to, filter_params, render_with_layout, respond_with
81
+ respond_with_content_type, set_session and set_the_flash matchers.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Carlos Brando
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,2 @@
1
+ Remarkable Rails
2
+ ================
@@ -0,0 +1,31 @@
1
+ module Remarkable
2
+ module ActionController
3
+ class Base < Remarkable::Base
4
+
5
+ before_assert :perform_action_with_macro_stubs
6
+
7
+ optional :with_expectations, :default => true
8
+ optional :with_stubs, :default => true
9
+
10
+ protected
11
+
12
+ # Before assertions, call run_action! to perform the action if it was
13
+ # not performed yet.
14
+ #
15
+ def perform_action_with_macro_stubs
16
+ @spec.send(:run_action!, run_with_expectations?) if @spec.send(:controller)
17
+ end
18
+
19
+ def run_with_expectations?
20
+ if @options.key?(:with_stubs)
21
+ !@options[:with_stubs]
22
+ elsif @options.key?(:with_expectations)
23
+ @options[:with_expectations]
24
+ else
25
+ false
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,518 @@
1
+ # Macro stubs makes stubs and expectations easier, more readable and DRY.
2
+ #
3
+ # == Example
4
+ #
5
+ # Let's jump off to an example:
6
+ #
7
+ # describe ProjectsController do
8
+ # describe "responding to GET show" do
9
+ # expects :find, :on => Project, :with => '37', :returns => proc { mock_project }
10
+ # get :show, :id => 37
11
+ #
12
+ # should_assign_to :project
13
+ # should_render_template 'show'
14
+ #
15
+ # describe 'with mime type XML' do
16
+ # mime Mime::XML
17
+ #
18
+ # should_assign_to :project
19
+ # should_respond_with_content_type Mime::XML
20
+ # end
21
+ # end
22
+ # end
23
+ #
24
+ # See how the spec is readable: a ProjectsController responding to get show
25
+ # expects :find on Project which returns a proc with mock project, request the
26
+ # action show with id 37 and then should assign to project and render template
27
+ # 'show' (it will get even better soon).
28
+ #
29
+ # == Understanding it
30
+ #
31
+ # The <tt>expects</tt> method declares that a Project will receive :find with
32
+ # '37' as argument and return the value of the proc. Next, we declare we should
33
+ # perform a GET on action show with params { :id => '37' }.
34
+ #
35
+ # Then we have two Remarkable macros: should_assign_to and should_render_template.
36
+ # Each macro before asserting will check if an action was already performed and
37
+ # if not, it runs the expectations and call the action.
38
+ #
39
+ # In other words, should assign to macro is basically doing:
40
+ #
41
+ # it 'should assign to project' do
42
+ # Project.should_receive(:find).with('37').and_return(mock_project)
43
+ # get :show, :id => '37'
44
+ # assigns(:project).should == mock_project
45
+ # end
46
+ #
47
+ # On the other hand, should render template is doing something like this:
48
+ #
49
+ # it 'should render template show' do
50
+ # Project.stub!(:find).and_return(mock_project)
51
+ # get :show, :id => '37'
52
+ # response.should render_template('show')
53
+ # end
54
+ #
55
+ # Now comes the first question: how each macro knows if they should perform
56
+ # expectations or stubs?
57
+ #
58
+ # By default, only should_assign_to macro performs expectations. You can change
59
+ # this behavior sending :with_stubs or :with_expectations as options:
60
+ #
61
+ # should_assign_to :project, :with_stubs => true
62
+ # should_render_template 'show', :with_expectations => true
63
+ #
64
+ # This also works in the rspec way:
65
+ #
66
+ # it { should assign_to(:project).with_stubs }
67
+ # it { should render_tempalte('show').with_expectations }
68
+ #
69
+ # == Readability
70
+ #
71
+ # Previously, you probably noticed that the readibility was not a 100%:
72
+ #
73
+ # " A ProjectsController responding to get show expects :find on Project
74
+ # which returns a proc with mock project, request the action show with
75
+ # id 37 and then should assign to project and render template 'show' "
76
+ #
77
+ # This is because we are reading get action show twice and there is a proc in
78
+ # the middle of the description. But, we can make it even better:
79
+ #
80
+ # describe ProjectsController do
81
+ # mock_models :project
82
+ #
83
+ # describe :get => :show, :id => 37 do
84
+ # expects :find, :on => Project, :with => '37', :returns => mock_project
85
+ #
86
+ # should_assign_to :project
87
+ # should_render_template 'show'
88
+ #
89
+ # describe Mime::XML do
90
+ # should_assign_to :project
91
+ # should_respond_with_content_type Mime::XML
92
+ # end
93
+ # end
94
+ # end
95
+ #
96
+ # You might have notices two changes:
97
+ #
98
+ # 1. We moved the "get :show, :id => 37" to the describe method. Don't worry
99
+ # in your spec output, you will still see: "responding to GET show". Which
100
+ # is also localized, as all Remarkable macro and matchers.
101
+ #
102
+ # 2. proc is gone. We've added a call to mock_models which creates a class
103
+ # method that simply returns a proc and a instance method that do the
104
+ # actual mock. In other words, it creates:
105
+ #
106
+ # def self.mock_project
107
+ # proc { mock_project }
108
+ # end
109
+ #
110
+ # def mock_project(stubs={})
111
+ # @project ||= mock_model(Project, stubs)
112
+ # end
113
+ #
114
+ # = Give me more!
115
+ #
116
+ # Things start to get even better when we start to talk about nested resources.
117
+ # After our ProjectsController is created, we want to create a TasksController:
118
+ #
119
+ # describe TasksController do
120
+ # params :project_id => '42' #=> define params for all requests
121
+ #
122
+ # # Those two expectations get inherited in all describe groups below
123
+ # expects :find_by_title, :on => Project, :with => '42', :returns => mock_project
124
+ # expects :tasks, :and_return => Task
125
+ #
126
+ # describe :get => :show, :id => '37' do
127
+ # expects :find, :with => '37', :and_return => mock_task
128
+ #
129
+ # should_assign_to :project, :task
130
+ # should_render_template 'show'
131
+ # end
132
+ # end
133
+ #
134
+ # As you noticed, you can define parameters that will be available to all requests,
135
+ # using the method <tt>params</tt>.
136
+ #
137
+ # Finally, if you used expects chain like above, but need to write a spec by
138
+ # hand you can invoke the action and expectations with run_expectations!,
139
+ # run_stubs! and run_action!. Examples:
140
+ #
141
+ # describe :get => :new do
142
+ # expects :new, :on => Project, :returns => mock_project
143
+ #
144
+ # it "should do something different" do
145
+ # run_action!
146
+ # # do you assertions here
147
+ # end
148
+ # end
149
+ #
150
+ # = Performance!
151
+ #
152
+ # Remarkable comes with a new way to speed up your tests. It perform the action
153
+ # inside a before(:all), so you can do:
154
+ #
155
+ # describe "responding to GET show" do
156
+ # get! :show, :id => 37
157
+ #
158
+ # should_assign_to :task
159
+ # should_render_template :show
160
+ # end
161
+ #
162
+ # Or in the compact way:
163
+ #
164
+ # describe :get! => :show, :id => 37
165
+ #
166
+ # The action will be performed just once before asserting the assignment and
167
+ # the template. If any error happens while performing the action rspec will
168
+ # output an error but ALL the examples inside the example group (describe) won't
169
+ # be run.
170
+ #
171
+ # By now, the bang methods works only when integrate_views are true and this is
172
+ # when you must have the bigger performance gain.
173
+ #
174
+ # This comes with some rspec and rspec rails tweakings. So if you want to do
175
+ # something before the action is performed (stubs something or log someone in
176
+ # session), you have to do it giving a block to the action method:
177
+ #
178
+ # get! :show, :id => 37 do
179
+ # login_as(mock_user)
180
+ # end
181
+ #
182
+ # You can still use the compact way and give the block:
183
+ #
184
+ # describe :get => :show, :id => 37 do
185
+ # get! do
186
+ # login_as(mock_user)
187
+ # end
188
+ # end
189
+ #
190
+ module Remarkable
191
+ module ActionController
192
+
193
+ module MacroStubs
194
+ HTTP_VERBS_METHODS = [:get, :get!, :post, :post!, :put, :put!, :delete, :delete!]
195
+
196
+ def self.included(base)
197
+ base.extend ClassMethods
198
+ base.class_inheritable_reader :expects_chain, :default_action, :default_mime,
199
+ :default_verb, :default_params, :before_all_block
200
+ end
201
+
202
+ module ClassMethods
203
+
204
+ # Creates a chain that will be evaluated as stub or expectation. The
205
+ # first parameter is the method expected.
206
+ #
207
+ # == Options
208
+ #
209
+ # * <tt>:on</tt> - Tell which object will receive the expected method.
210
+ # This option is always required.
211
+ #
212
+ # * <tt>:with</tt> - Tell each parameters will be sent with the expected
213
+ # method. This option is used only in expectations and is optional.
214
+ #
215
+ # * <tt>:returns</tt> - Tell what the expectations should return. Not
216
+ # required.
217
+ #
218
+ # * <tt>:times</tt> - The number of times the object will receive the
219
+ # method. Used only in expectations and when not given, defaults to 1.
220
+ #
221
+ # == Example
222
+ #
223
+ # expects :new, :on => Project, :returns => :mock_project, :times => 2
224
+ #
225
+ def expects(*args)
226
+ write_inheritable_array(:expects_chain, [args])
227
+ end
228
+
229
+ # The mime type of the request. The value given will be called transformed
230
+ # into a string and set in the @request.env['HTTP_ACCEPT'] variable.
231
+ #
232
+ # == Examples
233
+ #
234
+ # mime Mime::XML
235
+ # mime 'application/xml+rss'
236
+ #
237
+ def mime(mime)
238
+ write_inheritable_attribute(:default_mime, mime.to_s)
239
+ end
240
+
241
+ # The params used for the request. Calls are always nested:
242
+ #
243
+ # == Examples
244
+ #
245
+ # describe TasksController do
246
+ # params :project_id => 42
247
+ #
248
+ # describe :get => :show, :id => 37 do
249
+ # # will request with params {:id => 37, :project_id => 42}
250
+ # end
251
+ # end
252
+ #
253
+ def params(params)
254
+ write_inheritable_hash(:default_params, params)
255
+ end
256
+
257
+ [:get, :post, :put, :delete].each do |verb|
258
+ module_eval <<-VERB, __FILE__, __LINE__
259
+ # Declares that we want to do a #{verb} request in the given action
260
+ # and with the given params.
261
+ #
262
+ # == Examples
263
+ #
264
+ # #{verb} :action, :id => 42
265
+ #
266
+ def #{verb}(action, params={})
267
+ params(params)
268
+ write_inheritable_attribute(:default_verb, #{verb.inspect})
269
+ write_inheritable_attribute(:default_action, action)
270
+ end
271
+ VERB
272
+ end
273
+
274
+ [:get!, :post!, :put!, :delete!].each do |verb|
275
+ module_eval <<-VERB, __FILE__, __LINE__
276
+ # Declares that we want to do a #{verb} request in the given action
277
+ # and with the given params, but the action is performed just once
278
+ # in the describe group. In other words, it's performed in a
279
+ # before(:all) filter.
280
+ #
281
+ # == Examples
282
+ #
283
+ # #{verb} :action, :id => 42
284
+ #
285
+ def #{verb}(action=nil, params={}, &block)
286
+ #{verb.to_s.chop}(action, params) if action
287
+ write_inheritable_array(:before_all_block, [block]) if block
288
+ run_callbacks_once!
289
+ end
290
+ VERB
291
+ end
292
+
293
+ # Undefine the method run_callbacks so rspec won't run them in the
294
+ # before and after :each cycle. Then we redefine it as run_callbacks_once,
295
+ # which will be used as an before(:all) and after(:all) filter.
296
+ #
297
+ def run_callbacks_once!(&block) #:nodoc:
298
+ unless instance_methods.any?{|m| m.to_s == 'run_callbacks_once' }
299
+ alias_method :run_callbacks_once, :run_callbacks
300
+ class_eval "def run_callbacks(*args); end"
301
+
302
+ before(:all) do
303
+ setup_mocks_for_rspec
304
+ run_callbacks_once :setup
305
+
306
+ before_all_block.each do |block|
307
+ instance_eval(&block)
308
+ end if before_all_block
309
+
310
+ run_action!
311
+ verify_mocks_for_rspec
312
+ teardown_mocks_for_rspec
313
+ end
314
+
315
+ after(:all) do
316
+ run_callbacks_once :teardown
317
+ end
318
+ end
319
+ end
320
+
321
+ # Overwrites describe to provide quick action description with I18n.
322
+ #
323
+ # You can now do:
324
+ #
325
+ # describe :get => :show, :id => 37
326
+ #
327
+ # Which is the same as:
328
+ #
329
+ # describe 'responding to #GET show' do
330
+ # get :show, :id => 37
331
+ #
332
+ # And do this:
333
+ #
334
+ # describe Mime::XML
335
+ #
336
+ # Which is the same as:
337
+ #
338
+ # describe 'with xml' do
339
+ # mime Mime::XML
340
+ #
341
+ # The string can be localized using I18n. An example yml file is:
342
+ #
343
+ # locale:
344
+ # remarkable:
345
+ # action_controller:
346
+ # responding: "responding to #{{verb}} {{action}}"
347
+ # mime_type: "with {{format}} ({{content_type}})"
348
+ #
349
+ # And load the locale file with:
350
+ #
351
+ # Remarkable.add_locale locale_path
352
+ #
353
+ def describe(*args, &block)
354
+ options = args.first.is_a?(Hash) ? args.first : {}
355
+ verb = (options.keys & HTTP_VERBS_METHODS).first
356
+
357
+ if verb
358
+ action = options.delete(verb)
359
+ verb = verb.to_s
360
+
361
+ description = Remarkable.t 'remarkable.action_controller.responding',
362
+ :default => "responding to ##{verb.upcase} #{action}",
363
+ :verb => verb.sub('!', '').upcase, :action => action
364
+
365
+ send_args = [ verb, action, options ]
366
+ elsif args.first.is_a?(Mime::Type)
367
+ mime = args.first
368
+
369
+ description = Remarkable.t 'remarkable.action_controller.mime_type',
370
+ :default => "with #{mime.to_sym}",
371
+ :format => mime.to_sym, :content_type => mime.to_s
372
+
373
+ send_args = [ :mime, mime ]
374
+ else # return if no special type was found
375
+ return super(*args, &block)
376
+ end
377
+
378
+ args.shift
379
+ args.unshift(description)
380
+
381
+ # Creates an example group, send the method and eval the given block.
382
+ #
383
+ example_group = super(*args) do
384
+ send(*send_args)
385
+ instance_eval(&block)
386
+ end
387
+ end
388
+
389
+ # Creates mock methods automatically.
390
+ #
391
+ # == Options
392
+ #
393
+ # * <tt>:class_method</tt> - When set to false, does not create the
394
+ # class method which returns a proc.
395
+ #
396
+ # == Examples
397
+ #
398
+ # Doing this:
399
+ #
400
+ # describe ProjectsController do
401
+ # mock_models :project
402
+ # end
403
+ #
404
+ # Will create a class and instance mock method for you:
405
+ #
406
+ # def self.mock_project
407
+ # proc { mock_project }
408
+ # end
409
+ #
410
+ # def mock_project(stubs={})
411
+ # @project ||= mock_model(Project, stubs)
412
+ # end
413
+ #
414
+ # If you want to create just the instance method, you can give
415
+ # :class_method => false as option.
416
+ #
417
+ def mock_models(*models)
418
+ options = models.extract_options!
419
+ options = { :class_method => true }.merge(options)
420
+
421
+ models.each do |model|
422
+ self.class_eval <<-METHOD
423
+ #{"def self.mock_#{model}; proc { mock_#{model} }; end" if options[:class_method]}
424
+
425
+ def mock_#{model}(stubs={})
426
+ @#{model} ||= mock_model(#{model.to_s.classify}, stubs)
427
+ end
428
+ METHOD
429
+ end
430
+ end
431
+
432
+ end
433
+
434
+ protected
435
+
436
+ # Evaluates the expectation chain as stub or expectations.
437
+ #
438
+ def evaluate_expectation_chain(use_expectations=true) #:nodoc:
439
+ return if self.expects_chain.nil?
440
+
441
+ self.expects_chain.each do |method, default_options|
442
+ options = default_options.dup
443
+
444
+ # Those are used both in expectations and stubs
445
+ object = evaluate_value(options.delete(:on))
446
+ return_value = evaluate_value(options.delete(:returns))
447
+
448
+ raise ScriptError, "You have to give me :on as an option when calling :expects." if object.nil?
449
+
450
+ if use_expectations
451
+ with = evaluate_value(options.delete(:with))
452
+ times = options.delete(:times) || 1
453
+
454
+ chain = object.should_receive(method)
455
+ chain = chain.with(with) if with
456
+ chain = chain.exactly(times).times
457
+ else
458
+ chain = object.stub!(method)
459
+ end
460
+ chain = chain.and_return(return_value)
461
+ end
462
+ end
463
+
464
+ # Instance method run_stubs! if someone wants to declare additional
465
+ # tests and call the stubs inside of it.
466
+ #
467
+ def run_stubs!
468
+ evaluate_expectation_chain(false)
469
+ end
470
+
471
+ # Instance method run_expectations! if someone wants to declare
472
+ # additional tests and call the stubs inside of it.
473
+ #
474
+ def run_expectations!
475
+ evaluate_expectation_chain(true)
476
+ end
477
+
478
+ # Run the action declared in the describe group, but before runs also
479
+ # the expectations. If an action was already performed, it doesn't run
480
+ # anything at all and returns false.
481
+ #
482
+ # The first parameter is if you want to run expectations or stubs. You
483
+ # can also supply the verb (get, post, put or delete), which action to
484
+ # call, parameters and the mime type. If any of those parameters are
485
+ # supplied, they override the current definition.
486
+ #
487
+ def run_action!(use_expectations=true, verb=nil, action=nil, params=nil, mime=nil)
488
+ return false if controller.send(:performed?)
489
+
490
+ evaluate_expectation_chain(use_expectations)
491
+
492
+ mime ||= default_mime
493
+ verb ||= default_verb
494
+ action ||= default_action
495
+ params ||= default_params
496
+
497
+ raise ScriptError, "No action was performed or declared." unless verb && action
498
+
499
+ request.env["HTTP_ACCEPT"] ||= mime.to_s if mime
500
+ send(verb, action, params)
501
+ end
502
+
503
+ # Evaluate a given value.
504
+ #
505
+ # This allows procs to be given to the expectation chain and they will
506
+ # be evaluated in the instance binding.
507
+ #
508
+ def evaluate_value(duck) #:nodoc:
509
+ if duck.is_a?(Proc)
510
+ self.instance_eval(&duck)
511
+ else
512
+ duck
513
+ end
514
+ end
515
+
516
+ end
517
+ end
518
+ end