with_model 2.1.7 → 2.3.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,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
- describe 'ActiveRecord behaviors' do
6
- describe 'a temporary ActiveRecord model created with with_model' do
7
- context 'that has a named scope' do
5
+ describe "ActiveRecord behaviors" do
6
+ describe "a temporary ActiveRecord model created with with_model" do
7
+ context "that has a named scope" do
8
8
  before do
9
9
  @regular_model = Class.new ActiveRecord::Base do
10
- self.table_name = 'regular_models'
11
- scope :title_is_foo, -> { where(title: 'foo') }
10
+ self.table_name = "regular_models"
11
+ scope :title_is_foo, -> { where(title: "foo") }
12
12
  end
13
13
 
14
14
  @regular_model.connection.create_table(@regular_model.table_name, force: true) do |t|
15
- t.string 'title'
16
- t.text 'content'
15
+ t.string "title"
16
+ t.text "content"
17
17
  t.timestamps null: false
18
18
  end
19
19
  end
@@ -24,37 +24,37 @@ describe 'ActiveRecord behaviors' do
24
24
 
25
25
  with_model :BlogPost do
26
26
  table do |t|
27
- t.string 'title'
28
- t.text 'content'
27
+ t.string "title"
28
+ t.text "content"
29
29
  t.timestamps null: false
30
30
  end
31
31
 
32
32
  model do
33
- scope :title_is_foo, -> { where(title: 'foo') }
33
+ scope :title_is_foo, -> { where(title: "foo") }
34
34
  end
35
35
  end
36
36
 
37
- describe 'the named scope' do
38
- it 'works like a regular named scope' do
39
- included = @regular_model.create!(title: 'foo', content: 'Include me!')
40
- @regular_model.create!(title: 'bar', content: 'Include me!')
37
+ describe "the named scope" do
38
+ it "works like a regular named scope" do
39
+ included = @regular_model.create!(title: "foo", content: "Include me!")
40
+ @regular_model.create!(title: "bar", content: "Include me!")
41
41
 
42
42
  expect(@regular_model.title_is_foo).to eq [included]
43
43
 
44
- included = BlogPost.create!(title: 'foo', content: 'Include me!')
45
- BlogPost.create!(title: 'bar', content: 'Include me!')
44
+ included = BlogPost.create!(title: "foo", content: "Include me!")
45
+ BlogPost.create!(title: "bar", content: "Include me!")
46
46
 
47
47
  expect(BlogPost.title_is_foo).to eq [included]
48
48
  end
49
49
  end
50
50
  end
51
51
 
52
- context 'that has a polymorphic belongs_to' do
52
+ context "that has a polymorphic belongs_to" do
53
53
  before do
54
54
  animal = Class.new ActiveRecord::Base do
55
55
  has_many :tea_cups, as: :pet
56
56
  end
57
- stub_const 'Animal', animal
57
+ stub_const "Animal", animal
58
58
  end
59
59
 
60
60
  with_model :TeaCup do
@@ -69,29 +69,30 @@ describe 'ActiveRecord behaviors' do
69
69
  with_table :animals
70
70
 
71
71
  with_model :StuffedAnimal do
72
+ table
72
73
  model do
73
74
  has_many :tea_cups, as: :pet
74
75
  end
75
76
  end
76
77
 
77
- describe 'the polymorphic belongs_to' do
78
- it 'works like a regular polymorphic belongs_to' do
78
+ describe "the polymorphic belongs_to" do
79
+ it "works like a regular polymorphic belongs_to" do
79
80
  animal = Animal.create!
80
81
  stuffed_animal = StuffedAnimal.create!
81
82
 
82
83
  tea_cup_for_animal = TeaCup.create!(pet: animal)
83
- expect(tea_cup_for_animal.pet_type).to eq 'Animal'
84
+ expect(tea_cup_for_animal.pet_type).to eq "Animal"
84
85
  expect(animal.tea_cups).to include(tea_cup_for_animal)
85
86
 
86
87
  tea_cup_for_stuffed_animal = TeaCup.create!(pet: stuffed_animal)
87
- expect(tea_cup_for_stuffed_animal.pet_type).to eq 'StuffedAnimal'
88
+ expect(tea_cup_for_stuffed_animal.pet_type).to eq "StuffedAnimal"
88
89
  expect(stuffed_animal.tea_cups).to include(tea_cup_for_stuffed_animal)
89
90
  end
90
91
  end
91
92
  end
92
93
  end
93
94
 
94
- context 'with an association' do
95
+ context "with an association" do
95
96
  with_model :Province do
96
97
  table do |t|
97
98
  t.belongs_to :country
@@ -101,15 +102,17 @@ describe 'ActiveRecord behaviors' do
101
102
  end
102
103
  end
103
104
 
104
- with_model :Country
105
+ with_model :Country do
106
+ table
107
+ end
105
108
 
106
- context 'in earlier examples' do
107
- it 'works as normal' do
109
+ context "in earlier examples" do
110
+ it "works as normal" do
108
111
  expect { Province.create!(country: Country.create!) }.not_to raise_error
109
112
  end
110
113
  end
111
114
 
112
- context 'in later examples' do
115
+ context "in later examples" do
113
116
  it "does not hold a reference to earlier example groups' classes" do
114
117
  expect(Province.reflect_on_association(:country).klass).to eq Country
115
118
  end
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
5
  module WithModel
6
6
  describe ConstantStubber do
7
- it 'allows calling unstub_const multiple times' do
8
- stubber = described_class.new('Foo')
7
+ it "allows calling unstub_const multiple times" do
8
+ stubber = described_class.new("Foo")
9
9
  stubber.stub_const(1)
10
10
  expect { 2.times { stubber.unstub_const } }.not_to raise_error
11
11
  end
12
12
 
13
- it 'allows calling unstub_const without stub_const' do
14
- stubber = described_class.new('Foo')
13
+ it "allows calling unstub_const without stub_const" do
14
+ stubber = described_class.new("Foo")
15
15
  expect { stubber.unstub_const }.not_to raise_error
16
16
  end
17
17
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe "Descendants tracking" do
6
+ with_model :BlogPost do
7
+ table
8
+ model do
9
+ def self.inspect
10
+ "BlogPost class #{object_id}"
11
+ end
12
+ end
13
+ end
14
+
15
+ def blog_post_classes
16
+ ActiveRecord::Base.descendants.select do |c|
17
+ c.table_name == BlogPost.table_name
18
+ end
19
+ end
20
+
21
+ shared_examples "clearing descendants between test runs" do
22
+ it "includes the correct model class in descendants on the first test run" do
23
+ expect(blog_post_classes).to eq [BlogPost]
24
+ end
25
+
26
+ it "includes the correct model class in descendants on the second test run" do
27
+ expect(blog_post_classes).to eq [BlogPost]
28
+ end
29
+ end
30
+
31
+ context "with ActiveSupport::DescendantsTracker (cache_classes: true)" do
32
+ before do
33
+ expect(ActiveSupport::DescendantsTracker.clear_disabled).to be_falsey
34
+ expect { ActiveSupport::DescendantsTracker.clear([]) }.not_to raise_exception
35
+ end
36
+
37
+ include_examples "clearing descendants between test runs"
38
+ end
39
+
40
+ context "without ActiveSupport::DescendantsTracker (cache_classes: false)" do
41
+ before do
42
+ ActiveSupport::DescendantsTracker.disable_clear!
43
+ expect(ActiveSupport::DescendantsTracker.clear_disabled).to be_truthy
44
+ expect { ActiveSupport::DescendantsTracker.clear([]) }.to raise_exception(RuntimeError)
45
+ end
46
+
47
+ include_examples "clearing descendants between test runs"
48
+ end
49
+ end
data/spec/readme_spec.rb CHANGED
@@ -1,31 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
- describe 'A blog post' do
6
- before do
7
- stub_const('MyModule', Module.new)
8
- end
5
+ module MyModule; end
6
+
7
+ # A pre-existing model
8
+ class Car < ActiveRecord::Base
9
+ self.abstract_class = true
10
+ end
9
11
 
12
+ describe "A blog post" do
10
13
  with_model :BlogPost do
11
- # The table block works just like a migration.
14
+ # The table block (and an options hash) is passed to Active Record migration’s `create_table`.
12
15
  table do |t|
13
16
  t.string :title
14
17
  t.timestamps null: false
15
18
  end
16
19
 
17
- # The model block works just like the class definition.
20
+ # The model block is the Active Record model’s class body.
18
21
  model do
19
22
  include MyModule
23
+
20
24
  has_many :comments
21
25
  validates_presence_of :title
22
26
 
23
27
  def self.some_class_method
24
- 'chunky'
28
+ "chunky"
25
29
  end
26
30
 
27
31
  def some_instance_method
28
- 'bacon'
32
+ "bacon"
29
33
  end
30
34
  end
31
35
  end
@@ -43,46 +47,46 @@ describe 'A blog post' do
43
47
  end
44
48
  end
45
49
 
46
- it 'can be accessed as a constant' do
50
+ it "can be accessed as a constant" do
47
51
  expect(BlogPost).to be
48
52
  end
49
53
 
50
- it 'has the module' do
54
+ it "has the module" do
51
55
  expect(BlogPost.include?(MyModule)).to be true
52
56
  end
53
57
 
54
- it 'has the class method' do
55
- expect(BlogPost.some_class_method).to eq 'chunky'
58
+ it "has the class method" do
59
+ expect(BlogPost.some_class_method).to eq "chunky"
56
60
  end
57
61
 
58
- it 'has the instance method' do
59
- expect(BlogPost.new.some_instance_method).to eq 'bacon'
62
+ it "has the instance method" do
63
+ expect(BlogPost.new.some_instance_method).to eq "bacon"
60
64
  end
61
65
 
62
- it 'can do all the things a regular model can' do
66
+ it "can do all the things a regular model can" do
63
67
  record = BlogPost.new
64
68
  expect(record).not_to be_valid
65
- record.title = 'foo'
69
+ record.title = "foo"
66
70
  expect(record).to be_valid
67
71
  expect(record.save).to be true
68
72
  expect(record.reload).to eq record
69
- record.comments.create!(text: 'Lorem ipsum')
73
+ record.comments.create!(text: "Lorem ipsum")
70
74
  expect(record.comments.count).to eq 1
71
75
  end
72
76
 
73
- # with_model classes can have inheritance.
74
- class Car < ActiveRecord::Base
75
- self.abstract_class = true
77
+ # with_model classes can have inheritance. Car is abstract, so it has no table
78
+ # and Ford gets one of its own. To inherit a concrete superclass's table
79
+ # instead, see "Single table inheritance" below.
80
+ with_model :Ford, superclass: Car do
81
+ table
76
82
  end
77
83
 
78
- with_model :Ford, superclass: Car
79
-
80
- it 'has a specified superclass' do
81
- expect(Ford < Car).to be true
84
+ it "has a specified superclass" do
85
+ expect(Ford.new).to be_a(Car)
82
86
  end
83
87
  end
84
88
 
85
- describe 'with_model can be run within RSpec :all hook' do
89
+ describe "with_model can be run within RSpec :all hook" do
86
90
  with_model :BlogPost, scope: :all do
87
91
  table do |t|
88
92
  t.string :title
@@ -93,26 +97,71 @@ describe 'with_model can be run within RSpec :all hook' do
93
97
  BlogPost.create # without scope: :all these will fail
94
98
  end
95
99
 
96
- it 'has been initialized within before(:all)' do
100
+ it "has been initialized within before(:all)" do
97
101
  expect(BlogPost.count).to eq 1
98
102
  end
99
103
  end
100
104
 
101
- describe 'another example group' do
102
- it 'does not have the constant anymore' do
105
+ describe "another example group" do
106
+ it "does not have the constant anymore" do
103
107
  expect(defined?(BlogPost)).to be_falsy
104
108
  end
105
109
  end
106
110
 
107
- describe 'with table options' do
111
+ describe "with table options" do
108
112
  with_model :WithOptions do
109
113
  table id: false do |t|
110
- t.string 'foo'
114
+ t.string "foo"
111
115
  t.timestamps null: false
112
116
  end
113
117
  end
114
118
 
115
- it 'respects the additional options' do
116
- expect(WithOptions.columns.map(&:name)).not_to include('id')
119
+ it "respects the additional options" do
120
+ expect(WithOptions.columns.map(&:name)).not_to include("id")
121
+ end
122
+ end
123
+
124
+ describe "with_model supports Single Table Inheritance" do
125
+ with_model :Sandwich do
126
+ table do |t|
127
+ t.string "type"
128
+ t.string "bread"
129
+ end
130
+ end
131
+
132
+ with_model :ChunkyBacon, superclass: :Sandwich do
133
+ table(false)
134
+ end
135
+
136
+ it "shares the superclass's table" do
137
+ expect(ChunkyBacon.table_name).to eq Sandwich.table_name
138
+ end
139
+
140
+ it "stores its own type" do
141
+ sandwich = ChunkyBacon.create!(bread: "rye")
142
+
143
+ expect(sandwich.reload.type).to eq "ChunkyBacon"
144
+ expect(Sandwich.first).to be_a ChunkyBacon
145
+ end
146
+ end
147
+
148
+ describe "with_model supports foreign keys" do
149
+ with_model :Author do
150
+ table
151
+ end
152
+
153
+ with_model :Book do
154
+ table do |t|
155
+ t.references :author, foreign_key: {to_table: Author.table_name}
156
+ end
157
+
158
+ model do
159
+ belongs_to :author
160
+ end
161
+ end
162
+
163
+ it "has a foreign key" do
164
+ expect { Book.create!(author_id: 0) }
165
+ .to raise_error ActiveRecord::InvalidForeignKey
117
166
  end
118
167
  end
data/spec/spec_helper.rb CHANGED
@@ -1,16 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Workaround for JRuby CI failure https://github.com/jruby/jruby/issues/6547#issuecomment-774104996
4
- if RUBY_ENGINE == 'jruby'
5
- require 'i18n/backend'
6
- require 'i18n/backend/simple'
7
- end
8
-
9
- require 'simplecov'
10
- SimpleCov.start
3
+ require "bundler/setup"
4
+ require "with_model"
11
5
 
12
- require 'bundler/setup'
13
- require 'with_model'
6
+ WithModel.deprecator.behavior = :raise
14
7
 
15
8
  RSpec.configure do |config|
16
9
  config.extend WithModel
@@ -26,24 +19,21 @@ RSpec.configure do |config|
26
19
  end
27
20
  end
28
21
 
29
- is_jruby = RUBY_PLATFORM == 'java'
30
- adapter = is_jruby ? 'jdbcsqlite3' : 'sqlite3'
31
-
32
22
  # WithModel requires ActiveRecord::Base.connection to be established.
33
23
  # If ActiveRecord already has a connection, as in a Rails app, this is unnecessary.
34
- require 'active_record'
35
- ActiveRecord::Base.establish_connection(adapter: adapter, database: ':memory:')
24
+ require "active_record"
25
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
36
26
 
37
27
  I18n.enforce_available_locales = true if defined?(I18n) && I18n.respond_to?(:enforce_available_locales=)
38
28
 
39
- if ENV['LOGGER']
40
- require 'logger'
29
+ if ENV["LOGGER"]
30
+ require "logger"
41
31
  ActiveRecord::Base.logger = Logger.new($stdout)
42
32
  end
43
33
 
44
34
  module SpecHelper
45
35
  module RailsTestCompatibility
46
- require 'minitest'
36
+ require "minitest"
47
37
  include Minitest::Assertions
48
38
 
49
39
  def assertions