remarkable_rails 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: