with_model 2.1.6 → 2.2.0

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.
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_model'
4
- require 'spec_helper'
3
+ require "active_model"
4
+ require "spec_helper"
5
5
 
6
- shared_examples_for 'ActiveModel' do
7
- require 'active_model/lint'
6
+ shared_examples_for "ActiveModel" do
7
+ require "active_model/lint"
8
8
  include SpecHelper::RailsTestCompatibility
9
9
  include ActiveModel::Lint::Tests
10
10
 
@@ -12,7 +12,8 @@ shared_examples_for 'ActiveModel' do
12
12
  active_model_lint_tests = active_model_methods.map(&:to_s).grep(/^test/)
13
13
 
14
14
  active_model_lint_tests.each do |method_name|
15
- friendly_name = method_name.tr('_', ' ')
15
+ friendly_name = method_name.tr("_", " ")
16
+
16
17
  example friendly_name do
17
18
  public_send method_name.to_sym
18
19
  end
@@ -21,14 +22,14 @@ shared_examples_for 'ActiveModel' do
21
22
  before { @model = subject }
22
23
  end
23
24
 
24
- describe 'a temporary ActiveRecord model created with with_model' do
25
+ describe "a temporary ActiveRecord model created with with_model" do
25
26
  non_shadowing_example_ran = false
26
27
 
27
28
  describe "which doesn't shadow an existing class" do
28
29
  with_model :BlogPost do
29
30
  table do |t|
30
- t.string 'title'
31
- t.text 'content'
31
+ t.string "title"
32
+ t.text "content"
32
33
  t.timestamps null: false
33
34
  end
34
35
 
@@ -43,13 +44,13 @@ describe 'a temporary ActiveRecord model created with with_model' do
43
44
  non_shadowing_example_ran = true
44
45
  end
45
46
 
46
- it 'acts like a normal ActiveRecord model' do
47
- record = BlogPost.create!(title: 'New blog post', content: 'Hello, world!')
47
+ it "acts like a normal ActiveRecord model" do
48
+ record = BlogPost.create!(title: "New blog post", content: "Hello, world!")
48
49
 
49
50
  record.reload
50
51
 
51
- expect(record.title).to eq 'New blog post'
52
- expect(record.content).to eq 'Hello, world!'
52
+ expect(record.title).to eq "New blog post"
53
+ expect(record.content).to eq "Hello, world!"
53
54
  expect(record.updated_at).to be_present
54
55
 
55
56
  record.destroy
@@ -57,123 +58,126 @@ describe 'a temporary ActiveRecord model created with with_model' do
57
58
  expect { record.reload }.to raise_error(ActiveRecord::RecordNotFound)
58
59
  end
59
60
 
60
- describe 'the class' do
61
+ describe "the class" do
61
62
  subject { BlogPost.new }
62
63
 
63
- it_behaves_like 'ActiveModel'
64
+ it_behaves_like "ActiveModel"
64
65
  end
65
66
 
66
- it 'has the methods defined in its model block' do
67
- expect(BlogPost.new(title: 'New blog post').fancy_title).to eq 'Title: New blog post'
67
+ it "has the methods defined in its model block" do
68
+ expect(BlogPost.new(title: "New blog post").fancy_title).to eq "Title: New blog post"
68
69
  end
69
70
 
70
- it 'defines a constant' do
71
+ it "defines a constant" do
71
72
  expect(BlogPost).to be_a(Class)
72
73
  end
73
74
 
74
- describe '.with_model?' do
75
- it 'returns true' do
76
- expect(BlogPost.with_model?).to eq true
75
+ describe ".with_model?" do
76
+ it "returns true" do
77
+ expect(BlogPost.with_model?).to be true
77
78
  end
78
79
  end
79
80
 
80
- it 'is its own base_class' do
81
+ it "is its own base_class" do
81
82
  expect(BlogPost.base_class).to eq BlogPost
82
83
  end
83
84
  end
84
85
 
85
- context 'after an example which uses with_model without shadowing an existing constant' do
86
- it 'returns the constant to its undefined state' do
87
- expect(non_shadowing_example_ran).to eq true
86
+ context "after an example which uses with_model without shadowing an existing constant" do
87
+ it "returns the constant to its undefined state" do
88
+ expect(non_shadowing_example_ran).to be true
88
89
  expect(defined?(BlogPost)).to be_falsy
89
90
  end
90
91
  end
91
92
 
92
- describe 'constant restoration' do
93
- before { stub_const('MyConst', 1) }
93
+ describe "constant restoration" do
94
+ before { stub_const("MyConst", 1) }
94
95
 
95
96
  shadowing_example_ran = false
96
97
 
97
- context 'with the with_model block' do
98
+ context "with the with_model block" do
98
99
  with_model :MyConst
99
100
 
100
101
  after do
101
102
  shadowing_example_ran = true
102
103
  end
103
104
 
104
- it 'shadows that constant' do
105
+ it "shadows that constant" do
105
106
  expect(MyConst).to be_a(Class)
106
107
  end
107
108
  end
108
109
 
109
- context 'without the with_model block' do
110
- it 'returns the constant to its original value' do
111
- expect(shadowing_example_ran).to eq true
110
+ context "without the with_model block" do
111
+ it "returns the constant to its original value" do
112
+ expect(shadowing_example_ran).to be true
112
113
  expect(MyConst).to eq 1
113
114
  end
114
115
  end
115
116
  end
116
117
 
117
- describe 'with a plural name' do
118
+ describe "with a plural name" do
118
119
  with_model :BlogPosts
119
120
 
120
- it 'does not singularize the constant name' do
121
+ it "does not singularize the constant name" do
121
122
  expect(BlogPosts).to be
122
123
  expect(-> { BlogPost }).to raise_error(NameError)
123
124
  end
124
125
  end
125
126
 
126
- describe 'with a name containing capital letters' do
127
+ describe "with a name containing capital letters" do
127
128
  with_model :BlogPost
128
129
 
129
- it 'tableizes the table name' do
130
+ it "tableizes the table name" do
130
131
  expect(BlogPost.table_name).to match(/_blog_posts_/)
131
132
  expect(BlogPost.table_name).to eq BlogPost.table_name.downcase
132
133
  end
133
134
  end
134
135
 
135
- describe 'with a name with underscores' do
136
+ describe "with a name with underscores" do
136
137
  with_model :blog_post
137
138
 
138
- it 'constantizes the name' do
139
+ it "constantizes the name" do
139
140
  expect(BlogPost).to be
140
141
  end
141
142
 
142
- it 'tableizes the table name' do
143
+ it "tableizes the table name" do
143
144
  expect(BlogPost.table_name).to match(/_blog_posts_/)
144
145
  expect(BlogPost.table_name).to eq BlogPost.table_name.downcase
145
146
  end
146
147
  end
147
148
 
148
- describe 'with a name which is namespaced' do
149
- before { stub_const('Stuff', Module.new) }
149
+ describe "with a name which is namespaced" do
150
+ before { stub_const("Stuff", Module.new) }
150
151
 
151
- with_model :'Stuff::BlogPost'
152
+ with_model :"Stuff::BlogPost"
152
153
 
153
- it 'creates the model in the namespace' do
154
- expect(defined?(::BlogPost)).to be_falsey
155
- expect(defined?(::Stuff::BlogPost)).to be_truthy
154
+ it "creates the model in the namespace" do
155
+ expect(defined?(BlogPost)).to be_falsey
156
+ expect(defined?(Stuff::BlogPost)).to be_truthy
156
157
  end
157
158
  end
158
159
 
159
- describe 'using the constant in the model block' do
160
+ describe "using the constant in the model block" do
160
161
  with_model :BlogPost do
161
162
  model do
162
- raise 'I am not myself!' unless self == BlogPost
163
+ raise "I am not myself!" unless self == BlogPost
163
164
  end
164
165
  end
165
166
 
166
- it 'is available' do
167
+ it "is available" do
167
168
  expect(BlogPost).to be
168
169
  end
169
170
  end
170
171
 
171
- context 'with a mixin' do
172
+ context "with a mixin" do
172
173
  let(:mixin) do
173
- Module.new { def foo; end }
174
+ Module.new {
175
+ def foo
176
+ end
177
+ }
174
178
  end
175
179
 
176
- before { stub_const('AMixin', mixin) }
180
+ before { stub_const("AMixin", mixin) }
177
181
 
178
182
  with_model :WithAMixin do
179
183
  model do
@@ -181,108 +185,109 @@ describe 'a temporary ActiveRecord model created with with_model' do
181
185
  end
182
186
  end
183
187
 
184
- it 'has the mixin' do
185
- expect(-> { ::WithAMixin.new.foo }).not_to raise_error
186
- expect(::WithAMixin.include?(AMixin)).to eq true
188
+ it "has the mixin" do
189
+ expect(-> { WithAMixin.new.foo }).not_to raise_error
190
+ expect(WithAMixin.include?(AMixin)).to be true
187
191
  end
188
192
  end
189
193
 
190
- context 'with a mixin that has a class_eval' do
194
+ context "with a mixin that has a class_eval" do
191
195
  subject { WithAClassEval.new }
192
196
 
193
197
  let(:mixin) do
194
198
  Module.new do
195
199
  def self.included(klass)
196
200
  klass.class_eval do
197
- after_save { |object| object.my_method } # rubocop:disable Style/SymbolProc
201
+ after_save { |object| object.my_method }
198
202
  end
199
203
  end
200
204
  end
201
205
  end
202
206
 
203
- before { stub_const('AMixin', mixin) }
207
+ before { stub_const("AMixin", mixin) }
204
208
 
205
209
  with_model :WithAClassEval do
206
210
  model do
207
211
  include AMixin
208
- def my_method; end
212
+ def my_method
213
+ end
209
214
  end
210
215
  end
211
216
 
212
- it 'only has one after_save callback' do
217
+ it "only has one after_save callback" do
213
218
  expect(subject).to receive(:my_method).once
214
219
  subject.save
215
220
  end
216
221
 
217
- it 'still only has one after_save callback in future tests' do
222
+ it "still only has one after_save callback in future tests" do
218
223
  expect(subject).to receive(:my_method).once
219
224
  subject.save
220
225
  end
221
226
  end
222
227
 
223
- context 'with table options' do
228
+ context "with table options" do
224
229
  with_model :WithOptions do
225
230
  table id: false do |t|
226
- t.string 'foo'
231
+ t.string "foo"
227
232
  t.timestamps null: false
228
233
  end
229
234
  end
230
235
 
231
- it 'respects the additional options' do
232
- expect(WithOptions.columns.map(&:name)).not_to include('id')
236
+ it "respects the additional options" do
237
+ expect(WithOptions.columns.map(&:name)).not_to include("id")
233
238
  end
234
239
  end
235
240
 
236
- context 'without a block' do
241
+ context "without a block" do
237
242
  with_model :BlogPost
238
243
 
239
- it 'acts like a normal ActiveRecord model' do
244
+ it "acts like a normal ActiveRecord model" do
240
245
  record = BlogPost.create!
241
246
  record.reload
242
247
  record.destroy
243
248
  expect { record.reload }.to raise_error(ActiveRecord::RecordNotFound)
244
249
  end
245
250
 
246
- describe 'the class' do
251
+ describe "the class" do
247
252
  subject { BlogPost.new }
248
253
 
249
- it_behaves_like 'ActiveModel'
254
+ it_behaves_like "ActiveModel"
250
255
  end
251
256
  end
252
257
 
253
- context 'with an empty block' do
254
- with_model(:BlogPost) {} # rubocop:disable Lint/EmptyBlock
258
+ context "with an empty block" do
259
+ with_model(:BlogPost) {}
255
260
 
256
- it 'acts like a normal ActiveRecord model' do
261
+ it "acts like a normal ActiveRecord model" do
257
262
  record = BlogPost.create!
258
263
  record.reload
259
264
  record.destroy
260
265
  expect { record.reload }.to raise_error(ActiveRecord::RecordNotFound)
261
266
  end
262
267
 
263
- describe 'the class' do
268
+ describe "the class" do
264
269
  subject { BlogPost.new }
265
270
 
266
- it_behaves_like 'ActiveModel'
271
+ it_behaves_like "ActiveModel"
267
272
  end
268
273
  end
269
274
 
270
- context 'without a model block' do
275
+ context "without a model block" do
271
276
  with_model :BlogPost do
272
277
  table do |t|
273
- t.string 'title'
274
- t.text 'content'
278
+ t.string "title"
279
+ t.text "content"
275
280
  t.timestamps null: false
276
281
  end
277
282
  end
278
283
 
279
- it 'acts like a normal ActiveRecord model' do
280
- record = BlogPost.create!(title: 'New blog post', content: 'Hello, world!')
284
+ it "acts like a normal ActiveRecord model" do
285
+ record = BlogPost.create!(title: "New blog post", content: "Hello, world!")
281
286
 
282
287
  record.reload
283
288
 
284
- expect(record.title).to eq 'New blog post'
285
- expect(record.content).to eq 'Hello, world!'
289
+ expect(record.title).to eq "New blog post"
290
+ expect(record.content).to eq "Hello, world!"
286
291
  expect(record.updated_at).to be_present
287
292
 
288
293
  record.destroy
@@ -290,56 +295,32 @@ describe 'a temporary ActiveRecord model created with with_model' do
290
295
  expect { record.reload }.to raise_error(ActiveRecord::RecordNotFound)
291
296
  end
292
297
 
293
- describe 'the class' do
298
+ describe "the class" do
294
299
  subject { BlogPost.new }
295
300
 
296
- it_behaves_like 'ActiveModel'
301
+ it_behaves_like "ActiveModel"
297
302
  end
298
303
  end
299
304
 
300
- context 'without a table or model block' do
305
+ context "without a table or model block" do
301
306
  with_model :BlogPost
302
307
 
303
- it 'acts like a normal ActiveRecord model' do
304
- expect(BlogPost.columns.map(&:name)).to eq ['id']
308
+ it "acts like a normal ActiveRecord model" do
309
+ expect(BlogPost.columns.map(&:name)).to eq ["id"]
305
310
  record = BlogPost.create!
306
311
  record.reload
307
312
  record.destroy
308
313
  expect { record.reload }.to raise_error(ActiveRecord::RecordNotFound)
309
314
  end
310
315
 
311
- describe 'the class' do
316
+ describe "the class" do
312
317
  subject { BlogPost.new }
313
318
 
314
- it_behaves_like 'ActiveModel'
319
+ it_behaves_like "ActiveModel"
315
320
  end
316
321
  end
317
322
 
318
- context 'with ActiveSupport::DescendantsTracker' do
319
- with_model :BlogPost do
320
- model do
321
- def self.inspect
322
- "BlogPost class #{object_id}"
323
- end
324
- end
325
- end
326
-
327
- def blog_post_classes
328
- ActiveRecord::Base.descendants.select do |c|
329
- c.table_name == BlogPost.table_name
330
- end
331
- end
332
-
333
- it 'includes the correct model class in descendants on the first test run' do
334
- expect(blog_post_classes).to eq [BlogPost]
335
- end
336
-
337
- it 'includes the correct model class in descendants on the second test run' do
338
- expect(blog_post_classes).to eq [BlogPost]
339
- end
340
- end
341
-
342
- context 'with_model can be run within RSpec :all hook' do
323
+ context "with_model can be run within RSpec :all hook" do
343
324
  with_model :BlogPost, scope: :all do
344
325
  table do |t|
345
326
  t.string :title
@@ -350,42 +331,55 @@ describe 'a temporary ActiveRecord model created with with_model' do
350
331
  BlogPost.create # without scope: :all these will fail
351
332
  end
352
333
 
353
- it 'has been initialized within before(:all)' do
334
+ it "has been initialized within before(:all)" do
354
335
  expect(BlogPost.count).to eq 1
355
336
  end
356
337
  end
357
338
 
358
339
  context "with 'superclass' option" do
359
- class BlogPostParent < ActiveRecord::Base
340
+ class BlogPostParent < ActiveRecord::Base # standard:disable Lint/ConstantDefinitionInBlock
360
341
  self.abstract_class = true
361
342
  end
362
343
 
363
- after(:all) do
364
- Object.__send__(:remove_const, 'BlogPostParent')
365
- end
366
-
367
344
  with_model :BlogPost, superclass: BlogPostParent do
368
345
  table do |t|
369
- t.string 'title'
346
+ t.string "title"
370
347
  end
371
348
  end
372
349
 
373
- describe 'the class' do
350
+ describe "the class" do
374
351
  subject { BlogPost.new }
375
352
 
376
- it_behaves_like 'ActiveModel'
353
+ it_behaves_like "ActiveModel"
377
354
  end
378
355
 
379
- it 'is a subclass of the supplied superclass' do
380
- expect(BlogPost < BlogPostParent).to eq true
356
+ it "is a subclass of the supplied superclass" do
357
+ expect(BlogPost < BlogPostParent).to be true
381
358
  end
382
359
 
383
- it 'is its own base_class' do
360
+ it "is its own base_class" do
384
361
  expect(BlogPost.base_class).to eq BlogPost
385
362
  end
386
363
 
387
- it 'responds to .with_model? with true' do
388
- expect(BlogPost.with_model?).to eq true
364
+ it "responds to .with_model? with true" do
365
+ expect(BlogPost.with_model?).to be true
366
+ end
367
+ end
368
+
369
+ context "with 'superclass' that connects to a different database" do
370
+ class ApplicationRecordInDifferentDatabase < ActiveRecord::Base # standard:disable Lint/ConstantDefinitionInBlock
371
+ self.abstract_class = true
372
+ establish_connection(ActiveRecord::Base.connection_pool.db_config.configuration_hash)
373
+ end
374
+
375
+ with_model :BlogPost, superclass: ApplicationRecordInDifferentDatabase do
376
+ table do |t|
377
+ t.string "title"
378
+ end
379
+ end
380
+
381
+ it "uses the superclass connection" do
382
+ expect(BlogPost.connection.tables).to include(BlogPost.table_name)
389
383
  end
390
384
  end
391
385
  end
data/test/test_helper.rb CHANGED
@@ -1,28 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
4
 
5
- # Workaround for JRuby CI failure https://github.com/jruby/jruby/issues/6547#issuecomment-774104996
6
- if RUBY_ENGINE == 'jruby'
7
- require 'i18n/backend'
8
- require 'i18n/backend/simple'
9
- end
10
-
11
- require 'with_model'
12
- require 'minitest/autorun'
5
+ require "with_model"
6
+ require "minitest/autorun"
13
7
 
14
8
  WithModel.runner = :minitest
15
9
 
16
- module MiniTest
17
- class Test
18
- extend WithModel
19
- end
10
+ Minitest::Test.class_eval do
11
+ extend WithModel
20
12
  end
21
13
 
22
- is_jruby = RUBY_PLATFORM == 'java'
23
- adapter = is_jruby ? 'jdbcsqlite3' : 'sqlite3'
24
-
25
14
  # WithModel requires ActiveRecord::Base.connection to be established.
26
15
  # If ActiveRecord already has a connection, as in a Rails app, this is unnecessary.
27
- require 'active_record'
28
- ActiveRecord::Base.establish_connection(adapter: adapter, database: ':memory:')
16
+ require "active_record"
17
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_helper'
3
+ require "test_helper"
4
4
 
5
- class WithModelTest < MiniTest::Test
5
+ class WithModelTest < Minitest::Test
6
6
  with_model :BlogPost do
7
7
  table do |t|
8
- t.string 'title'
9
- t.text 'content'
8
+ t.string "title"
9
+ t.text "content"
10
10
  t.timestamps null: false
11
11
  end
12
12
 
@@ -17,13 +17,13 @@ class WithModelTest < MiniTest::Test
17
17
  end
18
18
  end
19
19
 
20
- def test_it_should_act_like_a_normal_active_record_model # rubocop:disable Minitest/MultipleAssertions
21
- record = BlogPost.create!(title: 'New blog post', content: 'Hello, world!')
20
+ def test_it_should_act_like_a_normal_active_record_model
21
+ record = BlogPost.create!(title: "New blog post", content: "Hello, world!")
22
22
 
23
23
  record.reload
24
24
 
25
- assert_equal 'New blog post', record.title
26
- assert_equal 'Hello, world!', record.content
25
+ assert_equal "New blog post", record.title
26
+ assert_equal "Hello, world!", record.content
27
27
  assert record.updated_at
28
28
 
29
29
  record.destroy
@@ -34,6 +34,6 @@ class WithModelTest < MiniTest::Test
34
34
  end
35
35
 
36
36
  def test_it_has_the_methods_defined_in_its_model_block
37
- assert_equal 'Title: New blog post', BlogPost.new(title: 'New blog post').fancy_title
37
+ assert_equal "Title: New blog post", BlogPost.new(title: "New blog post").fancy_title
38
38
  end
39
39
  end
data/with_model.gemspec CHANGED
@@ -1,43 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $LOAD_PATH.push File.expand_path('lib', __dir__)
4
- require 'with_model/version'
3
+ $LOAD_PATH.push File.expand_path("lib", __dir__)
4
+ require "with_model/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = 'with_model'
8
- spec.version = WithModel::VERSION
9
- spec.authors = ['Case Commons, LLC', 'Grant Hutchins', 'Andrew Marshall']
10
- spec.email = %w[casecommons-dev@googlegroups.com gems@nertzy.com andrew@johnandrewmarshall.com]
11
- spec.homepage = 'https://github.com/Casecommons/with_model'
12
- spec.summary = 'Dynamically build a model within an RSpec context'
7
+ spec.name = "with_model"
8
+ spec.version = WithModel::VERSION
9
+ spec.authors = ["Case Commons, LLC", "Grant Hutchins", "Andrew Marshall"]
10
+ spec.email = %w[casecommons-dev@googlegroups.com gems@nertzy.com andrew@johnandrewmarshall.com]
11
+ spec.homepage = "https://github.com/Casecommons/with_model"
12
+ spec.summary = "Dynamically build a model within an RSpec context"
13
13
  spec.description = spec.summary
14
- spec.license = 'MIT'
15
- spec.metadata['rubygems_mfa_required'] = 'true'
14
+ spec.license = "MIT"
15
+ spec.metadata["rubygems_mfa_required"] = "true"
16
16
 
17
- spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
- spec.require_paths = ['lib']
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
21
20
 
22
- spec.required_ruby_version = '>= 2.6'
21
+ spec.required_ruby_version = ">= 3.1"
23
22
 
24
- spec.add_dependency 'activerecord', '>= 5.2'
25
-
26
- spec.add_development_dependency 'bundler'
27
- spec.add_development_dependency 'minitest'
28
- spec.add_development_dependency 'pry'
29
- spec.add_development_dependency 'rake'
30
- spec.add_development_dependency 'rspec'
31
- spec.add_development_dependency 'rubocop'
32
- spec.add_development_dependency 'rubocop-minitest'
33
- spec.add_development_dependency 'rubocop-rake'
34
- spec.add_development_dependency 'rubocop-rspec'
35
- spec.add_development_dependency 'simplecov'
36
- spec.add_development_dependency 'yard'
37
-
38
- if RUBY_PLATFORM == 'java'
39
- spec.add_development_dependency 'activerecord-jdbcsqlite3-adapter'
40
- else
41
- spec.add_development_dependency 'sqlite3'
42
- end
23
+ spec.add_dependency "activerecord", ">= 7.0"
43
24
  end