rspec-activemodel-mocks 1.0.0.beta1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5a5cc1ea66ca12596ba1723b13be6ada5fbcc6bc
4
+ data.tar.gz: 9bad54a7e796d1465ecf0922b6d11d32e74c0b80
5
+ SHA512:
6
+ metadata.gz: 17a71ff3a6b9b8ce1ef5878966b11ad2cf549499cb09aeb02d1ae3eea0800fc4ba5de63365298d0406e7c86a273d78f52cabb53de84ad72f70ebcc09dd3de5f1
7
+ data.tar.gz: 94d431c9b32d5fea92dfdb428d3156dfc526a8e22ca6d489c0225a3f3fb7224c25fa9c93d1fc51838fc2c6f195e0154ba1d93b5d5177ba48873b19937fab4015
data/.yardopts ADDED
@@ -0,0 +1,4 @@
1
+ --no-private
2
+ --exclude features
3
+ --markup markdown
4
+ --template-path yard/template/
data/License.txt ADDED
@@ -0,0 +1,23 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2012 David Chelimsky, Andy Lindeman
4
+ Copyright (c) 2006 David Chelimsky, The RSpec Development Team
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # RSpec::ActiveModel::Mocks [![Build Status](https://secure.travis-ci.org/rspec/rspec-activemodel-mocks.png?branch=master)](http://travis-ci.org/rspec/rspec-activemodel-mocks)
2
+
3
+ RSpec::ActiveModel::Mocks provides tools for testing `ActiveModel` classes.
4
+
5
+ mock_model(Person, name: "Fred")
6
+
7
+ ## Install
8
+
9
+ Add this line to your application's gemfile:
10
+
11
+ gem 'rspec-activemodel-mocks'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ If you are using [rspec-rails](https://github.com/rspec/rspec-rails) and have
18
+ followed the installation instructions there, you're all set to use `stub_model`
19
+ and `mock_model`.
20
+
21
+ To use `stub_model` and `mock_model` without rspec-rails, require the
22
+ following file:
23
+
24
+ require 'rspec/active_model/mocks'
25
+
26
+ ## Usage
27
+
28
+ ### Mock
29
+
30
+ Creates a test double representing `string_or_model_class` with common
31
+ ActiveModel methods stubbed out. Additional methods may be easily stubbed
32
+ (via `add_stubs`) if `stubs` is passed. This is most useful for impersonating
33
+ models that don't exist yet.
34
+
35
+ ActiveModel methods, plus `new_record?`, are stubbed out implicitly.
36
+ `new_record?` returns the inverse of `persisted?`, and is present only for
37
+ compatibility with extension frameworks that have yet to update themselves to
38
+ the ActiveModel API (which declares `persisted?`, not `new_record?`).
39
+
40
+ `string_or_model_class` can be any of:
41
+
42
+ * A String representing a Class that does not exist
43
+ * A String representing a Class that extends `ActiveModel::Naming`
44
+ * A Class that extends `ActiveModel::Naming`
45
+
46
+ ### Stub
47
+
48
+ Creates an instance of `Model` with `to_param` stubbed using a generated value
49
+ that is unique to each object. If `Model` is an `ActiveRecord` model, it is
50
+ prohibited from accessing the database.
51
+
52
+ For each key in `stubs`, if the model has a matching attribute (determined by
53
+ `respond_to?`) it is simply assigned the submitted values. If the model does
54
+ not have a matching attribute, the key/value pair is assigned as a stub return
55
+ value using RSpec's mocking/stubbing framework.
56
+
57
+ `persisted?` is overridden to return the result of `!id.nil?` This means that
58
+ by default `persisted?` will return true. If you want the object to behave as a
59
+ new record, sending it `as_new_record` will set the id to nil. You can also
60
+ explicitly set `:id => nil`, in which case `persisted?` will return false, but
61
+ using `as_new_record` makes the example a bit more descriptive.
62
+
63
+ While you can use `stub_model` in any example (model, view, controller,
64
+ helper), it is especially useful in view examples, which are inherently more
65
+ state-based than interaction-based.
66
+
67
+ stub_model(Person)
68
+ stub_model(Person).as_new_record
69
+ stub_model(Person, :to_param => 37)
70
+ stub_model(Person) {|person| person.first_name = "David"}
@@ -0,0 +1,147 @@
1
+ Feature: mock_model
2
+
3
+ The `mock_model` method generates a test double that acts like an instance of
4
+ `ActiveModel`. This is different from the `stub_model` method which generates
5
+ an instance of a real model class.
6
+
7
+ The benefit of `mock_model` over `stub_model` is that it is a true double, so
8
+ the examples are not dependent on the behavior (or mis-behavior), or even the
9
+ existence of any other code. If you're working on a controller spec and you
10
+ need a model that doesn't exist, you can pass `mock_model` a string and the
11
+ generated object will act as though its an instance of the class named by
12
+ that string.
13
+
14
+ Scenario: passing a string that represents a non-existent constant
15
+ Given a file named "spec/models/car_spec.rb" with:
16
+ """ruby
17
+ require "spec_helper"
18
+
19
+ describe "mock_model('Car') with no Car constant in existence" do
20
+ it "generates a constant" do
21
+ expect(Object.const_defined?(:Car)).to be_falsey
22
+ mock_model("Car")
23
+ expect(Object.const_defined?(:Car)).to be_truthy
24
+ end
25
+
26
+ describe "generates an object that ..." do
27
+ it "returns the correct name" do
28
+ car = mock_model("Car")
29
+ expect(car.class.name).to eq("Car")
30
+ end
31
+
32
+ it "says it is a Car" do
33
+ car = mock_model("Car")
34
+ expect(car).to be_a(Car)
35
+ end
36
+ end
37
+ end
38
+ """
39
+ When I run `rspec spec/models/car_spec.rb`
40
+ Then the examples should all pass
41
+
42
+ Scenario: passing a string that represents an existing constant
43
+ Given a file named "spec/models/widget_spec.rb" with:
44
+ """ruby
45
+ require "spec_helper"
46
+
47
+ describe Widget do
48
+ it "uses the existing constant" do
49
+ widget = mock_model("Widget")
50
+ expect(widget).to be_a(Widget)
51
+ end
52
+ end
53
+ """
54
+ When I run `rspec spec/models/widget_spec.rb`
55
+ Then the examples should all pass
56
+
57
+ Scenario: passing a class that does not extend ActiveModel::Naming
58
+ Given a file named "spec/models/string_spec.rb" with:
59
+ """ruby
60
+ require "spec_helper"
61
+
62
+ describe String do
63
+ it "raises" do
64
+ expect { mock_model(String) }.to raise_exception
65
+ end
66
+ end
67
+ """
68
+ When I run `rspec spec/models/string_spec.rb`
69
+ Then the examples should all pass
70
+
71
+ Scenario: passing an Active Record constant
72
+ Given a file named "spec/models/widget_spec.rb" with:
73
+ """ruby
74
+ require "spec_helper"
75
+
76
+ describe Widget do
77
+ let(:widget) { mock_model(Widget) }
78
+
79
+ it "is valid by default" do
80
+ expect(widget).to be_valid
81
+ end
82
+
83
+ it "is not a new record by default" do
84
+ expect(widget).not_to be_new_record
85
+ end
86
+
87
+ it "can be converted to a new record" do
88
+ expect(widget.as_new_record).to be_new_record
89
+ end
90
+
91
+ it "sets :id to nil upon destroy" do
92
+ widget.destroy
93
+ expect(widget.id).to be_nil
94
+ end
95
+ end
96
+ """
97
+ When I run `rspec spec/models/widget_spec.rb`
98
+ Then the examples should all pass
99
+
100
+ Scenario: passing an Active Record constant with method stubs
101
+ Given a file named "spec/models/widget_spec.rb" with:
102
+ """ruby
103
+ require "spec_helper"
104
+
105
+ describe "mock_model(Widget) with stubs" do
106
+ let(:widget) do
107
+ mock_model Widget, :foo => "bar",
108
+ :save => true,
109
+ :update_attributes => false
110
+ end
111
+
112
+ it "supports stubs for methods that don't exist in ActiveModel or ActiveRecord" do
113
+ expect(widget.foo).to eq("bar")
114
+ end
115
+
116
+ it "supports stubs for methods that do exist" do
117
+ expect(widget.save).to eq(true)
118
+ expect(widget.update_attributes).to be_falsey
119
+ end
120
+
121
+ describe "#errors" do
122
+ context "with update_attributes => false" do
123
+ it "is not empty" do
124
+ expect(widget.errors).not_to be_empty
125
+ end
126
+ end
127
+ end
128
+ end
129
+ """
130
+ When I run `rspec spec/models/widget_spec.rb`
131
+ Then the examples should all pass
132
+
133
+ Scenario: mock_model outside rails
134
+ Given a file named "mock_model_outside_rails_spec.rb" with:
135
+ """ruby
136
+ require 'rspec/active_model/mocks'
137
+
138
+ describe "Foo" do
139
+ it "is mockable" do
140
+ foo = mock_model("Foo")
141
+ expect(foo.id).to eq(1001)
142
+ expect(foo.to_param).to eq("1001")
143
+ end
144
+ end
145
+ """
146
+ When I run `rspec mock_model_outside_rails_spec.rb`
147
+ Then the examples should all pass
@@ -0,0 +1,58 @@
1
+ Feature: stub_model
2
+
3
+ The stub_model method generates an instance of a Active Model model.
4
+
5
+ While you can use stub_model in any example (model, view, controller,
6
+ helper), it is especially useful in view examples, which are inherently
7
+ more state-based than interaction-based.
8
+
9
+ Scenario: passing an Active Record constant with a hash of stubs
10
+ Given a file named "spec/models/widget_spec.rb" with:
11
+ """ruby
12
+ require "spec_helper"
13
+
14
+ describe "stub_model(Widget) with a hash of stubs" do
15
+ let(:widget) do
16
+ stub_model Widget, :id => 5, :random_attribute => true
17
+ end
18
+
19
+ it "stubs :id" do
20
+ expect(widget.id).to eql(5)
21
+ end
22
+
23
+ it "stubs :random_attribute" do
24
+ expect(widget.random_attribute).to be_truthy
25
+ end
26
+
27
+ it "returns false for new_record? if :id is set" do
28
+ expect(widget).not_to be_new_record
29
+ end
30
+
31
+ it "can be converted to a new record" do
32
+ widget.as_new_record
33
+ expect(widget).to be_new_record
34
+ end
35
+ end
36
+ """
37
+ When I run `rspec spec/models/widget_spec.rb`
38
+ Then the examples should all pass
39
+
40
+ Scenario: passing an Active Record constant with a block of stubs
41
+ Given a file named "spec/models/widget_spec.rb" with:
42
+ """ruby
43
+ require "spec_helper"
44
+
45
+ describe "stub_model(Widget) with a block of stubs" do
46
+ let(:widget) do
47
+ stub_model Widget do |widget|
48
+ widget.id = 5
49
+ end
50
+ end
51
+
52
+ it "stubs :id" do
53
+ expect(widget.id).to eql(5)
54
+ end
55
+ end
56
+ """
57
+ When I run `rspec spec/models/widget_spec.rb`
58
+ Then the examples should all pass
@@ -0,0 +1,4 @@
1
+ Then /^the example(s)? should( all)? pass$/ do |_, _|
2
+ step %q{the output should contain "0 failures"}
3
+ step %q{the exit status should be 0}
4
+ end
@@ -0,0 +1,3 @@
1
+ Given /a (\w+) model/ do |model_class_name|
2
+ puts eval(model_class_name)
3
+ end
@@ -0,0 +1,53 @@
1
+ require 'aruba/cucumber'
2
+
3
+ module ArubaExt
4
+ def run(cmd)
5
+ super(cmd =~ /^rspec/ ? "bin/#{cmd}" : cmd)
6
+ end
7
+ end
8
+
9
+ World(ArubaExt)
10
+
11
+ Before do
12
+ @aruba_timeout_seconds = 30
13
+ end
14
+
15
+ unless File.directory?('./tmp/sample')
16
+ system "rake generate:sample"
17
+ end
18
+
19
+ def aruba_path(file_or_dir)
20
+ File.expand_path("../../../#{file_or_dir.sub('sample','aruba')}", __FILE__)
21
+ end
22
+
23
+ def sample_path(file_or_dir)
24
+ File.expand_path("../../../#{file_or_dir}", __FILE__)
25
+ end
26
+
27
+ def write_symlink(file_or_dir)
28
+ source = sample_path(file_or_dir)
29
+ target = aruba_path(file_or_dir)
30
+ system "ln -s #{source} #{target}"
31
+ end
32
+
33
+ def copy(file_or_dir)
34
+ source = sample_path(file_or_dir)
35
+ target = aruba_path(file_or_dir)
36
+ system "cp -r #{source} #{target}"
37
+ end
38
+
39
+ Before do
40
+ steps %Q{
41
+ Given a directory named "spec"
42
+ }
43
+
44
+ Dir['tmp/sample/*'].each do |file_or_dir|
45
+ if !(file_or_dir =~ /spec$/)
46
+ write_symlink(file_or_dir)
47
+ end
48
+ end
49
+
50
+ ["spec/spec_helper.rb"].each do |file_or_dir|
51
+ write_symlink("tmp/sample/#{file_or_dir}")
52
+ end
53
+ end
@@ -0,0 +1,6 @@
1
+ # Required until https://github.com/rubinius/rubinius/issues/2430 is resolved
2
+ ENV['RBXOPT'] = "#{ENV["RBXOPT"]} -Xcompiler.no_rbc"
3
+
4
+ Around "@unsupported-on-rbx" do |scenario, block|
5
+ block.call unless defined?(Rubinius)
6
+ end
@@ -0,0 +1,271 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext/object/to_param'
3
+ require 'active_model'
4
+
5
+ module RSpec::ActiveModel::Mocks
6
+ class IllegalDataAccessException < StandardError; end
7
+ module Mocks
8
+
9
+ module ActiveModelInstanceMethods
10
+ # Stubs `persisted?` to return false and `id` to return nil
11
+ # @return self
12
+ def as_new_record
13
+ RSpec::Mocks.allow_message(self, :persisted?).and_return(false)
14
+ RSpec::Mocks.allow_message(self, :id).and_return(nil)
15
+ self
16
+ end
17
+
18
+ # Returns true by default. Override with a stub.
19
+ def persisted?
20
+ true
21
+ end
22
+
23
+ # Returns false for names matching <tt>/_before_type_cast$/</tt>,
24
+ # otherwise delegates to super.
25
+ def respond_to?(message, include_private=false)
26
+ message.to_s =~ /_before_type_cast$/ ? false : super
27
+ end
28
+ end
29
+
30
+ # Starting with Rails 4.1, ActiveRecord associations are inversible
31
+ # by default. This class represents an association from the mocked
32
+ # model's perspective.
33
+ #
34
+ # @private
35
+ class Association
36
+ attr_accessor :target, :inversed
37
+
38
+ def initialize(association_name)
39
+ @association_name = association_name
40
+ end
41
+ end
42
+
43
+ module ActiveRecordInstanceMethods
44
+ # Stubs `persisted?` to return `false` and `id` to return `nil`.
45
+ def destroy
46
+ RSpec::Mocks.allow_message(self, :persisted?).and_return(false)
47
+ RSpec::Mocks.allow_message(self, :id).and_return(nil)
48
+ end
49
+
50
+ # Transforms the key to a method and calls it.
51
+ def [](key)
52
+ send(key)
53
+ end
54
+
55
+ # Returns the opposite of `persisted?`
56
+ def new_record?
57
+ !persisted?
58
+ end
59
+
60
+ # Returns an object representing an association from the mocked
61
+ # model's perspective. For use by Rails internally only.
62
+ def association(association_name)
63
+ @associations ||= Hash.new { |h, k| h[k] = Association.new(k) }
64
+ @associations[association_name]
65
+ end
66
+ end
67
+
68
+ # Creates a test double representing `string_or_model_class` with common
69
+ # ActiveModel methods stubbed out. Additional methods may be easily
70
+ # stubbed (via add_stubs) if `stubs` is passed. This is most useful for
71
+ # impersonating models that don't exist yet.
72
+ #
73
+ # ActiveModel methods, plus <tt>new_record?</tt>, are
74
+ # stubbed out implicitly. <tt>new_record?</tt> returns the inverse of
75
+ # <tt>persisted?</tt>, and is present only for compatibility with
76
+ # extension frameworks that have yet to update themselves to the
77
+ # ActiveModel API (which declares <tt>persisted?</tt>, not
78
+ # <tt>new_record?</tt>).
79
+ #
80
+ # `string_or_model_class` can be any of:
81
+ #
82
+ # * A String representing a Class that does not exist
83
+ # * A String representing a Class that extends ActiveModel::Naming
84
+ # * A Class that extends ActiveModel::Naming
85
+ def mock_model(string_or_model_class, stubs = {})
86
+ if String === string_or_model_class
87
+ if Object.const_defined?(string_or_model_class)
88
+ model_class = Object.const_get(string_or_model_class)
89
+ else
90
+ model_class = Object.const_set(string_or_model_class, Class.new do
91
+ extend ::ActiveModel::Naming
92
+ def self.primary_key; :id; end
93
+ end)
94
+ end
95
+ else
96
+ model_class = string_or_model_class
97
+ end
98
+
99
+ unless model_class.kind_of? ::ActiveModel::Naming
100
+ raise ArgumentError.new <<-EOM
101
+ The mock_model method can only accept as its first argument:
102
+ * A String representing a Class that does not exist
103
+ * A String representing a Class that extends ActiveModel::Naming
104
+ * A Class that extends ActiveModel::Naming
105
+
106
+ It received #{model_class.inspect}
107
+ EOM
108
+ end
109
+
110
+ stubs = {:id => next_id}.merge(stubs)
111
+ stubs = {:persisted? => !!stubs[:id],
112
+ :destroyed? => false,
113
+ :marked_for_destruction? => false,
114
+ :valid? => true,
115
+ :blank? => false}.merge(stubs)
116
+
117
+ double("#{model_class.name}_#{stubs[:id]}", stubs).tap do |m|
118
+ msingleton = class << m; self; end
119
+ msingleton.class_eval do
120
+ include ActiveModelInstanceMethods
121
+ include ActiveRecordInstanceMethods if defined?(ActiveRecord)
122
+ include ActiveModel::Conversion
123
+ include ActiveModel::Validations
124
+ end
125
+ if defined?(ActiveRecord)
126
+ [:save, :update_attributes, :update].each do |key|
127
+ if stubs[key] == false
128
+ RSpec::Mocks.allow_message(m.errors, :empty?).and_return(false)
129
+ end
130
+ end
131
+ end
132
+
133
+ msingleton.__send__(:define_method, :is_a?) do |other|
134
+ model_class.ancestors.include?(other)
135
+ end unless stubs.has_key?(:is_a?)
136
+
137
+ msingleton.__send__(:define_method, :kind_of?) do |other|
138
+ model_class.ancestors.include?(other)
139
+ end unless stubs.has_key?(:kind_of?)
140
+
141
+ msingleton.__send__(:define_method, :instance_of?) do |other|
142
+ other == model_class
143
+ end unless stubs.has_key?(:instance_of?)
144
+
145
+ msingleton.__send__(:define_method, :__model_class_has_column?) do |method_name|
146
+ model_class.respond_to?(:column_names) && model_class.column_names.include?(method_name.to_s)
147
+ end
148
+
149
+ msingleton.__send__(:define_method, :has_attribute?) do |attr_name|
150
+ __model_class_has_column?(attr_name)
151
+ end unless stubs.has_key?(:has_attribute?)
152
+
153
+ msingleton.__send__(:define_method, :respond_to?) do |method_name, *args|
154
+ include_private = args.first || false
155
+ __model_class_has_column?(method_name) ? true : super(method_name, include_private)
156
+ end unless stubs.has_key?(:respond_to?)
157
+
158
+ msingleton.__send__(:define_method, :method_missing) do |m, *a, &b|
159
+ respond_to?(m) ? null_object? ? self : nil : super(m, *a, &b)
160
+ end
161
+
162
+ msingleton.__send__(:define_method, :class) do
163
+ model_class
164
+ end unless stubs.has_key?(:class)
165
+
166
+ mock_param = to_param
167
+ msingleton.__send__(:define_method, :to_s) do
168
+ "#{model_class.name}_#{mock_param}"
169
+ end unless stubs.has_key?(:to_s)
170
+ yield m if block_given?
171
+ end
172
+ end
173
+
174
+ module ActiveModelStubExtensions
175
+ # Stubs `persisted` to return false and `id` to return nil
176
+ def as_new_record
177
+ RSpec::Mocks.allow_message(self, :persisted?).and_return(false)
178
+ RSpec::Mocks.allow_message(self, :id).and_return(nil)
179
+ self
180
+ end
181
+
182
+ # Returns `true` by default. Override with a stub.
183
+ def persisted?
184
+ true
185
+ end
186
+ end
187
+
188
+ module ActiveRecordStubExtensions
189
+ # Stubs `id` (or other primary key method) to return nil
190
+ def as_new_record
191
+ self.__send__("#{self.class.primary_key}=", nil)
192
+ super
193
+ end
194
+
195
+ # Returns the opposite of `persisted?`.
196
+ def new_record?
197
+ !persisted?
198
+ end
199
+
200
+ # Raises an IllegalDataAccessException (stubbed models are not allowed to access the database)
201
+ # @raises IllegalDataAccessException
202
+ def connection
203
+ raise RSpec::ActiveModel::Mocks::IllegalDataAccessException.new("stubbed models are not allowed to access the database")
204
+ end
205
+ end
206
+
207
+ # Creates an instance of `Model` with `to_param` stubbed using a
208
+ # generated value that is unique to each object. If `Model` is an
209
+ # `ActiveRecord` model, it is prohibited from accessing the database.
210
+ #
211
+ # For each key in `stubs`, if the model has a matching attribute
212
+ # (determined by `respond_to?`) it is simply assigned the submitted values.
213
+ # If the model does not have a matching attribute, the key/value pair is
214
+ # assigned as a stub return value using RSpec's mocking/stubbing
215
+ # framework.
216
+ #
217
+ # <tt>persisted?</tt> is overridden to return the result of !id.nil?
218
+ # This means that by default persisted? will return true. If you want
219
+ # the object to behave as a new record, sending it `as_new_record` will
220
+ # set the id to nil. You can also explicitly set :id => nil, in which
221
+ # case persisted? will return false, but using `as_new_record` makes the
222
+ # example a bit more descriptive.
223
+ #
224
+ # While you can use stub_model in any example (model, view, controller,
225
+ # helper), it is especially useful in view examples, which are
226
+ # inherently more state-based than interaction-based.
227
+ #
228
+ # @example
229
+ #
230
+ # stub_model(Person)
231
+ # stub_model(Person).as_new_record
232
+ # stub_model(Person, :to_param => 37)
233
+ # stub_model(Person) {|person| person.first_name = "David"}
234
+ def stub_model(model_class, stubs={})
235
+ model_class.new.tap do |m|
236
+ m.extend ActiveModelStubExtensions
237
+ if defined?(ActiveRecord) && model_class < ActiveRecord::Base
238
+ m.extend ActiveRecordStubExtensions
239
+ primary_key = model_class.primary_key.to_sym
240
+ stubs = {primary_key => next_id}.merge(stubs)
241
+ stubs = {:persisted? => !!stubs[primary_key]}.merge(stubs)
242
+ else
243
+ stubs = {:id => next_id}.merge(stubs)
244
+ stubs = {:persisted? => !!stubs[:id]}.merge(stubs)
245
+ end
246
+ stubs = {:blank? => false}.merge(stubs)
247
+
248
+ stubs.each do |message, return_value|
249
+ if m.respond_to?("#{message}=")
250
+ m.__send__("#{message}=", return_value)
251
+ else
252
+ RSpec::Mocks.allow_message(m, message).and_return(return_value)
253
+ end
254
+ end
255
+
256
+ yield m if block_given?
257
+ end
258
+ end
259
+
260
+ private
261
+
262
+ @@model_id = 1000
263
+
264
+ def next_id
265
+ @@model_id += 1
266
+ end
267
+
268
+ end
269
+ end
270
+
271
+ RSpec.configuration.include RSpec::ActiveModel::Mocks::Mocks
@@ -0,0 +1,9 @@
1
+ module RSpec
2
+ module ActiveModel
3
+ module Mocks
4
+ module Version
5
+ STRING = '1.0.0.beta1'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ require 'rspec/core'
2
+
3
+ RSpec::configure do |c|
4
+ c.backtrace_exclusion_patterns << /lib\/rspec\/active_model\/mocks/
5
+ end
6
+
7
+ require 'rspec/active_model/mocks/version'
8
+ require 'rspec/active_model/mocks/mocks'
@@ -0,0 +1 @@
1
+ require 'rspec/active_model/mocks'