remarkable_rails 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,6 +1,6 @@
1
1
  [TODO] Port views matchers from rspec to Remarkable to provide I18n.
2
2
 
3
- # v3.0.0
3
+ # v3.0.0
4
4
 
5
5
  [ENHANCEMENT] redirect_to and render_template were ported from rspec-rails to
6
6
  remarkable to provide I18n. The second was also extended to deal with :with,
@@ -18,64 +18,27 @@ consistent API.
18
18
  [ENHANCEMENT] remarkable_rails now ships with a new feature, called macro stubs.
19
19
  This allows you to declare just once your mocks and/or expectations, and each
20
20
  matcher will know how to deal with properly. A TasksController could have your
21
- specs for a destroy action rewritten like this:
21
+ specs for a create action rewritten like this:
22
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
23
+ describe TasksController do
24
+ mock_models :task
26
25
 
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).
26
+ describe :post => :create, :task => { :these => 'params' } do
27
+ expects :new, :on => Task, with => {'these' => 'params'}, :returns => mock_task
28
+ expects :save, :on => mock_task, :returns => true
57
29
 
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
30
+ should_assign_to :task, :with => mock_task
31
+ should_redirect_to { task_url(mock_task) }
32
+ end
64
33
  end
65
34
 
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
35
+ It automatically performs the action before running each macro. In assign_to,
36
+ it executes the expects as expectations (:should_receive), and in redirect_to
37
+ it executes the expects as stubs (:stub!), just as above.
75
38
 
76
39
  For more options, information and configuration, check macro stubs documentation.
77
40
 
78
41
  # v2.x
79
42
 
80
43
  [ENHANCMENT] Added assign_to, filter_params, render_with_layout, respond_with
81
- respond_with_content_type, set_session and set_the_flash matchers.
44
+ respond_with_content_type, route, set_session and set_the_flash matchers.
data/README CHANGED
@@ -1,2 +1,83 @@
1
- Remarkable Rails
2
- ================
1
+ = Remarkable Rails
2
+
3
+ Remarkable Rails is a collection of matchers to Rails. This package has some
4
+ ActionController matchers and soon some ActionView matchers.
5
+
6
+ Whenever using the Remarkable Rails gem and ActiveRecord, it will automatically
7
+ add your ActiveRecord matchers. So just one line is needed to install both:
8
+
9
+ sudo gem install remarkable_rails
10
+
11
+ == Matchers & Macros
12
+
13
+ The supported matchers and macros are:
14
+
15
+ assign_to, filter_params, render_with_layout, respond_with,
16
+ respond_with_content_type, route, set_session and set_the_flash matchers.
17
+
18
+ In Remarkable 3.0, we also ported and extended redirect to and render template
19
+ from rspec rails matchers to provide I18n. You can also do:
20
+
21
+ render_template 'edit', :layout => 'default'
22
+ respond_with 404, :content_type => Mime::XML, :body => /Not found/
23
+
24
+ == Macro stubs
25
+
26
+ Another cool feature in Remarkable 3.0 is macro stubs, which makes your mocks
27
+ and stubs DRY and easier to maintain. An rspec default scaffold would be:
28
+
29
+ describe TasksController do
30
+ def mock_task(stubs={})
31
+ @task ||= mock_model(Task, stubs)
32
+ end
33
+
34
+ describe “responding to #POST create” do
35
+ it "exposes a newly created task as @task" do
36
+ Task.should_receive(:new).with({'these' => 'params'}).
37
+ and_return(mock_task(:save => true))
38
+ post :create, :task => {:these => 'params'}
39
+ assigns[:task].should equal(mock_task)
40
+ end
41
+
42
+ it "redirects to the created task" do
43
+ Task.stub!(:new).and_return(mock_task(:save => true))
44
+ post :create, :task => {}
45
+ response.should redirect_to(task_url(mock_task))
46
+ end
47
+ end
48
+ end
49
+
50
+ An equivalent in remarkable would be:
51
+
52
+ describe TasksController do
53
+ mock_models :task
54
+
55
+ describe :post => :create, :task => { :these => 'params' } do
56
+ expects :new, :on => Task, with => {'these' => 'params'}, :returns => mock_task
57
+ expects :save, :on => mock_task, :returns => true
58
+
59
+ should_assign_to :task, :with => mock_task
60
+ should_redirect_to { task_url(mock_task) }
61
+ end
62
+ end
63
+
64
+ It automatically performs the action before running each macro. In assign_to,
65
+ it executes the expects as expectations (:should_receive), and in redirect_to
66
+ it executes the expects as stubs (:stub!), just as above.
67
+
68
+ There are also params and mime methods:
69
+
70
+ describe TasksController
71
+ params :project_id => 42
72
+ mime Mime::HTML
73
+
74
+ describe :get => :show, :id => 37 do
75
+ should_assign_to :project, :task
76
+
77
+ describe Mime::XML do
78
+ should_assign_to :project, :task
79
+ end
80
+ end
81
+ end
82
+
83
+ And much more. Be sure to check macro stubs documentation.
@@ -12,11 +12,11 @@ module Remarkable
12
12
  # Before assertions, call run_action! to perform the action if it was
13
13
  # not performed yet.
14
14
  #
15
- def perform_action_with_macro_stubs
15
+ def perform_action_with_macro_stubs #:nodoc:
16
16
  @spec.send(:run_action!, run_with_expectations?) if @spec.send(:controller)
17
17
  end
18
18
 
19
- def run_with_expectations?
19
+ def run_with_expectations? #:nodoc:
20
20
  if @options.key?(:with_stubs)
21
21
  !@options[:with_stubs]
22
22
  elsif @options.key?(:with_expectations)
@@ -1,518 +1,493 @@
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)
1
+ module Remarkable
2
+ module ActionController
3
+
4
+ # Macro stubs makes stubs and expectations easier, more readable and DRY.
5
+ #
6
+ # == Example
7
+ #
8
+ # Let's jump off to an example:
9
+ #
10
+ # describe ProjectsController do
11
+ # describe :get => :show, :id => 37 do
12
+ # expects :find, :on => Project, :with => '37', :returns => proc { mock_project }
13
+ #
14
+ # should_assign_to :project, :with => proc { mock_project }
15
+ # should_render_template 'show'
16
+ #
17
+ # describe Mime::XML do
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 a mock project and then should assign to
26
+ # project and render template 'show'.
27
+ #
28
+ # Each macro before asserting will check if an action was already performed and
29
+ # if not, it runs the expectations and call the action.
30
+ #
31
+ # In other words, should assign to macro is basically doing:
32
+ #
33
+ # it 'should assign to project' do
34
+ # Project.should_receive(:find).with('37').and_return(mock_project)
35
+ # get :show, :id => '37'
36
+ # assigns(:project).should == mock_project
37
+ # end
38
+ #
39
+ # On the other hand, should render template is doing something like this:
40
+ #
41
+ # it 'should render template show' do
42
+ # Project.stub!(:find).and_return(mock_project)
43
+ # get :show, :id => '37'
44
+ # response.should render_template('show')
45
+ # end
46
+ #
47
+ # Now comes the first question: how each macro knows if they should perform
48
+ # expectations or stubs?
49
+ #
50
+ # By default, only should_assign_to macro performs expectations. You can change
51
+ # this behavior sending :with_stubs or :with_expectations as options:
52
+ #
53
+ # should_assign_to :project, :with_stubs => true
54
+ # should_render_template 'show', :with_expectations => true
55
+ #
56
+ # This also works in the rspec way:
57
+ #
58
+ # it { should assign_to(:project).with_stubs }
59
+ # it { should render_tempalte('show').with_expectations }
60
+ #
61
+ # == mock_models
62
+ #
63
+ # You don't have to play with proc all the time. You can call mock_models which
64
+ # creates a class method that simply returns a proc and a instance method that
65
+ # do the actual mock. In other words, it creates:
66
+ #
67
+ # def self.mock_project
68
+ # proc { mock_project }
69
+ # end
70
+ #
71
+ # def mock_project(stubs={})
72
+ # @project ||= mock_model(Project, stubs)
73
+ # end
74
+ #
75
+ # Then you can replace those lines:
76
+ #
77
+ # expects :find, :on => Project, :with => '37', :returns => proc { mock_project }
78
+ # should_assign_to :project, :with => proc { mock_project }
79
+ #
80
+ # For:
81
+ #
82
+ # expects :find, :on => Project, :with => '37', :returns => mock_project
83
+ # should_assign_to :project, :with => mock_project
84
+ #
85
+ # = Give me more!
86
+ #
87
+ # If you need to specify the describe description, you can also do:
88
+ #
89
+ # describe 'my description' do
90
+ # get :show, :id => 37
91
+ #
92
+ # Which is the same as above.
93
+ #
94
+ # Things start to get even better when we start to talk about nested resources.
95
+ # After our ProjectsController is created, we want to create a TasksController:
96
+ #
97
+ # describe TasksController do
98
+ # params :project_id => '42' #=> define params for all requests
99
+ #
100
+ # # Those two expectations get inherited in all describe groups below
101
+ # expects :find_by_title, :on => Project, :with => '42', :returns => mock_project
102
+ # expects :tasks, :and_return => Task
103
+ #
104
+ # describe :get => :show, :id => '37' do
105
+ # expects :find, :with => '37', :and_return => mock_task
106
+ #
107
+ # should_assign_to :project, :task
108
+ # should_render_template 'show'
109
+ # end
110
+ # end
111
+ #
112
+ # As you noticed, you can define parameters that will be available to all requests,
113
+ # using the method <tt>params</tt>.
114
+ #
115
+ # Finally, if you used expects chain like above, but need to write a spec by
116
+ # hand you can invoke the action and expectations with run_expectations!,
117
+ # run_stubs! and run_action!. Examples:
118
+ #
119
+ # describe :get => :new do
120
+ # expects :new, :on => Project, :returns => mock_project
121
+ #
122
+ # it "should do something different" do
123
+ # run_action!
124
+ # # do you assertions here
125
+ # end
126
+ # end
127
+ #
128
+ # = Performance!
129
+ #
130
+ # Remarkable comes with a new way to speed up your tests. It perform the action
131
+ # inside a before(:all), so you can do:
132
+ #
133
+ # describe "responding to GET show" do
134
+ # get! :show, :id => 37
135
+ #
136
+ # should_assign_to :task
137
+ # should_render_template :show
138
+ # end
139
+ #
140
+ # Or in the compact way:
141
+ #
142
+ # describe :get! => :show, :id => 37
143
+ #
144
+ # The action will be performed just once before asserting the assignment and
145
+ # the template. If any error happens while performing the action rspec will
146
+ # output an error but ALL the examples inside the example group (describe) won't
147
+ # be run.
148
+ #
149
+ # By now, the bang methods works only when integrate_views are true and this is
150
+ # when you must have the bigger performance gain.
151
+ #
152
+ # This comes with some rspec and rspec rails tweakings. So if you want to do
153
+ # something before the action is performed (stubs something or log someone in
154
+ # session), you have to do it giving a block to the action method:
155
+ #
156
+ # get! :show, :id => 37 do
157
+ # login_as(mock_user)
158
+ # end
159
+ #
160
+ # You can still use the compact way and give the block:
161
+ #
162
+ # describe :get => :show, :id => 37 do
163
+ # get! do
164
+ # login_as(mock_user)
165
+ # end
166
+ # end
167
+ #
168
+ module MacroStubs
169
+ HTTP_VERBS_METHODS = [:get, :get!, :post, :post!, :put, :put!, :delete, :delete!]
170
+
171
+ def self.included(base) #:nodoc:
172
+ base.extend ClassMethods
173
+ base.class_inheritable_reader :expects_chain, :default_action, :default_mime,
174
+ :default_verb, :default_params, :before_all_block
175
+ end
176
+
177
+ module ClassMethods
178
+
179
+ # Creates a chain that will be evaluated as stub or expectation. The
180
+ # first parameter is the method expected.
181
+ #
182
+ # == Options
183
+ #
184
+ # * <tt>:on</tt> - Tell which object will receive the expected method.
185
+ # This option is always required.
186
+ #
187
+ # * <tt>:with</tt> - Tell each parameters will be sent with the expected
188
+ # method. This option is used only in expectations and is optional.
189
+ #
190
+ # * <tt>:returns</tt> - Tell what the expectations should return. Not
191
+ # required.
192
+ #
193
+ # * <tt>:times</tt> - The number of times the object will receive the
194
+ # method. Used only in expectations and when not given, defaults to 1.
195
+ #
196
+ # == Example
197
+ #
198
+ # expects :new, :on => Project, :returns => :mock_project, :times => 2
199
+ #
200
+ def expects(*args)
201
+ write_inheritable_array(:expects_chain, [args])
202
+ end
203
+
204
+ # The mime type of the request. The value given will be called transformed
205
+ # into a string and set in the @request.env['HTTP_ACCEPT'] variable.
206
+ #
207
+ # == Examples
208
+ #
209
+ # mime Mime::XML
210
+ # mime 'application/xml+rss'
211
+ #
212
+ def mime(mime)
213
+ write_inheritable_attribute(:default_mime, mime.to_s)
214
+ end
215
+
216
+ # The params used for the request. Calls are always nested:
217
+ #
218
+ # == Examples
219
+ #
220
+ # describe TasksController do
221
+ # params :project_id => 42
222
+ #
223
+ # describe :get => :show, :id => 37 do
224
+ # # will request with params {:id => 37, :project_id => 42}
225
+ # end
226
+ # end
227
+ #
228
+ def params(params)
229
+ write_inheritable_hash(:default_params, params)
230
+ end
231
+
232
+ [:get, :post, :put, :delete].each do |verb|
233
+ module_eval <<-VERB, __FILE__, __LINE__
234
+ # Declares that we want to do a #{verb} request in the given action
235
+ # and with the given params.
236
+ #
237
+ # == Examples
238
+ #
239
+ # #{verb} :action, :id => 42
240
+ #
241
+ def #{verb}(action, params={})
242
+ params(params)
243
+ write_inheritable_attribute(:default_verb, #{verb.inspect})
244
+ write_inheritable_attribute(:default_action, action)
245
+ end
246
+ VERB
247
+ end
248
+
249
+ [:get!, :post!, :put!, :delete!].each do |verb|
250
+ module_eval <<-VERB, __FILE__, __LINE__
251
+ # Declares that we want to do a #{verb} request in the given action
252
+ # and with the given params, but the action is performed just once
253
+ # in the describe group. In other words, it's performed in a
254
+ # before(:all) filter.
255
+ #
256
+ # == Examples
257
+ #
258
+ # #{verb} :action, :id => 42
259
+ #
260
+ def #{verb}(action=nil, params={}, &block)
286
261
  #{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
262
+ write_inheritable_array(:before_all_block, [block]) if block
263
+ run_callbacks_once!
264
+ end
265
+ VERB
266
+ end
267
+
268
+ # Undefine the method run_callbacks so rspec won't run them in the
269
+ # before and after :each cycle. Then we redefine it as run_callbacks_once,
270
+ # which will be used as an before(:all) and after(:all) filter.
271
+ #
272
+ def run_callbacks_once!(&block) #:nodoc:
273
+ unless instance_methods.any?{|m| m.to_s == 'run_callbacks_once' }
274
+ alias_method :run_callbacks_once, :run_callbacks
275
+ class_eval "def run_callbacks(*args); end"
276
+
277
+ before(:all) do
278
+ setup_mocks_for_rspec
304
279
  run_callbacks_once :setup
305
280
 
306
281
  before_all_block.each do |block|
307
282
  instance_eval(&block)
308
283
  end if before_all_block
309
-
284
+
310
285
  run_action!
311
286
  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
287
+ teardown_mocks_for_rspec
288
+ end
289
+
290
+ after(:all) do
291
+ run_callbacks_once :teardown
292
+ end
293
+ end
294
+ end
295
+
296
+ # Overwrites describe to provide quick action description with I18n.
297
+ #
298
+ # You can now do:
299
+ #
300
+ # describe :get => :show, :id => 37
301
+ #
302
+ # Which is the same as:
303
+ #
304
+ # describe 'responding to #GET show' do
305
+ # get :show, :id => 37
306
+ #
307
+ # And do this:
308
+ #
309
+ # describe Mime::XML
310
+ #
311
+ # Which is the same as:
312
+ #
313
+ # describe 'with xml' do
314
+ # mime Mime::XML
315
+ #
316
+ # The string can be localized using I18n. An example yml file is:
317
+ #
318
+ # locale:
319
+ # remarkable:
320
+ # action_controller:
321
+ # responding: "responding to #{{verb}} {{action}}"
322
+ # mime_type: "with {{format}} ({{content_type}})"
323
+ #
324
+ # And load the locale file with:
325
+ #
326
+ # Remarkable.add_locale locale_path
327
+ #
328
+ def describe(*args, &block)
329
+ options = args.first.is_a?(Hash) ? args.first : {}
330
+ verb = (options.keys & HTTP_VERBS_METHODS).first
331
+
332
+ if verb
333
+ action = options.delete(verb)
334
+ verb = verb.to_s
335
+
336
+ description = Remarkable.t 'remarkable.action_controller.responding',
337
+ :default => "responding to ##{verb.upcase} #{action}",
338
+ :verb => verb.sub('!', '').upcase, :action => action
339
+
340
+ send_args = [ verb, action, options ]
341
+ elsif args.first.is_a?(Mime::Type)
342
+ mime = args.first
343
+
344
+ description = Remarkable.t 'remarkable.action_controller.mime_type',
345
+ :default => "with #{mime.to_sym}",
346
+ :format => mime.to_sym, :content_type => mime.to_s
347
+
348
+ send_args = [ :mime, mime ]
349
+ else # return if no special type was found
350
+ return super(*args, &block)
351
+ end
352
+
353
+ args.shift
354
+ args.unshift(description)
355
+
356
+ # Creates an example group, send the method and eval the given block.
357
+ #
358
+ example_group = super(*args) do
359
+ send(*send_args)
360
+ instance_eval(&block)
361
+ end
362
+ end
363
+
364
+ # Creates mock methods automatically.
365
+ #
366
+ # == Options
367
+ #
368
+ # * <tt>:class_method</tt> - When set to false, does not create the
369
+ # class method which returns a proc.
370
+ #
371
+ # == Examples
372
+ #
373
+ # Doing this:
374
+ #
375
+ # describe ProjectsController do
376
+ # mock_models :project
377
+ # end
378
+ #
379
+ # Will create a class and instance mock method for you:
380
+ #
381
+ # def self.mock_project
382
+ # proc { mock_project }
383
+ # end
384
+ #
385
+ # def mock_project(stubs={})
386
+ # @project ||= mock_model(Project, stubs)
387
+ # end
388
+ #
389
+ # If you want to create just the instance method, you can give
390
+ # :class_method => false as option.
391
+ #
392
+ def mock_models(*models)
393
+ options = models.extract_options!
394
+ options = { :class_method => true }.merge(options)
395
+
396
+ models.each do |model|
397
+ self.class_eval <<-METHOD
398
+ #{"def self.mock_#{model}; proc { mock_#{model} }; end" if options[:class_method]}
399
+
400
+ def mock_#{model}(stubs={})
401
+ @#{model} ||= mock_model(#{model.to_s.classify}, stubs)
402
+ end
403
+ METHOD
404
+ end
405
+ end
406
+
407
+ end
408
+
409
+ protected
410
+
411
+ # Evaluates the expectation chain as stub or expectations.
412
+ #
413
+ def evaluate_expectation_chain(use_expectations=true) #:nodoc:
414
+ return if self.expects_chain.nil?
415
+
416
+ self.expects_chain.each do |method, default_options|
417
+ options = default_options.dup
418
+
419
+ # Those are used both in expectations and stubs
420
+ object = evaluate_value(options.delete(:on))
421
+ return_value = evaluate_value(options.delete(:returns))
422
+
423
+ raise ScriptError, "You have to give me :on as an option when calling :expects." if object.nil?
424
+
425
+ if use_expectations
426
+ with = evaluate_value(options.delete(:with))
427
+ times = options.delete(:times) || 1
428
+
429
+ chain = object.should_receive(method)
430
+ chain = chain.with(with) if with
431
+ chain = chain.exactly(times).times
432
+ else
433
+ chain = object.stub!(method)
434
+ end
435
+ chain = chain.and_return(return_value)
436
+ end
437
+ end
438
+
439
+ # Instance method run_stubs! if someone wants to declare additional
440
+ # tests and call the stubs inside of it.
441
+ #
442
+ def run_stubs!
443
+ evaluate_expectation_chain(false)
444
+ end
445
+
446
+ # Instance method run_expectations! if someone wants to declare
447
+ # additional tests and call the stubs inside of it.
448
+ #
449
+ def run_expectations!
450
+ evaluate_expectation_chain(true)
451
+ end
452
+
453
+ # Run the action declared in the describe group, but before runs also
454
+ # the expectations. If an action was already performed, it doesn't run
455
+ # anything at all and returns false.
456
+ #
457
+ # The first parameter is if you want to run expectations or stubs. You
458
+ # can also supply the verb (get, post, put or delete), which action to
459
+ # call, parameters and the mime type. If any of those parameters are
460
+ # supplied, they override the current definition.
461
+ #
462
+ def run_action!(use_expectations=true, verb=nil, action=nil, params=nil, mime=nil)
463
+ return false if controller.send(:performed?)
464
+
465
+ evaluate_expectation_chain(use_expectations)
466
+
467
+ mime ||= default_mime
468
+ verb ||= default_verb
469
+ action ||= default_action
470
+ params ||= default_params
471
+
472
+ raise ScriptError, "No action was performed or declared." unless verb && action
473
+
474
+ request.env["HTTP_ACCEPT"] ||= mime.to_s if mime
475
+ send(verb, action, params)
476
+ end
477
+
478
+ # Evaluate a given value.
479
+ #
480
+ # This allows procs to be given to the expectation chain and they will
481
+ # be evaluated in the instance binding.
482
+ #
483
+ def evaluate_value(duck) #:nodoc:
484
+ if duck.is_a?(Proc)
485
+ self.instance_eval(&duck)
486
+ else
487
+ duck
488
+ end
489
+ end
490
+
491
+ end
492
+ end
493
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remarkable_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Brando
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-04-09 00:00:00 +02:00
13
+ date: 2009-04-10 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -31,7 +31,7 @@ dependencies:
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: 3.0.0
34
+ version: 3.0.1
35
35
  version:
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: remarkable_activerecord
@@ -41,7 +41,7 @@ dependencies:
41
41
  requirements:
42
42
  - - ">="
43
43
  - !ruby/object:Gem::Version
44
- version: 3.0.0
44
+ version: 3.0.1
45
45
  version:
46
46
  description: "Remarkable Rails: collection of matchers and macros with I18n for Rails"
47
47
  email: