remarkable_rails 3.1.0 → 3.1.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,3 +1,28 @@
1
+ * mock_models now creates a second class method to be used on the index action [#71]
2
+ In other words, mock_models :project will create:
3
+
4
+ def self.mock_project
5
+ proc { mock_project }
6
+ end
7
+
8
+ # This was added to be used on index actions
9
+ def self.mock_projects
10
+ proc { [ mock_project ] }
11
+ end
12
+
13
+ def mock_project(stubs={})
14
+ @project ||= mock_model(Project, stubs)
15
+ end
16
+
17
+ * Allow multiple args to be given to :with in expects. If you need to verify that
18
+ an array is being sent, you need to send an array inside another array [#70]
19
+
20
+ * Allow procs or blocks to be given to respond_with_body and respond_with :body [#67]
21
+
22
+ * Allow ordered to be given to macro stubs as option [#66]
23
+
24
+ * Allow multiple methods to be given to expects [#65]
25
+
1
26
  # v3.1
2
27
 
3
28
  * Ensure set_cookies and set_session work with arrays [#55]
@@ -56,12 +56,27 @@ module Remarkable
56
56
  # This also works in the rspec way:
57
57
  #
58
58
  # it { should assign_to(:project).with_stubs }
59
- # it { should render_tempalte('show').with_expectations }
59
+ # it { should render_template('show').with_expectations }
60
+ #
61
+ # == Attention!
62
+ #
63
+ # If you need to check that an array is being sent to a method, you need to
64
+ # give an array inside another array, for example:
65
+ #
66
+ # expects :comment_ids=, :on => Post, :with => [1,2,3]
67
+ #
68
+ # Is the same as:
69
+ #
70
+ # Post.comment_ids = (1, 2, 3)
71
+ #
72
+ # And it won't work. The right way to handle this is:
73
+ #
74
+ # expects :comment_ids=, :on => Post, :with => [[1,2,3]]
60
75
  #
61
76
  # == mock_models
62
77
  #
63
78
  # 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
79
+ # creates two class methods that simply returns a proc and a instance method that
65
80
  # do the actual mock.
66
81
  #
67
82
  # describe ProjectsController do
@@ -71,6 +86,11 @@ module Remarkable
71
86
  #
72
87
  # def self.mock_project
73
88
  # proc { mock_project }
89
+ # end
90
+ #
91
+ # # To be used on index actions
92
+ # def self.mock_projects
93
+ # proc { [mock_project] }
74
94
  # end
75
95
  #
76
96
  # def mock_project(stubs={})
@@ -180,8 +200,9 @@ module Remarkable
180
200
  module ClassMethods
181
201
 
182
202
  # Creates a chain that will be evaluated as stub or expectation. The
183
- # first parameter is the method expected. Also, a block can be given
184
- # to calculate the returned value. See examples below.
203
+ # first parameter is the method expected. You can also specify multiple
204
+ # methods to stub and give a block to calculate the returned value. See
205
+ # examples below.
185
206
  #
186
207
  # == Options
187
208
  #
@@ -195,18 +216,26 @@ module Remarkable
195
216
  # required.
196
217
  #
197
218
  # * <tt>:times</tt> - The number of times the object will receive the
198
- # method. Used only in expectations and when not given, defaults to 1.
219
+ # method. Used only in expectations and when not given, defaults to 1.
220
+ #
221
+ # * <tt>:ordered</tt> - When true specifies that expectations should
222
+ # be received in order.
199
223
  #
200
224
  # == Example
201
225
  #
202
226
  # expects :new, :on => Project, :returns => :mock_project, :times => 2
203
227
  #
228
+ # expects :new, :find, :on => Project, :returns => :mock_project
229
+ #
204
230
  # expects :human_attribute_name, :on => Project, :with => :title do |attr|
205
231
  # attr.to_s.humanize
206
232
  # end
207
233
  #
208
234
  def expects(*args, &block)
209
- write_inheritable_array(:expects_chain, [args << block])
235
+ options = args.extract_options!
236
+ args.each do |arg|
237
+ write_inheritable_array(:expects_chain, [ [ arg, options, block] ])
238
+ end
210
239
  end
211
240
 
212
241
  # The mime type of the request. The value given will be called transformed
@@ -396,15 +425,20 @@ module Remarkable
396
425
  # mock_models :project
397
426
  # end
398
427
  #
399
- # Will create a class and instance mock method for you:
428
+ # Will create one instance and two class mock methods for you:
400
429
  #
401
430
  # def self.mock_project
402
431
  # proc { mock_project }
432
+ # end
433
+ #
434
+ # # To be used on index actions
435
+ # def self.mock_projects
436
+ # proc { [ mock_project ] }
403
437
  # end
404
438
  #
405
439
  # def mock_project(stubs={})
406
440
  # @project ||= mock_model(Project, stubs)
407
- # end
441
+ # end
408
442
  #
409
443
  # If you want to create just the instance method, you can give
410
444
  # :class_method => false as option.
@@ -413,12 +447,14 @@ module Remarkable
413
447
  options = models.extract_options!
414
448
  options = { :class_method => true }.merge(options)
415
449
 
416
- models.each do |model|
450
+ models.each do |model|
451
+ model = model.to_s
417
452
  self.class_eval <<-METHOD
418
- #{"def self.mock_#{model}; proc { mock_#{model} }; end" if options[:class_method]}
453
+ #{"def self.mock_#{model}; proc { mock_#{model} }; end" if options[:class_method]}
454
+ #{"def self.mock_#{model.pluralize}; proc { [ mock_#{model} ] }; end" if options[:class_method]}
419
455
 
420
456
  def mock_#{model}(stubs={})
421
- @#{model} ||= mock_model(#{model.to_s.classify}, stubs)
457
+ @#{model} ||= mock_model(#{model.classify}, stubs)
422
458
  end
423
459
  METHOD
424
460
  end
@@ -433,19 +469,22 @@ module Remarkable
433
469
  def evaluate_expectation_chain(use_expectations=true) #:nodoc:
434
470
  return if self.expects_chain.nil?
435
471
 
436
- self.expects_chain.each do |method, default_options, block|
437
- options = default_options.dup
438
-
439
- # Those are used both in expectations and stubs
440
- object = evaluate_value(options.delete(:on))
441
- return_value = evaluate_value(options.delete(:returns))
442
-
472
+ self.expects_chain.each do |method, options, block|
473
+ object = evaluate_value(options[:on])
443
474
  raise ScriptError, "You have to give me :on as an option when calling :expects." if object.nil?
444
475
 
445
476
  if use_expectations
446
- chain = object.should_receive(method)
447
- chain = chain.with(evaluate_value(options.delete(:with))) if options.key?(:with)
448
- chain = chain.exactly(options.delete(:times) || 1).times
477
+ chain = object.should_receive(method)
478
+
479
+ if options.key?(:with)
480
+ with = evaluate_value(options[:with])
481
+ chain = chain.with(*with)
482
+ end
483
+
484
+ times = options[:times] || 1
485
+ chain = chain.exactly(times).times
486
+
487
+ chain = chain.ordered if options[:ordered]
449
488
  else
450
489
  chain = object.stub!(method)
451
490
  end
@@ -453,6 +492,7 @@ module Remarkable
453
492
  chain = if block
454
493
  chain.and_return(&block)
455
494
  else
495
+ return_value = evaluate_value(options[:returns])
456
496
  chain.and_return(return_value)
457
497
  end
458
498
  end
@@ -122,23 +122,26 @@ module Remarkable
122
122
  # Extensions check does not work in Rails 2.1.x.
123
123
  #
124
124
  def render_template(*args, &block)
125
- options = args.extract_options!
126
- RenderTemplateMatcher.new(options.merge(:template => args.first), &block).spec(self)
125
+ options = args.extract_options!
126
+ options.merge!(:template => args.first)
127
+ RenderTemplateMatcher.new(options, &block).spec(self)
127
128
  end
128
129
 
129
130
  # This is just a shortcut for render_template :layout => layout. It's also
130
131
  # used for Shoulda compatibility. Check render_template for more information.
131
132
  #
132
133
  def render_with_layout(*args, &block)
133
- options = args.extract_options!
134
- RenderTemplateMatcher.new(options.merge(:layout => args.first), &block).spec(self)
134
+ options = args.extract_options!
135
+ options.merge!(:layout => args.first)
136
+ RenderTemplateMatcher.new(options, &block).spec(self)
135
137
  end
136
138
 
137
139
  # This is just a shortcut for render_template :layout => nil. It's also
138
140
  # used for Shoulda compatibility. Check render_template for more information.
139
141
  #
140
- def render_without_layout(options={}, &block)
141
- RenderTemplateMatcher.new(options.merge(:layout => nil), &block).spec(self)
142
+ def render_without_layout(options={}, &block)
143
+ options.merge!(:layout => nil)
144
+ RenderTemplateMatcher.new(options, &block).spec(self)
142
145
  end
143
146
 
144
147
  end
@@ -2,7 +2,7 @@ module Remarkable
2
2
  module ActionController
3
3
  module Matchers
4
4
  class RespondWithMatcher < Remarkable::ActionController::Base #:nodoc:
5
- arguments
5
+ arguments :block => true
6
6
 
7
7
  optional :with, :body, :content_type
8
8
 
@@ -11,7 +11,7 @@ module Remarkable
11
11
  @controller = @spec.instance_variable_get('@controller')
12
12
  end
13
13
 
14
- before_assert :evaluate_content_type
14
+ before_assert :evaluate_content_type, :evaluate_body
15
15
 
16
16
  assertions :status_matches?, :body_matches?, :content_type_matches?
17
17
 
@@ -45,7 +45,6 @@ module Remarkable
45
45
  assert_contains(@response.content_type, @options[:content_type])
46
46
  end
47
47
 
48
- # Evaluate content_type before assertions to have nice descriptions
49
48
  def evaluate_content_type
50
49
  return unless @options.key?(:content_type)
51
50
 
@@ -57,6 +56,14 @@ module Remarkable
57
56
  else
58
57
  @options[:content_type].to_s
59
58
  end
59
+ end
60
+
61
+ def evaluate_body
62
+ if @options.key?(:body) || @block
63
+ value = @options.key?(:body) ? @options[:body] : @block
64
+ value = @spec.instance_eval(&value) if value.is_a?(Proc)
65
+ @options[:body] = value
66
+ end
60
67
  end
61
68
 
62
69
  def interpolation_options
@@ -98,16 +105,20 @@ module Remarkable
98
105
  # it { should respond_with(300..399).content_type(Mime::XML) }
99
106
  #
100
107
  def respond_with(*args, &block)
101
- options = args.extract_options!
102
- RespondWithMatcher.new(options.merge(:with => args.first), &block).spec(self)
108
+ options = args.extract_options!
109
+ options.merge!(:with => args.first)
110
+ RespondWithMatcher.new(options, &block).spec(self)
103
111
  end
104
112
 
105
113
  # This is just a shortcut for respond_with :body => body. Check respond_with
106
114
  # for more information.
107
115
  #
108
116
  def respond_with_body(*args, &block)
109
- options = args.extract_options!
110
- RespondWithMatcher.new(options.merge(:body => args.first), &block).spec(self)
117
+ options = args.extract_options!
118
+ # Since body can be also given as block, only merge if any arguments was
119
+ # actually sent.
120
+ options.merge!(:body => args.first) unless args.empty?
121
+ RespondWithMatcher.new(options, &block).spec(self)
111
122
  end
112
123
 
113
124
  # This is just a shortcut for respond_with :content_type => content_type.
@@ -115,8 +126,9 @@ module Remarkable
115
126
  # information.
116
127
  #
117
128
  def respond_with_content_type(*args, &block)
118
- options = args.extract_options!
119
- RespondWithMatcher.new(options.merge(:content_type => args.first), &block).spec(self)
129
+ options = args.extract_options!
130
+ options.merge!(:content_type => args.first)
131
+ RespondWithMatcher.new(options, &block).spec(self)
120
132
  end
121
133
 
122
134
  end
@@ -10,15 +10,22 @@ describe 'MacroStubs' do
10
10
  def current_id; '37'; end
11
11
 
12
12
  describe 'mock_models' do
13
- before(:each) do
14
- self.class.metaclass.send(:undef_method, :mock_project) if self.class.respond_to?(:mock_project)
15
- self.class.send(:undef_method, :mock_project) if self.respond_to?(:mock_project)
13
+ before(:each) do
14
+ self.class.metaclass.send(:undef_method, :mock_projects) if self.class.respond_to?(:mock_projects)
15
+ self.class.metaclass.send(:undef_method, :mock_project) if self.class.respond_to?(:mock_project)
16
+ self.class.send(:undef_method, :mock_project) if self.respond_to?(:mock_project)
16
17
  end
17
18
 
18
- it 'should create a class mock method' do
19
+ it 'should create a class singular mock method' do
19
20
  self.class.respond_to?(:mock_project).should be_false
20
21
  self.class.mock_models :project
21
22
  self.class.respond_to?(:mock_project).should be_true
23
+ end
24
+
25
+ it 'should create a class plural mock method' do
26
+ self.class.respond_to?(:mock_projects).should be_false
27
+ self.class.mock_models :project
28
+ self.class.respond_to?(:mock_projects).should be_true
22
29
  end
23
30
 
24
31
  it 'should create an instance mock method' do
@@ -35,18 +42,66 @@ describe 'MacroStubs' do
35
42
  self.respond_to?(:mock_project).should be_true
36
43
  end
37
44
 
38
- it 'should create procs which evals to mocks dynamically' do
45
+ it 'should create procs which evals to a mock dynamically' do
39
46
  proc = self.class.mock_task
40
47
  proc.should be_kind_of(Proc)
41
48
 
42
- self.instance_variable_get('@task').should be_nil
43
- instance_eval(&proc)
44
- self.instance_variable_get('@task').should_not be_nil
49
+ @task.should be_nil
50
+ instance_eval(&proc).should == mock_task
51
+ @task.should_not be_nil
52
+ end
53
+
54
+ it 'should create procs which evals to an array of mocks dynamically' do
55
+ proc = self.class.mock_tasks
56
+ proc.should be_kind_of(Proc)
57
+
58
+ @task.should be_nil
59
+ instance_eval(&proc).should == [ mock_task ]
60
+ @task.should == mock_task
45
61
  end
62
+ end
63
+
64
+ describe 'failures' do
65
+ expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
66
+ expects :max, :min, :count, :on => Task, :ordered => true
67
+
68
+ get :show, :id => 37
69
+
70
+ it 'should fail if expectation is not met' do
71
+ self.stub!(:current_id).and_return("42")
72
+
73
+ lambda {
74
+ run_action!(true)
75
+ }.should raise_error(Spec::Mocks::MockExpectationError, /expected :find with \("42"\) but received it with \("37"\)/)
76
+ end
77
+
78
+ it 'should fail if expectations are received out of order' do
79
+ lambda {
80
+ run_action!(true)
81
+ }.should raise_error(Spec::Mocks::MockExpectationError, /received :count out of order/)
82
+ end
83
+
84
+ it 'should splat an array given to with' do
85
+ self.stub!(:current_id).and_return([1, 2, 3])
86
+ run_expectations!
87
+
88
+ lambda {
89
+ Task.find([1,2,3])
90
+ }.should raise_error(Spec::Mocks::MockExpectationError, /expected :find with \(1\, 2\, 3\) but received it with \(\[1\, 2\, 3\]\)/)
91
+
92
+ lambda {
93
+ Task.find(1, 2, 3)
94
+ }.should_not raise_error
95
+ end
96
+
97
+ after(:each) do
98
+ teardown_mocks_for_rspec
99
+ end
46
100
  end
47
101
 
48
102
  describe 'when extending describe group behavior' do
49
- expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
103
+ expects :find, :on => Task, :with => proc{ current_id }, :returns => mock_task
104
+ expects :count, :max, :min, :on => Task
50
105
 
51
106
  get :show, :id => 37
52
107
  params :special_task_id => 42
@@ -89,8 +144,8 @@ describe 'MacroStubs' do
89
144
  it 'should run expectations without performing an action' do
90
145
  self.should_receive(:current_id).once.and_return('37')
91
146
  run_expectations!
92
- @controller.send(:performed?).should_not be_true
93
- Task.find('37') # Execute expectations by hand
147
+ @controller.send(:performed?).should_not be_true
148
+ get :show, :id => '37' # Execute the action to match expectations
94
149
  end
95
150
 
96
151
  it 'should run action with stubs' do
@@ -77,7 +77,9 @@ describe 'respond_with' do
77
77
  before(:each) { build_response { respond_to{ |format| format.xml { render :xml => [].to_xml } } } }
78
78
 
79
79
  it { should respond_with_body(%{<?xml version="1.0" encoding="UTF-8"?>\n<nil-classes type="array"/>\n}) }
80
- it { should respond_with_body(/xml/) }
80
+ it { should respond_with_body(/xml/) }
81
+ it { should respond_with_body{/xml/} }
82
+ it { should respond_with_body proc{/xml/} }
81
83
  it { should_not respond_with_body('html') }
82
84
  it { should_not respond_with_body(/html/) }
83
85
  end
@@ -11,7 +11,12 @@ class TasksController < ApplicationController
11
11
  end
12
12
 
13
13
  def show
14
- @task = Task.find(params[:id])
14
+ @task = Task.find(params[:id])
15
+
16
+ # Multiple expects
17
+ Task.count
18
+ Task.max
19
+ Task.min
15
20
 
16
21
  respond_to do |format|
17
22
  format.html { render :text => 'show' }
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.1.0
4
+ version: 3.1.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-05-04 00:00:00 +02:00
13
+ date: 2009-05-13 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.1.0
34
+ version: 3.1.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.1.0
44
+ version: 3.1.1
45
45
  version:
46
46
  description: "Remarkable Rails: collection of matchers and macros with I18n for Rails"
47
47
  email: