with_model 2.2.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/.github/dependabot.yml +22 -6
- data/.github/workflows/ci.yml +64 -29
- data/CHANGELOG.md +26 -0
- data/CONTRIBUTING.md +83 -0
- data/Gemfile +2 -7
- data/LICENSE +1 -1
- data/README.md +116 -22
- data/lib/with_model/invalid_superclass.rb +15 -0
- data/lib/with_model/missing_superclass.rb +14 -0
- data/lib/with_model/model/dsl.rb +5 -2
- data/lib/with_model/model.rb +86 -6
- data/lib/with_model/null_table.rb +98 -0
- data/lib/with_model/table.rb +12 -0
- data/lib/with_model/version.rb +1 -1
- data/lib/with_model.rb +39 -1
- data/spec/active_record_behaviors_spec.rb +4 -1
- data/spec/descendants_tracking_spec.rb +1 -0
- data/spec/readme_spec.rb +61 -12
- data/spec/spec_helper.rb +2 -0
- data/spec/table_false_spec.rb +672 -0
- data/spec/with_model_spec.rb +33 -10
- data/test/declaration_order_test.rb +61 -0
- data/test/spec_dsl_test.rb +48 -0
- data/test/sti_test.rb +68 -0
- data/test/test_helper.rb +2 -0
- data/with_model.gemspec +2 -2
- metadata +14 -6
data/spec/with_model_spec.rb
CHANGED
|
@@ -96,7 +96,9 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
96
96
|
shadowing_example_ran = false
|
|
97
97
|
|
|
98
98
|
context "with the with_model block" do
|
|
99
|
-
with_model :MyConst
|
|
99
|
+
with_model :MyConst do
|
|
100
|
+
table
|
|
101
|
+
end
|
|
100
102
|
|
|
101
103
|
after do
|
|
102
104
|
shadowing_example_ran = true
|
|
@@ -116,16 +118,20 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
116
118
|
end
|
|
117
119
|
|
|
118
120
|
describe "with a plural name" do
|
|
119
|
-
with_model :BlogPosts
|
|
121
|
+
with_model :BlogPosts do
|
|
122
|
+
table
|
|
123
|
+
end
|
|
120
124
|
|
|
121
125
|
it "does not singularize the constant name" do
|
|
122
126
|
expect(BlogPosts).to be
|
|
123
|
-
expect
|
|
127
|
+
expect { BlogPost }.to raise_error(NameError)
|
|
124
128
|
end
|
|
125
129
|
end
|
|
126
130
|
|
|
127
131
|
describe "with a name containing capital letters" do
|
|
128
|
-
with_model :BlogPost
|
|
132
|
+
with_model :BlogPost do
|
|
133
|
+
table
|
|
134
|
+
end
|
|
129
135
|
|
|
130
136
|
it "tableizes the table name" do
|
|
131
137
|
expect(BlogPost.table_name).to match(/_blog_posts_/)
|
|
@@ -134,7 +140,9 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
134
140
|
end
|
|
135
141
|
|
|
136
142
|
describe "with a name with underscores" do
|
|
137
|
-
with_model :blog_post
|
|
143
|
+
with_model :blog_post do
|
|
144
|
+
table
|
|
145
|
+
end
|
|
138
146
|
|
|
139
147
|
it "constantizes the name" do
|
|
140
148
|
expect(BlogPost).to be
|
|
@@ -149,7 +157,9 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
149
157
|
describe "with a name which is namespaced" do
|
|
150
158
|
before { stub_const("Stuff", Module.new) }
|
|
151
159
|
|
|
152
|
-
with_model :"Stuff::BlogPost"
|
|
160
|
+
with_model :"Stuff::BlogPost" do
|
|
161
|
+
table
|
|
162
|
+
end
|
|
153
163
|
|
|
154
164
|
it "creates the model in the namespace" do
|
|
155
165
|
expect(defined?(BlogPost)).to be_falsey
|
|
@@ -159,6 +169,7 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
159
169
|
|
|
160
170
|
describe "using the constant in the model block" do
|
|
161
171
|
with_model :BlogPost do
|
|
172
|
+
table
|
|
162
173
|
model do
|
|
163
174
|
raise "I am not myself!" unless self == BlogPost
|
|
164
175
|
end
|
|
@@ -180,13 +191,14 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
180
191
|
before { stub_const("AMixin", mixin) }
|
|
181
192
|
|
|
182
193
|
with_model :WithAMixin do
|
|
194
|
+
table
|
|
183
195
|
model do
|
|
184
196
|
include AMixin
|
|
185
197
|
end
|
|
186
198
|
end
|
|
187
199
|
|
|
188
200
|
it "has the mixin" do
|
|
189
|
-
expect
|
|
201
|
+
expect { WithAMixin.new.foo }.not_to raise_error
|
|
190
202
|
expect(WithAMixin.include?(AMixin)).to be true
|
|
191
203
|
end
|
|
192
204
|
end
|
|
@@ -207,8 +219,10 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
207
219
|
before { stub_const("AMixin", mixin) }
|
|
208
220
|
|
|
209
221
|
with_model :WithAClassEval do
|
|
222
|
+
table
|
|
210
223
|
model do
|
|
211
224
|
include AMixin
|
|
225
|
+
|
|
212
226
|
def my_method
|
|
213
227
|
end
|
|
214
228
|
end
|
|
@@ -238,8 +252,13 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
238
252
|
end
|
|
239
253
|
end
|
|
240
254
|
|
|
255
|
+
# Omitting `table` is deprecated, but still supported for the rest of 2.x.
|
|
256
|
+
# These three contexts are its only coverage, so they keep omitting it and
|
|
257
|
+
# silence the warning rather than adopting the replacement spelling.
|
|
241
258
|
context "without a block" do
|
|
242
|
-
|
|
259
|
+
WithModel.deprecator.silence do
|
|
260
|
+
with_model :BlogPost
|
|
261
|
+
end
|
|
243
262
|
|
|
244
263
|
it "acts like a normal ActiveRecord model" do
|
|
245
264
|
record = BlogPost.create!
|
|
@@ -256,7 +275,9 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
256
275
|
end
|
|
257
276
|
|
|
258
277
|
context "with an empty block" do
|
|
259
|
-
|
|
278
|
+
WithModel.deprecator.silence do
|
|
279
|
+
with_model(:BlogPost) {}
|
|
280
|
+
end
|
|
260
281
|
|
|
261
282
|
it "acts like a normal ActiveRecord model" do
|
|
262
283
|
record = BlogPost.create!
|
|
@@ -303,7 +324,9 @@ describe "a temporary ActiveRecord model created with with_model" do
|
|
|
303
324
|
end
|
|
304
325
|
|
|
305
326
|
context "without a table or model block" do
|
|
306
|
-
|
|
327
|
+
WithModel.deprecator.silence do
|
|
328
|
+
with_model :BlogPost
|
|
329
|
+
end
|
|
307
330
|
|
|
308
331
|
it "acts like a normal ActiveRecord model" do
|
|
309
332
|
expect(BlogPost.columns.map(&:name)).to eq ["id"]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
# Models are created in declaration order and destroyed in reverse, so each one
|
|
6
|
+
# can depend on the ones above it for as long as it exists. Both halves of that
|
|
7
|
+
# are tested here.
|
|
8
|
+
#
|
|
9
|
+
# The model block is evaluated when the model is created, so a model that
|
|
10
|
+
# refers to another one by constant can only work if the model it refers to
|
|
11
|
+
# was created first.
|
|
12
|
+
class DeclarationOrderTest < Minitest::Test
|
|
13
|
+
with_model :Author do
|
|
14
|
+
table do |t|
|
|
15
|
+
t.string "name"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
with_model :Book do
|
|
20
|
+
table do |t|
|
|
21
|
+
t.integer "author_id"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
model do
|
|
25
|
+
belongs_to :author, class_name: Author.name
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
with_model :Shelf do
|
|
30
|
+
table do |t|
|
|
31
|
+
t.string "name"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# `to_table` because `foreign_key: true` would infer a table name from the
|
|
36
|
+
# column rather than asking the model, and with_model's table names are
|
|
37
|
+
# generated.
|
|
38
|
+
with_model :Jar do
|
|
39
|
+
table do |t|
|
|
40
|
+
t.references "shelf", foreign_key: {to_table: Shelf.table_name}
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_a_model_can_refer_to_one_declared_above_it
|
|
45
|
+
author = Author.create!(name: "Ursula K. Le Guin")
|
|
46
|
+
book = Book.create!(author: author)
|
|
47
|
+
|
|
48
|
+
assert_equal author, book.reload.author
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# The assertion for teardown order is that this test finishes cleanly. A
|
|
52
|
+
# referenced table cannot be dropped while a row still points at it, so tearing
|
|
53
|
+
# these down in declaration order raises ActiveRecord::InvalidForeignKey after
|
|
54
|
+
# the body has already passed.
|
|
55
|
+
def test_a_table_can_point_at_one_declared_above_it
|
|
56
|
+
shelf = Shelf.create!(name: "pantry")
|
|
57
|
+
jar = Jar.create!(shelf_id: shelf.id)
|
|
58
|
+
|
|
59
|
+
assert_equal shelf.id, jar.reload.shelf_id
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
# The README offers Minitest::Spec as well as Minitest::Test. Minitest::Spec
|
|
6
|
+
# inherits from Minitest::Test, so extending Minitest::Test reaches describe
|
|
7
|
+
# blocks too, and with_model needs no separate wiring for them.
|
|
8
|
+
describe "with_model in a spec-style suite" do
|
|
9
|
+
with_model :Sofa do
|
|
10
|
+
table do |t|
|
|
11
|
+
t.string "type"
|
|
12
|
+
t.string "fabric"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
with_model :Loveseat, superclass: :Sofa do
|
|
17
|
+
table(false)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "creates the models a describe block declares" do
|
|
21
|
+
assert_empty Sofa.all, "another test's rows outlived it"
|
|
22
|
+
|
|
23
|
+
Loveseat.create!(fabric: "tweed")
|
|
24
|
+
|
|
25
|
+
assert_equal Sofa.table_name, Loveseat.table_name
|
|
26
|
+
assert_instance_of Loveseat, Sofa.first
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Every describe is its own subclass of the one around it, so a nested block
|
|
30
|
+
# inherits the models declared above it and can add more of its own.
|
|
31
|
+
describe "and a nested describe" do
|
|
32
|
+
with_model :Ottoman do
|
|
33
|
+
table do |t|
|
|
34
|
+
t.string "name"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "sees the models from both levels" do
|
|
39
|
+
assert_empty Sofa.all, "another test's rows outlived it"
|
|
40
|
+
|
|
41
|
+
Ottoman.create!(name: "pouf")
|
|
42
|
+
Loveseat.create!(fabric: "velvet")
|
|
43
|
+
|
|
44
|
+
assert_equal 1, Ottoman.count
|
|
45
|
+
assert_equal 1, Sofa.count
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/test/sti_test.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
# Stands in for an application's own model, the usual reason to want single table
|
|
6
|
+
# inheritance: its table is created once and outlives every test here, so a
|
|
7
|
+
# with_model child's rows cannot be disposed of by dropping the table.
|
|
8
|
+
module AppModels
|
|
9
|
+
class Cupboard < ActiveRecord::Base
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Base.connection.create_table AppModels::Cupboard.table_name, force: true do |t|
|
|
14
|
+
t.string "type"
|
|
15
|
+
t.string "name"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# A with_model parent and an STI child in the same test case. The child's
|
|
19
|
+
# superclass is resolved per-example, so this only works if the parent is
|
|
20
|
+
# created before the child and destroyed after it.
|
|
21
|
+
class StiTest < Minitest::Test
|
|
22
|
+
with_model :Vehicle do
|
|
23
|
+
table do |t|
|
|
24
|
+
t.string "type"
|
|
25
|
+
t.string "name"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
with_model :Truck, superclass: -> { Vehicle } do
|
|
30
|
+
table(false)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
with_model :Chest, superclass: "AppModels::Cupboard" do
|
|
34
|
+
table(false)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_the_child_shares_the_parents_table
|
|
38
|
+
assert_equal Vehicle.table_name, Truck.table_name
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_the_child_stores_its_own_type
|
|
42
|
+
truck = Truck.create!(name: "Ford F-150")
|
|
43
|
+
|
|
44
|
+
assert_equal "Truck", truck.reload.type
|
|
45
|
+
assert_instance_of Truck, Vehicle.first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Rows in a table the child does not own have to be deleted when it goes away,
|
|
49
|
+
# since nothing else will: Cupboard's table is still standing afterwards, and a
|
|
50
|
+
# row naming a class that no longer exists makes it unloadable. Both tests write
|
|
51
|
+
# one and first insist the table is empty, so whichever minitest happens to run
|
|
52
|
+
# second fails if the rows survived teardown - whatever order the seed picks.
|
|
53
|
+
def test_the_childs_rows_do_not_outlive_it
|
|
54
|
+
assert_empty AppModels::Cupboard.all, "a previous test's rows outlived it"
|
|
55
|
+
|
|
56
|
+
Chest.create!(name: "sideboard")
|
|
57
|
+
|
|
58
|
+
assert_equal 1, AppModels::Cupboard.count
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_the_childs_rows_leave_the_superclass_loadable
|
|
62
|
+
assert_empty AppModels::Cupboard.all, "a previous test's rows outlived it"
|
|
63
|
+
|
|
64
|
+
Chest.create!(name: "wardrobe")
|
|
65
|
+
|
|
66
|
+
assert_instance_of Chest, AppModels::Cupboard.first
|
|
67
|
+
end
|
|
68
|
+
end
|
data/test/test_helper.rb
CHANGED
data/with_model.gemspec
CHANGED
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
19
19
|
spec.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
-
spec.required_ruby_version = ">= 3.
|
|
21
|
+
spec.required_ruby_version = ">= 3.3"
|
|
22
22
|
|
|
23
|
-
spec.add_dependency "activerecord", ">= 7.
|
|
23
|
+
spec.add_dependency "activerecord", ">= 7.2"
|
|
24
24
|
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.
|
|
4
|
+
version: 2.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Case Commons, LLC
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
- Andrew Marshall
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activerecord
|
|
@@ -17,14 +17,14 @@ dependencies:
|
|
|
17
17
|
requirements:
|
|
18
18
|
- - ">="
|
|
19
19
|
- !ruby/object:Gem::Version
|
|
20
|
-
version: '7.
|
|
20
|
+
version: '7.2'
|
|
21
21
|
type: :runtime
|
|
22
22
|
prerelease: false
|
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
|
24
24
|
requirements:
|
|
25
25
|
- - ">="
|
|
26
26
|
- !ruby/object:Gem::Version
|
|
27
|
-
version: '7.
|
|
27
|
+
version: '7.2'
|
|
28
28
|
description: Dynamically build a model within an RSpec context
|
|
29
29
|
email:
|
|
30
30
|
- casecommons-dev@googlegroups.com
|
|
@@ -42,6 +42,7 @@ files:
|
|
|
42
42
|
- ".rspec"
|
|
43
43
|
- ".yardopts"
|
|
44
44
|
- CHANGELOG.md
|
|
45
|
+
- CONTRIBUTING.md
|
|
45
46
|
- Gemfile
|
|
46
47
|
- LICENSE
|
|
47
48
|
- README.md
|
|
@@ -49,9 +50,12 @@ files:
|
|
|
49
50
|
- lib/with_model.rb
|
|
50
51
|
- lib/with_model/constant_stubber.rb
|
|
51
52
|
- lib/with_model/descendants_tracker.rb
|
|
53
|
+
- lib/with_model/invalid_superclass.rb
|
|
52
54
|
- lib/with_model/methods.rb
|
|
55
|
+
- lib/with_model/missing_superclass.rb
|
|
53
56
|
- lib/with_model/model.rb
|
|
54
57
|
- lib/with_model/model/dsl.rb
|
|
58
|
+
- lib/with_model/null_table.rb
|
|
55
59
|
- lib/with_model/table.rb
|
|
56
60
|
- lib/with_model/version.rb
|
|
57
61
|
- spec/active_record_behaviors_spec.rb
|
|
@@ -59,7 +63,11 @@ files:
|
|
|
59
63
|
- spec/descendants_tracking_spec.rb
|
|
60
64
|
- spec/readme_spec.rb
|
|
61
65
|
- spec/spec_helper.rb
|
|
66
|
+
- spec/table_false_spec.rb
|
|
62
67
|
- spec/with_model_spec.rb
|
|
68
|
+
- test/declaration_order_test.rb
|
|
69
|
+
- test/spec_dsl_test.rb
|
|
70
|
+
- test/sti_test.rb
|
|
63
71
|
- test/test_helper.rb
|
|
64
72
|
- test/with_model_test.rb
|
|
65
73
|
- with_model.gemspec
|
|
@@ -75,14 +83,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
75
83
|
requirements:
|
|
76
84
|
- - ">="
|
|
77
85
|
- !ruby/object:Gem::Version
|
|
78
|
-
version: '3.
|
|
86
|
+
version: '3.3'
|
|
79
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
88
|
requirements:
|
|
81
89
|
- - ">="
|
|
82
90
|
- !ruby/object:Gem::Version
|
|
83
91
|
version: '0'
|
|
84
92
|
requirements: []
|
|
85
|
-
rubygems_version:
|
|
93
|
+
rubygems_version: 4.0.18
|
|
86
94
|
specification_version: 4
|
|
87
95
|
summary: Dynamically build a model within an RSpec context
|
|
88
96
|
test_files: []
|