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.
@@ -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(-> { BlogPost }).to raise_error(NameError)
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(-> { WithAMixin.new.foo }).not_to raise_error
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
- with_model :BlogPost
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
- with_model(:BlogPost) {}
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
- with_model :BlogPost
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
@@ -7,6 +7,8 @@ require "minitest/autorun"
7
7
 
8
8
  WithModel.runner = :minitest
9
9
 
10
+ WithModel.deprecator.behavior = :raise
11
+
10
12
  Minitest::Test.class_eval do
11
13
  extend WithModel
12
14
  end
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.1"
21
+ spec.required_ruby_version = ">= 3.3"
22
22
 
23
- spec.add_dependency "activerecord", ">= 7.0"
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.2.0
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: 2025-02-04 00:00:00.000000000 Z
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.0'
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.0'
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.1'
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: 3.6.3
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: []