with_model 2.1.6 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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