with_model 2.3.0 → 2.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/with_model/null_table.rb +11 -11
- data/lib/with_model/version.rb +1 -1
- data/spec/table_false_spec.rb +504 -348
- data/spec/with_model_spec.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e161c7fe750e7eb3b78e178a14b2e23ef88b0fa4612abfb22e3920be9eda614e
|
|
4
|
+
data.tar.gz: fb6d9310626f6a006463782d179406e1a2af10b6672899fb57c2bf26f6df61a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7d80585ba48b4b87593f9b7f18b8c4674391e51458b5e273ee121e4962bf4b479000a178a83db14cfa38a1eb185c8f09ac01d727ce6f79afe39ce5e45686ca70
|
|
7
|
+
data.tar.gz: 3e241e4d17f7b5d889e665e5cb17e5d66de1ca7fdd3b3cbd4e73615421561f735aa3d3f40176b27c1be32cfc9e1db7059d642662ad35fc786fc45620b8a8146f
|
data/CHANGELOG.md
CHANGED
|
@@ -13,17 +13,17 @@ module WithModel
|
|
|
13
13
|
class NullTable
|
|
14
14
|
# @param [Class] superclass The resolved superclass whose table will be
|
|
15
15
|
# inherited.
|
|
16
|
-
# @param [Symbol, String] name The model's name, so that
|
|
16
|
+
# @param [Symbol, String] name The model's name, so that an error can say
|
|
17
17
|
# which model it is talking about.
|
|
18
18
|
def initialize(superclass, name)
|
|
19
19
|
@superclass = superclass
|
|
20
20
|
@name = name
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
# Creates nothing, but
|
|
24
|
-
# table inheritance.
|
|
23
|
+
# Creates nothing, but raises {WithModel::InvalidSuperclass} when the
|
|
24
|
+
# superclass cannot support single table inheritance.
|
|
25
25
|
#
|
|
26
|
-
#
|
|
26
|
+
# Errors describe the model's situation rather than the call that produced
|
|
27
27
|
# it. Any expression that evaluates to false selects a NullTable, so there
|
|
28
28
|
# is no call spelling to quote - and in with_model 3.0, omitting `table`
|
|
29
29
|
# will arrive here too.
|
|
@@ -31,20 +31,20 @@ module WithModel
|
|
|
31
31
|
# A superclass whose table does not exist *yet* is deliberately allowed: the
|
|
32
32
|
# table may be created later in the example, and a test may legitimately
|
|
33
33
|
# want a model whose table is missing. Active Record raises a clear
|
|
34
|
-
# `StatementInvalid` naming the table if it never appears, so
|
|
34
|
+
# `StatementInvalid` naming the table if it never appears, so raising here
|
|
35
35
|
# would only forbid working setups.
|
|
36
36
|
#
|
|
37
|
-
# What is left is {WithModel::InvalidSuperclass}: both
|
|
37
|
+
# What is left is {WithModel::InvalidSuperclass}: both errors are permanent
|
|
38
38
|
# facts about the superclass passed in, not about when it was looked at, so no
|
|
39
39
|
# amount of waiting makes them work.
|
|
40
40
|
def create
|
|
41
|
-
|
|
41
|
+
raise_invalid_superclass "#{@superclass} has none to inherit" unless table_name?
|
|
42
42
|
|
|
43
43
|
# Nothing more can be checked until there is a table to look at.
|
|
44
44
|
return unless table_exists?
|
|
45
45
|
return if inheritance_column?
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
raise_invalid_superclass "#{@superclass}'s table #{@superclass.table_name.inspect} has no " \
|
|
48
48
|
"#{inheritance_column.inspect} column, so Active Record cannot tell its rows " \
|
|
49
49
|
"apart from a subclass's"
|
|
50
50
|
end
|
|
@@ -59,7 +59,7 @@ module WithModel
|
|
|
59
59
|
# (`ActiveRecord::SubclassNotFound`).
|
|
60
60
|
#
|
|
61
61
|
# `unscoped` is required because a `default_scope` on the superclass would
|
|
62
|
-
# otherwise hide rows from
|
|
62
|
+
# otherwise hide rows from cleanup; the inheritance-column condition is
|
|
63
63
|
# then reapplied explicitly, since `unscoped` also discards the type
|
|
64
64
|
# condition that keeps this from touching the superclass's own rows.
|
|
65
65
|
#
|
|
@@ -68,7 +68,7 @@ module WithModel
|
|
|
68
68
|
def teardown(klass)
|
|
69
69
|
return unless klass.table_exists?
|
|
70
70
|
|
|
71
|
-
klass.unscoped.where(klass.inheritance_column => klass.sti_name).
|
|
71
|
+
klass.unscoped.where(klass.inheritance_column => klass.sti_name).each(&:destroy!)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
# Drops nothing; there is no table of our own to drop.
|
|
@@ -90,7 +90,7 @@ module WithModel
|
|
|
90
90
|
inheritance_column.present? && @superclass.columns_hash.key?(inheritance_column)
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
def
|
|
93
|
+
def raise_invalid_superclass(problem)
|
|
94
94
|
raise InvalidSuperclass,
|
|
95
95
|
"with_model #{@name.inspect} has no table of its own, but #{problem}"
|
|
96
96
|
end
|
data/lib/with_model/version.rb
CHANGED
data/spec/table_false_spec.rb
CHANGED
|
@@ -2,515 +2,671 @@
|
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
#
|
|
13
|
-
|
|
5
|
+
RSpec.describe "table(false)" do
|
|
6
|
+
# Defines a named Active Record class for one example, equivalent to:
|
|
7
|
+
#
|
|
8
|
+
# class HasLateTable < ActiveRecord::Base
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# RSpec removes the constant afterward; the matching `after` hook below also
|
|
12
|
+
# clears Active Record's descendant trackers so the class object cannot leak.
|
|
13
|
+
def stub_active_record_class(name, superclass: ActiveRecord::Base)
|
|
14
|
+
klass = Class.new(superclass)
|
|
15
|
+
stub_const(name.to_s, klass)
|
|
16
|
+
(@stubbed_active_record_classes ||= []) << klass
|
|
17
|
+
klass
|
|
14
18
|
end
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
after do
|
|
21
|
+
classes = @stubbed_active_record_classes
|
|
22
|
+
next unless classes
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
ActiveSupport::DescendantsTracker.clear(classes) \
|
|
25
|
+
unless ActiveSupport::DescendantsTracker.clear_disabled
|
|
26
|
+
ActiveSupport::Dependencies::Reference.clear! \
|
|
27
|
+
if defined?(ActiveSupport::Dependencies::Reference)
|
|
28
|
+
WithModel::DescendantsTracker.clear(classes)
|
|
24
29
|
end
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
describe "with a concrete superclass" do
|
|
32
|
+
with_model :HasTypeColumn do
|
|
33
|
+
table do |t|
|
|
34
|
+
t.string :type
|
|
35
|
+
t.string :name
|
|
36
|
+
end
|
|
37
|
+
end
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
with_model :Truck, superclass: :HasTypeColumn do
|
|
40
|
+
table(false)
|
|
41
|
+
model do
|
|
42
|
+
def honk = "beep"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
32
45
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
it "inherits the superclass table rather than creating its own" do
|
|
47
|
+
expect(Truck.table_name).to eq HasTypeColumn.table_name
|
|
48
|
+
end
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
it "creates no table of its own" do
|
|
51
|
+
expect(ActiveRecord::Base.connection.tables.grep(/with_model_truck/)).to be_empty
|
|
52
|
+
end
|
|
40
53
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
self.abstract_class = true
|
|
45
|
-
end
|
|
54
|
+
it "reports the superclass as the STI base class" do
|
|
55
|
+
expect(Truck.base_class).to eq HasTypeColumn
|
|
56
|
+
end
|
|
46
57
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
it "still evaluates the model block" do
|
|
59
|
+
expect(Truck.new.honk).to eq "beep"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "writes its own name to the inheritance column" do
|
|
63
|
+
Truck.create!(name: "big")
|
|
64
|
+
expect(HasTypeColumn.first.type).to eq "Truck"
|
|
65
|
+
end
|
|
50
66
|
|
|
51
|
-
|
|
52
|
-
|
|
67
|
+
it "is found through the superclass as an instance of itself" do
|
|
68
|
+
Truck.create!(name: "big")
|
|
69
|
+
expect(HasTypeColumn.first).to be_a Truck
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Deliberately a second example asserting the same thing: both models are
|
|
73
|
+
# rebuilt for every example, so a superclass resolved once and cached on the
|
|
74
|
+
# Model instance would still point to the first example's dead parent.
|
|
75
|
+
it "works in a second example too" do
|
|
76
|
+
Truck.create!(name: "also big")
|
|
77
|
+
expect(HasTypeColumn.first).to be_a Truck
|
|
78
|
+
end
|
|
53
79
|
end
|
|
54
80
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
81
|
+
describe "teardown" do
|
|
82
|
+
with_model :HasTypeColumn do
|
|
83
|
+
table do |t|
|
|
58
84
|
t.string :type
|
|
59
85
|
t.string :name
|
|
60
86
|
end
|
|
87
|
+
end
|
|
61
88
|
|
|
62
|
-
|
|
89
|
+
context "when child and superclass rows exist" do
|
|
90
|
+
after do
|
|
91
|
+
expect(HasTypeColumn.where(type: "Truck").count).to eq 0
|
|
92
|
+
expect(HasTypeColumn.where(type: nil).count).to eq 1
|
|
93
|
+
end
|
|
63
94
|
|
|
64
|
-
with_model :Truck, superclass: HasTypeColumn do
|
|
95
|
+
with_model :Truck, superclass: :HasTypeColumn do
|
|
65
96
|
table(false)
|
|
66
|
-
model do
|
|
67
|
-
def honk = "beep"
|
|
68
|
-
end
|
|
69
97
|
end
|
|
70
98
|
|
|
71
|
-
it "
|
|
72
|
-
|
|
99
|
+
it "deletes its own rows and leaves the superclass's rows alone" do
|
|
100
|
+
Truck.create!(name: "child row")
|
|
101
|
+
HasTypeColumn.create!(name: "parent row")
|
|
73
102
|
end
|
|
103
|
+
end
|
|
74
104
|
|
|
75
|
-
|
|
76
|
-
|
|
105
|
+
context "when a child row exists" do
|
|
106
|
+
after do
|
|
107
|
+
expect { HasTypeColumn.first }.not_to raise_error
|
|
77
108
|
end
|
|
78
109
|
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
with_model :Truck, superclass: :HasTypeColumn do
|
|
111
|
+
table(false)
|
|
81
112
|
end
|
|
82
113
|
|
|
83
|
-
it "
|
|
84
|
-
|
|
114
|
+
it "leaves the superclass queryable" do
|
|
115
|
+
Truck.create!(name: "child row")
|
|
85
116
|
end
|
|
117
|
+
end
|
|
86
118
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
119
|
+
context "with an abstract superclass" do
|
|
120
|
+
with_model :TablelessSuperclass do
|
|
121
|
+
table
|
|
122
|
+
model do
|
|
123
|
+
self.abstract_class = true
|
|
124
|
+
self.table_name = nil
|
|
125
|
+
end
|
|
90
126
|
end
|
|
91
127
|
|
|
92
|
-
it "
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
128
|
+
it "does not delete rows when create raises WithModel::InvalidSuperclass" do
|
|
129
|
+
HasTypeColumn.create!(name: "parent row")
|
|
130
|
+
tableless_subclass = WithModel::Model.new(
|
|
131
|
+
:TablelessSubclass,
|
|
132
|
+
superclass: TablelessSuperclass
|
|
133
|
+
)
|
|
134
|
+
WithModel::Model::DSL.new(tableless_subclass).table(false)
|
|
135
|
+
|
|
136
|
+
expect { tableless_subclass.create }.to raise_error(WithModel::InvalidSuperclass)
|
|
137
|
+
expect { tableless_subclass.destroy }.not_to raise_error
|
|
96
138
|
|
|
97
|
-
|
|
98
|
-
# resolved once and cached on the Model instance would go stale here,
|
|
99
|
-
# because the parent is the same class object but the child is rebuilt.
|
|
100
|
-
it "works in a second example too" do
|
|
101
|
-
Truck.create!(name: "also big")
|
|
102
|
-
expect(HasTypeColumn.first).to be_a Truck
|
|
139
|
+
expect(HasTypeColumn.count).to eq 1
|
|
103
140
|
end
|
|
104
141
|
end
|
|
105
142
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
t
|
|
109
|
-
|
|
143
|
+
context "when destruction of its row is aborted" do
|
|
144
|
+
with_model :AbortsDestroy do
|
|
145
|
+
table do |t|
|
|
146
|
+
t.string :type
|
|
147
|
+
end
|
|
148
|
+
model do
|
|
149
|
+
before_destroy { throw :abort }
|
|
150
|
+
end
|
|
110
151
|
end
|
|
111
152
|
|
|
112
|
-
|
|
153
|
+
subject(:null_table) do
|
|
154
|
+
WithModel::NullTable.new(AbortsDestroy, :TemporaryAbortedDestroy)
|
|
155
|
+
end
|
|
113
156
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
WithModel::Model::DSL.new(model).instance_eval(&dsl)
|
|
117
|
-
end
|
|
157
|
+
after do
|
|
158
|
+
expect(Object.const_defined?(:TemporaryAbortedDestroy, false)).to be false
|
|
118
159
|
end
|
|
119
160
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Truck.create!(name: "child row")
|
|
124
|
-
HasTypeColumn.create!(name: "parent row")
|
|
161
|
+
with_model :TemporaryAbortedDestroy, superclass: :AbortsDestroy do
|
|
162
|
+
table(false)
|
|
163
|
+
end
|
|
125
164
|
|
|
126
|
-
|
|
165
|
+
it "fails loudly" do
|
|
166
|
+
TemporaryAbortedDestroy.create!
|
|
127
167
|
|
|
128
|
-
expect
|
|
129
|
-
|
|
168
|
+
expect do
|
|
169
|
+
null_table.teardown(TemporaryAbortedDestroy)
|
|
170
|
+
end.to raise_error(ActiveRecord::RecordNotDestroyed)
|
|
171
|
+
|
|
172
|
+
AbortsDestroy.where(type: TemporaryAbortedDestroy.sti_name).delete_all
|
|
130
173
|
end
|
|
174
|
+
end
|
|
131
175
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
176
|
+
context "when its rows have dependent records protected by a foreign key" do
|
|
177
|
+
with_model :HasDependentChildren do
|
|
178
|
+
table do |t|
|
|
179
|
+
t.string :type
|
|
180
|
+
end
|
|
181
|
+
model do
|
|
182
|
+
has_many :dependent_children,
|
|
183
|
+
class_name: "DependentChild",
|
|
184
|
+
foreign_key: :parent_id,
|
|
185
|
+
inverse_of: :parent,
|
|
186
|
+
dependent: :destroy
|
|
187
|
+
end
|
|
188
|
+
end
|
|
136
189
|
|
|
137
|
-
|
|
190
|
+
with_model :DependentChild do
|
|
191
|
+
table do |t|
|
|
192
|
+
t.references :parent,
|
|
193
|
+
null: false,
|
|
194
|
+
foreign_key: {to_table: HasDependentChildren.table_name}
|
|
195
|
+
end
|
|
196
|
+
model do
|
|
197
|
+
belongs_to :parent,
|
|
198
|
+
class_name: "HasDependentChildren",
|
|
199
|
+
inverse_of: :dependent_children
|
|
200
|
+
end
|
|
201
|
+
end
|
|
138
202
|
|
|
139
|
-
|
|
203
|
+
with_model :OtherDependentParent, superclass: :HasDependentChildren do
|
|
204
|
+
table(false)
|
|
140
205
|
end
|
|
141
206
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
207
|
+
after do
|
|
208
|
+
expect(HasDependentChildren.unscoped.ids).to contain_exactly(@superclass.id, @sibling.id)
|
|
209
|
+
expect(DependentChild.pluck(:parent_id)).to contain_exactly(@superclass.id, @sibling.id)
|
|
210
|
+
end
|
|
145
211
|
|
|
146
|
-
|
|
147
|
-
|
|
212
|
+
with_model :TemporaryDependentParent, superclass: :HasDependentChildren do
|
|
213
|
+
table(false)
|
|
214
|
+
end
|
|
148
215
|
|
|
149
|
-
|
|
216
|
+
it "destroys its dependents without removing superclass or sibling rows" do
|
|
217
|
+
temporary = TemporaryDependentParent.create!
|
|
218
|
+
@superclass = HasDependentChildren.create!
|
|
219
|
+
@sibling = OtherDependentParent.create!
|
|
220
|
+
[temporary, @superclass, @sibling].each do |parent|
|
|
221
|
+
parent.dependent_children.create!
|
|
222
|
+
end
|
|
150
223
|
end
|
|
151
224
|
end
|
|
225
|
+
end
|
|
152
226
|
|
|
153
|
-
|
|
154
|
-
|
|
227
|
+
describe "with a superclass that has a default_scope" do
|
|
228
|
+
with_model :HasDefaultScope do
|
|
229
|
+
table do |t|
|
|
155
230
|
t.string :type
|
|
156
231
|
t.boolean :archived, default: false
|
|
157
232
|
end
|
|
233
|
+
model do
|
|
234
|
+
default_scope { where(archived: false) }
|
|
235
|
+
end
|
|
236
|
+
end
|
|
158
237
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
model = WithModel::Model.new(:ScopedChild, superclass: HasDefaultScope)
|
|
163
|
-
WithModel::Model::DSL.new(model).table(false)
|
|
164
|
-
model.create
|
|
165
|
-
ScopedChild.create!(archived: false)
|
|
166
|
-
ScopedChild.create!(archived: true)
|
|
238
|
+
after do
|
|
239
|
+
expect(HasDefaultScope.unscoped.where(type: "ScopedChild").count).to eq 0
|
|
240
|
+
end
|
|
167
241
|
|
|
168
|
-
|
|
242
|
+
with_model :ScopedChild, superclass: :HasDefaultScope do
|
|
243
|
+
table(false)
|
|
244
|
+
end
|
|
169
245
|
|
|
170
|
-
|
|
171
|
-
|
|
246
|
+
it "deletes rows the default scope would have hidden" do
|
|
247
|
+
ScopedChild.create!(archived: false)
|
|
248
|
+
ScopedChild.create!(archived: true)
|
|
172
249
|
end
|
|
250
|
+
end
|
|
173
251
|
|
|
174
|
-
|
|
175
|
-
|
|
252
|
+
describe "with a non-standard inheritance_column" do
|
|
253
|
+
with_model :HasCustomInheritanceColumn do
|
|
254
|
+
table do |t|
|
|
176
255
|
t.string :kind
|
|
177
256
|
t.string :name
|
|
178
257
|
end
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
with_model :KindedChild, superclass: HasCustomInheritanceColumn do
|
|
183
|
-
table(false)
|
|
258
|
+
model do
|
|
259
|
+
self.inheritance_column = "kind"
|
|
184
260
|
end
|
|
261
|
+
end
|
|
185
262
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
end
|
|
263
|
+
with_model :KindedChild, superclass: :HasCustomInheritanceColumn do
|
|
264
|
+
table(false)
|
|
265
|
+
end
|
|
190
266
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
267
|
+
it "writes to the custom column" do
|
|
268
|
+
KindedChild.create!(name: "x")
|
|
269
|
+
expect(HasCustomInheritanceColumn.first.kind).to eq "KindedChild"
|
|
194
270
|
end
|
|
195
271
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
272
|
+
it "accepts a Symbol inheritance_column" do
|
|
273
|
+
expect(HasCustomInheritanceColumn.inheritance_column).to eq "kind"
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# The anchor case: a validation or teardown that hard-codes "type" passes
|
|
278
|
+
# every other example here and still scopes on the wrong column.
|
|
279
|
+
describe "with both a type column and a custom inheritance_column" do
|
|
280
|
+
with_model :CustomInheritanceWithType do
|
|
281
|
+
table do |t|
|
|
200
282
|
t.string :kind
|
|
201
283
|
t.string :type
|
|
202
284
|
t.string :name
|
|
203
285
|
end
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
with_model :KindedTypeChild, superclass: HasCustomInheritanceColumnAndTypeColumn do
|
|
208
|
-
table(false)
|
|
286
|
+
model do
|
|
287
|
+
self.inheritance_column = "kind"
|
|
209
288
|
end
|
|
289
|
+
end
|
|
210
290
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
row = HasCustomInheritanceColumnAndTypeColumn.first
|
|
214
|
-
expect(row.kind).to eq "KindedTypeChild"
|
|
215
|
-
expect(row.type).to be_nil
|
|
216
|
-
end
|
|
291
|
+
with_model :KindedTypeChild, superclass: :CustomInheritanceWithType do
|
|
292
|
+
table(false)
|
|
217
293
|
end
|
|
218
294
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
295
|
+
it "writes the custom column and leaves type null" do
|
|
296
|
+
KindedTypeChild.create!(name: "x")
|
|
297
|
+
row = CustomInheritanceWithType.first
|
|
298
|
+
expect(row.kind).to eq "KindedTypeChild"
|
|
299
|
+
expect(row.type).to be_nil
|
|
300
|
+
end
|
|
301
|
+
end
|
|
226
302
|
|
|
227
|
-
|
|
228
|
-
|
|
303
|
+
describe "with a with_model superclass" do
|
|
304
|
+
with_model :Parent do
|
|
305
|
+
table do |t|
|
|
306
|
+
t.string :type
|
|
307
|
+
t.string :name
|
|
229
308
|
end
|
|
309
|
+
end
|
|
230
310
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
311
|
+
with_model :StringChild, superclass: "Parent" do
|
|
312
|
+
table(false)
|
|
313
|
+
end
|
|
234
314
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
315
|
+
with_model :SymbolChild, superclass: :Parent do
|
|
316
|
+
table(false)
|
|
317
|
+
end
|
|
238
318
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
end
|
|
319
|
+
with_model :CallableChild, superclass: -> { Parent } do
|
|
320
|
+
table(false)
|
|
321
|
+
end
|
|
243
322
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
end
|
|
323
|
+
it "resolves a String superclass" do
|
|
324
|
+
expect(StringChild.superclass).to eq Parent
|
|
325
|
+
expect(StringChild.table_name).to eq Parent.table_name
|
|
326
|
+
end
|
|
249
327
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
328
|
+
# The same spelling with_model names its own models with.
|
|
329
|
+
it "resolves a Symbol superclass" do
|
|
330
|
+
expect(SymbolChild.superclass).to eq Parent
|
|
331
|
+
expect(SymbolChild.table_name).to eq Parent.table_name
|
|
332
|
+
end
|
|
253
333
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
end
|
|
334
|
+
it "resolves a callable superclass" do
|
|
335
|
+
expect(CallableChild.superclass).to eq Parent
|
|
336
|
+
end
|
|
258
337
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
expect(StringChild.superclass).to eq Parent
|
|
263
|
-
expect(StringChild.superclass).to be Parent
|
|
264
|
-
end
|
|
338
|
+
it "round-trips through the parent" do
|
|
339
|
+
StringChild.create!(name: "x")
|
|
340
|
+
expect(Parent.first).to be_a StringChild
|
|
265
341
|
end
|
|
266
342
|
|
|
267
|
-
|
|
268
|
-
|
|
343
|
+
# Second example: the parent class object is rebuilt every example, so a
|
|
344
|
+
# superclass memoized on the first resolution refers to a dead class here.
|
|
345
|
+
it "resolves against the current parent in a later example" do
|
|
346
|
+
expect(StringChild.superclass).to eq Parent
|
|
347
|
+
expect(StringChild.superclass).to be Parent
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
describe "namespaced constants" do
|
|
352
|
+
with_model :HasTypeColumn do
|
|
353
|
+
table do |t|
|
|
269
354
|
t.string :type
|
|
270
355
|
t.string :name
|
|
271
356
|
end
|
|
357
|
+
end
|
|
272
358
|
|
|
273
|
-
|
|
359
|
+
# WithModel::ConstantStubber resolves a namespaced name with `const_get` and
|
|
360
|
+
# stubs only the last segment, so the namespace has to exist already.
|
|
361
|
+
before { stub_const("TableFalseSpec", Module.new) }
|
|
274
362
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
with_model "TableFalseSpec::Step", superclass: HasTypeColumn do
|
|
279
|
-
table(false)
|
|
280
|
-
end
|
|
363
|
+
with_model "TableFalseSpec::Step", superclass: :HasTypeColumn do
|
|
364
|
+
table(false)
|
|
365
|
+
end
|
|
281
366
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
end
|
|
367
|
+
it "stores and round-trips the fully qualified name" do
|
|
368
|
+
TableFalseSpec::Step.create!(name: "x")
|
|
369
|
+
expect(HasTypeColumn.first.type).to eq "TableFalseSpec::Step"
|
|
370
|
+
expect(HasTypeColumn.first).to be_a TableFalseSpec::Step
|
|
287
371
|
end
|
|
372
|
+
end
|
|
288
373
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
374
|
+
# A missing table is a fact about the schema at that moment, not about the
|
|
375
|
+
# model, so it is allowed: the table may arrive later in the example, or its
|
|
376
|
+
# absence may be the very thing under test.
|
|
377
|
+
describe "when the superclass's table does not exist" do
|
|
378
|
+
# The shape a Rails app's ApplicationRecord takes: abstract, and inherited
|
|
379
|
+
# from rather than ActiveRecord::Base directly.
|
|
380
|
+
with_model :ApplicationRecord do
|
|
381
|
+
table
|
|
382
|
+
model do
|
|
383
|
+
self.abstract_class = true
|
|
384
|
+
self.table_name = nil
|
|
295
385
|
end
|
|
386
|
+
end
|
|
296
387
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
expect(Orphan).to be < HasMissingTable
|
|
301
|
-
expect(Orphan.table_name).to eq HasMissingTable.table_name
|
|
302
|
-
end
|
|
388
|
+
before do
|
|
389
|
+
stub_active_record_class(:HasMissingTable, superclass: ApplicationRecord)
|
|
390
|
+
end
|
|
303
391
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
end
|
|
392
|
+
with_model :Orphan, superclass: -> { HasMissingTable } do
|
|
393
|
+
table(false)
|
|
394
|
+
end
|
|
308
395
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
396
|
+
it "still defines the model, which inherits the missing table's name" do
|
|
397
|
+
# Not `new`: building an instance reads column information, which is
|
|
398
|
+
# itself a use of the absent table.
|
|
399
|
+
expect(Orphan).to be < HasMissingTable
|
|
400
|
+
expect(Orphan.table_name).to eq HasMissingTable.table_name
|
|
314
401
|
end
|
|
315
402
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
403
|
+
it "lets Active Record raise its own error, naming the table" do
|
|
404
|
+
expect { Orphan.create!(name: "x") }
|
|
405
|
+
.to raise_error(ActiveRecord::StatementInvalid, /#{HasMissingTable.table_name}/)
|
|
406
|
+
end
|
|
320
407
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
408
|
+
it "tears down without failing an example that otherwise passed" do
|
|
409
|
+
# Reaching the end of this example at all is the assertion: teardown has
|
|
410
|
+
# no rows to delete and must not go looking for them.
|
|
411
|
+
expect(Orphan.name).to eq "Orphan"
|
|
412
|
+
end
|
|
413
|
+
end
|
|
324
414
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
t.string :type
|
|
328
|
-
t.string :name
|
|
329
|
-
end
|
|
330
|
-
HasLateTable.reset_column_information
|
|
415
|
+
describe "when the superclass's table is created during the example" do
|
|
416
|
+
before { stub_active_record_class(:HasLateTable) }
|
|
331
417
|
|
|
332
|
-
|
|
418
|
+
with_model :LateChild, superclass: -> { HasLateTable } do
|
|
419
|
+
table(false)
|
|
420
|
+
end
|
|
333
421
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
end
|
|
422
|
+
after do
|
|
423
|
+
ActiveRecord::Base.connection.drop_table HasLateTable.table_name, if_exists: true
|
|
337
424
|
end
|
|
338
425
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
model.create
|
|
426
|
+
it "inherits the table once it exists" do
|
|
427
|
+
ActiveRecord::Base.connection.create_table HasLateTable.table_name, force: true do |t|
|
|
428
|
+
t.string :type
|
|
429
|
+
t.string :name
|
|
344
430
|
end
|
|
431
|
+
HasLateTable.reset_column_information
|
|
432
|
+
|
|
433
|
+
LateChild.create!(name: "late")
|
|
434
|
+
|
|
435
|
+
expect(HasLateTable.count).to eq 1
|
|
436
|
+
expect(HasLateTable.first).to be_a LateChild
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
describe "invalid configurations" do
|
|
441
|
+
# Creates immediately the same tableless subclass normally generated by:
|
|
442
|
+
#
|
|
443
|
+
# with_model :TablelessSubclass, superclass: superclass do
|
|
444
|
+
# table(false)
|
|
445
|
+
# end
|
|
446
|
+
#
|
|
447
|
+
# Bypassing `with_model`'s setup hook lets these examples assert failures
|
|
448
|
+
# raised while the superclass is resolved or the table configuration checked.
|
|
449
|
+
def create_tableless_subclass(superclass:, &dsl)
|
|
450
|
+
model = WithModel::Model.new(:TablelessSubclass, superclass: superclass)
|
|
451
|
+
WithModel::Model::DSL.new(model).instance_eval(&dsl || proc { table(false) })
|
|
452
|
+
model.create
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
it "names the model, which the superclass's name does not identify" do
|
|
456
|
+
expect { create_tableless_subclass(superclass: ActiveRecord::Base) }
|
|
457
|
+
.to raise_error(
|
|
458
|
+
WithModel::InvalidSuperclass,
|
|
459
|
+
/with_model :TablelessSubclass has no table of its own/
|
|
460
|
+
)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
it "raises WithModel::InvalidSuperclass for ActiveRecord::Base" do
|
|
464
|
+
expect { create_tableless_subclass(superclass: ActiveRecord::Base) }
|
|
465
|
+
.to raise_error(WithModel::InvalidSuperclass, /ActiveRecord::Base has none to inherit/)
|
|
466
|
+
end
|
|
345
467
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
468
|
+
context "with an abstract superclass" do
|
|
469
|
+
with_model :TablelessSuperclass do
|
|
470
|
+
table
|
|
471
|
+
model do
|
|
472
|
+
self.abstract_class = true
|
|
473
|
+
self.table_name = nil
|
|
474
|
+
end
|
|
349
475
|
end
|
|
350
476
|
|
|
351
|
-
it "
|
|
352
|
-
expect {
|
|
353
|
-
.to raise_error(WithModel::InvalidSuperclass, /
|
|
477
|
+
it "raises WithModel::InvalidSuperclass" do
|
|
478
|
+
expect { create_tableless_subclass(superclass: TablelessSuperclass) }
|
|
479
|
+
.to raise_error(WithModel::InvalidSuperclass, /TablelessSuperclass has none to inherit/)
|
|
354
480
|
end
|
|
481
|
+
end
|
|
355
482
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
483
|
+
context "with an abstract superclass a Rails app would call ApplicationRecord" do
|
|
484
|
+
with_model :ApplicationRecord do
|
|
485
|
+
table
|
|
486
|
+
model do
|
|
487
|
+
self.abstract_class = true
|
|
488
|
+
self.table_name = nil
|
|
489
|
+
end
|
|
359
490
|
end
|
|
360
491
|
|
|
361
|
-
it "
|
|
362
|
-
expect {
|
|
492
|
+
it "raises WithModel::InvalidSuperclass" do
|
|
493
|
+
expect { create_tableless_subclass(superclass: ApplicationRecord) }
|
|
363
494
|
.to raise_error(WithModel::InvalidSuperclass, /ApplicationRecord has none to inherit/)
|
|
364
495
|
end
|
|
496
|
+
end
|
|
365
497
|
|
|
366
|
-
|
|
367
|
-
|
|
498
|
+
context "when the superclass table lacks the inheritance column" do
|
|
499
|
+
with_model :HasNoTypeColumn do
|
|
500
|
+
table do |t|
|
|
368
501
|
t.string :name
|
|
369
502
|
end
|
|
503
|
+
end
|
|
370
504
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
expect { create_model(superclass: HasNoTypeColumn) }
|
|
375
|
-
.to raise_error(WithModel::InvalidSuperclass, /"type" column/)
|
|
376
|
-
end
|
|
505
|
+
it "raises WithModel::InvalidSuperclass and names the missing column" do
|
|
506
|
+
expect { create_tableless_subclass(superclass: HasNoTypeColumn) }
|
|
507
|
+
.to raise_error(WithModel::InvalidSuperclass, /"type" column/)
|
|
377
508
|
end
|
|
509
|
+
end
|
|
378
510
|
|
|
379
|
-
|
|
380
|
-
|
|
511
|
+
context "when the superclass disables inheritance" do
|
|
512
|
+
with_model :HasNilInheritanceColumn do
|
|
513
|
+
table do |t|
|
|
381
514
|
t.string :name
|
|
382
515
|
end
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
expect { create_model(superclass: HasNilInheritanceColumn) }
|
|
386
|
-
.to raise_error(WithModel::InvalidSuperclass)
|
|
516
|
+
model do
|
|
517
|
+
self.inheritance_column = nil
|
|
387
518
|
end
|
|
388
519
|
end
|
|
389
520
|
|
|
390
|
-
it "
|
|
391
|
-
expect
|
|
392
|
-
|
|
393
|
-
end.to raise_error(ArgumentError, /table does not take a block when its first argument is falsy/)
|
|
521
|
+
it "raises WithModel::InvalidSuperclass" do
|
|
522
|
+
expect { create_tableless_subclass(superclass: HasNilInheritanceColumn) }
|
|
523
|
+
.to raise_error(WithModel::InvalidSuperclass)
|
|
394
524
|
end
|
|
525
|
+
end
|
|
395
526
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
it "names the segment of a namespaced superclass that is missing" do
|
|
404
|
-
expect { create_model(superclass: "NoSuchNamespace::Deep::Parent") }
|
|
405
|
-
.to raise_error(WithModel::MissingSuperclass, /uninitialized constant NoSuchNamespace\./)
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
it "reports an unresolvable Symbol as the Symbol that was passed" do
|
|
409
|
-
expect { create_model(superclass: :NoSuchParent) }
|
|
410
|
-
.to raise_error(WithModel::MissingSuperclass,
|
|
411
|
-
/superclass :NoSuchParent could not be resolved: uninitialized constant NoSuchParent/)
|
|
527
|
+
context "when table(false) is passed a block" do
|
|
528
|
+
with_model :HasTypeColumn do
|
|
529
|
+
table do |t|
|
|
530
|
+
t.string :type
|
|
531
|
+
t.string :name
|
|
412
532
|
end
|
|
533
|
+
end
|
|
413
534
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
.to raise_error(WithModel::MissingSuperclass) { |error|
|
|
419
|
-
expect(error.cause).to be_a NameError
|
|
420
|
-
}
|
|
421
|
-
end
|
|
535
|
+
it "raises ArgumentError" do
|
|
536
|
+
expect do
|
|
537
|
+
create_tableless_subclass(superclass: HasTypeColumn) { table(false) { |t| t.string :nope } }
|
|
538
|
+
end.to raise_error(ArgumentError, /table does not take a block when its first argument is falsy/)
|
|
422
539
|
end
|
|
540
|
+
end
|
|
423
541
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
expect(
|
|
542
|
+
describe "a superclass that cannot be found" do
|
|
543
|
+
it "quotes the reason it could not be resolved" do
|
|
544
|
+
expect { create_tableless_subclass(superclass: "NoSuchParent") }
|
|
545
|
+
.to raise_error(WithModel::MissingSuperclass,
|
|
546
|
+
/superclass "NoSuchParent" could not be resolved: uninitialized constant NoSuchParent/)
|
|
427
547
|
end
|
|
428
548
|
|
|
429
|
-
it "
|
|
430
|
-
expect {
|
|
431
|
-
.to raise_error(WithModel::
|
|
432
|
-
/name it with a String or a Symbol, or pass a callable returning it/)
|
|
549
|
+
it "names the segment of a namespaced superclass that is missing" do
|
|
550
|
+
expect { create_tableless_subclass(superclass: "NoSuchNamespace::Deep::Parent") }
|
|
551
|
+
.to raise_error(WithModel::MissingSuperclass, /uninitialized constant NoSuchNamespace\./)
|
|
433
552
|
end
|
|
434
553
|
|
|
435
|
-
it "
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
554
|
+
it "reports an unresolvable Symbol as the Symbol that was passed" do
|
|
555
|
+
expect { create_tableless_subclass(superclass: :NoSuchParent) }
|
|
556
|
+
.to raise_error(WithModel::MissingSuperclass,
|
|
557
|
+
/superclass :NoSuchParent could not be resolved: uninitialized constant NoSuchParent/)
|
|
439
558
|
end
|
|
440
559
|
|
|
441
|
-
it "
|
|
442
|
-
|
|
443
|
-
|
|
560
|
+
it "keeps the NameError as its cause" do
|
|
561
|
+
# Ruby sets this for a raise inside a rescue, so the original backtrace
|
|
562
|
+
# stays reachable.
|
|
563
|
+
expect { create_tableless_subclass(superclass: "NoSuchParent") }
|
|
564
|
+
.to raise_error(WithModel::MissingSuperclass) { |error|
|
|
565
|
+
expect(error.cause).to be_a NameError
|
|
566
|
+
}
|
|
444
567
|
end
|
|
445
568
|
end
|
|
446
|
-
end
|
|
447
569
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
WithModel.deprecator.behavior = ->(message, *) { collected << message }
|
|
452
|
-
yield
|
|
453
|
-
collected
|
|
454
|
-
ensure
|
|
455
|
-
WithModel.deprecator.behavior = :raise
|
|
570
|
+
it "tells a missing superclass apart from an unusable one, but catches both" do
|
|
571
|
+
expect(WithModel::MissingSuperclass).to be < WithModel::InvalidSuperclass
|
|
572
|
+
expect(WithModel::InvalidSuperclass).to be < ArgumentError
|
|
456
573
|
end
|
|
457
574
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
575
|
+
it "says how to name a class that is not defined yet" do
|
|
576
|
+
expect { create_tableless_subclass(superclass: 42) }
|
|
577
|
+
.to raise_error(WithModel::InvalidSuperclass,
|
|
578
|
+
/name it with a String or a Symbol, or pass a callable returning it/)
|
|
462
579
|
end
|
|
463
580
|
|
|
464
|
-
it "
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
expect(messages.join).to match(/table/)
|
|
581
|
+
it "raises WithModel::InvalidSuperclass for a value that only has a to_s" do
|
|
582
|
+
# Every object has one, so honoring it would look up the constant "42".
|
|
583
|
+
expect { create_tableless_subclass(superclass: 42) }
|
|
584
|
+
.to raise_error(WithModel::InvalidSuperclass, /but was 42/)
|
|
469
585
|
end
|
|
470
586
|
|
|
471
|
-
it "
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
end
|
|
475
|
-
expect(messages.join).to include("3.0")
|
|
587
|
+
it "raises WithModel::InvalidSuperclass for a callable returning a non-ActiveRecord value" do
|
|
588
|
+
expect { create_tableless_subclass(superclass: -> { 42 }) }
|
|
589
|
+
.to raise_error(WithModel::InvalidSuperclass, /but was 42/)
|
|
476
590
|
end
|
|
591
|
+
end
|
|
592
|
+
end
|
|
477
593
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
messages = capture_deprecations do
|
|
483
|
-
define_group { with_model(:Warned) }
|
|
484
|
-
end
|
|
594
|
+
RSpec.describe "omitting table" do
|
|
595
|
+
before do
|
|
596
|
+
allow(WithModel.deprecator).to receive(:warn)
|
|
597
|
+
end
|
|
485
598
|
|
|
486
|
-
|
|
487
|
-
|
|
599
|
+
# Defines the supplied block as if it had appeared in an isolated group:
|
|
600
|
+
#
|
|
601
|
+
# RSpec.describe "throwaway" do
|
|
602
|
+
# # supplied definitions
|
|
603
|
+
# end
|
|
604
|
+
#
|
|
605
|
+
# The warning happens at definition time, so the assertion cannot rely on this
|
|
606
|
+
# file's own example-group load order.
|
|
607
|
+
def define_group(&body)
|
|
608
|
+
RSpec::Core::ExampleGroup.describe("throwaway", &body)
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
it "warns when no table is specified" do
|
|
612
|
+
define_group { with_model(:Warned) }
|
|
613
|
+
|
|
614
|
+
expect(WithModel.deprecator).to have_received(:warn) do |message, _callstack|
|
|
615
|
+
expect(message).to match(/table/)
|
|
488
616
|
end
|
|
617
|
+
end
|
|
489
618
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
expect(
|
|
619
|
+
it "names the 3.0 horizon in the warning" do
|
|
620
|
+
define_group { with_model(:Warned) }
|
|
621
|
+
|
|
622
|
+
expect(WithModel.deprecator).to have_received(:warn) do |message, _callstack|
|
|
623
|
+
expect(message).to include("3.0")
|
|
495
624
|
end
|
|
625
|
+
end
|
|
496
626
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
627
|
+
# Left to itself ActiveSupport::Deprecation blames the first frame it does not
|
|
628
|
+
# recognize as Rails or the standard library, which is with_model's own source
|
|
629
|
+
# - the same line for every omission in a suite.
|
|
630
|
+
it "blames the with_model call rather than with_model's own source" do
|
|
631
|
+
expected_source_line = __LINE__ + 1
|
|
632
|
+
define_group { with_model(:Warned) }
|
|
633
|
+
|
|
634
|
+
expect(WithModel.deprecator).to have_received(:warn) do |_message, callstack|
|
|
635
|
+
expect(callstack.first.path).to eq(__FILE__)
|
|
636
|
+
expect(callstack.first.lineno).to eq(expected_source_line)
|
|
637
|
+
expect(callstack.first.path).not_to include("lib/with_model.rb")
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
context "when table(false) is used" do
|
|
642
|
+
with_model :HasTypeColumn do
|
|
643
|
+
table do |t|
|
|
644
|
+
t.string :type
|
|
645
|
+
t.string :name
|
|
505
646
|
end
|
|
506
|
-
expect(messages).to be_empty
|
|
507
647
|
end
|
|
508
648
|
|
|
509
|
-
it "does not warn
|
|
510
|
-
|
|
511
|
-
|
|
649
|
+
it "does not warn" do
|
|
650
|
+
define_group { with_model(:Quiet, superclass: HasTypeColumn) { table(false) } }
|
|
651
|
+
|
|
652
|
+
expect(WithModel.deprecator).not_to have_received(:warn)
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
it "does not warn for an empty table block" do
|
|
657
|
+
define_group do
|
|
658
|
+
with_model(:Quiet) do
|
|
659
|
+
table do
|
|
660
|
+
end
|
|
512
661
|
end
|
|
513
|
-
expect(messages).to be_empty
|
|
514
662
|
end
|
|
663
|
+
|
|
664
|
+
expect(WithModel.deprecator).not_to have_received(:warn)
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
it "does not warn for a `table` call with no arguments" do
|
|
668
|
+
define_group { with_model(:Quiet) { table } }
|
|
669
|
+
|
|
670
|
+
expect(WithModel.deprecator).not_to have_received(:warn)
|
|
515
671
|
end
|
|
516
672
|
end
|
data/spec/with_model_spec.rb
CHANGED
|
@@ -124,7 +124,7 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
124
124
|
|
|
125
125
|
it "does not singularize the constant name" do
|
|
126
126
|
expect(BlogPosts).to be
|
|
127
|
-
expect
|
|
127
|
+
expect { BlogPost }.to raise_error(NameError)
|
|
128
128
|
end
|
|
129
129
|
end
|
|
130
130
|
|
|
@@ -198,7 +198,7 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
198
198
|
end
|
|
199
199
|
|
|
200
200
|
it "has the mixin" do
|
|
201
|
-
expect
|
|
201
|
+
expect { WithAMixin.new.foo }.not_to raise_error
|
|
202
202
|
expect(WithAMixin.include?(AMixin)).to be true
|
|
203
203
|
end
|
|
204
204
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: with_model
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.3.
|
|
4
|
+
version: 2.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Case Commons, LLC
|
|
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
90
90
|
- !ruby/object:Gem::Version
|
|
91
91
|
version: '0'
|
|
92
92
|
requirements: []
|
|
93
|
-
rubygems_version: 4.0.
|
|
93
|
+
rubygems_version: 4.0.18
|
|
94
94
|
specification_version: 4
|
|
95
95
|
summary: Dynamically build a model within an RSpec context
|
|
96
96
|
test_files: []
|