nested_record 1.0.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5710483535afba122d37dded3a1cf743254f6a2ea43e40ad126adf8a98bf8ed3
4
- data.tar.gz: 6219144c936fae21346f49380082b773e44c6e1bbed670de53f6b96a5d4200ec
3
+ metadata.gz: 0761ce9c739c3f58d9ee2b52552664015df2d6fb6aed4dab164dd33038fbc1fe
4
+ data.tar.gz: 2d63fb82c3be079c5de28599ca02d0d4ddeb20c5a82f554901601bbaa8b70011
5
5
  SHA512:
6
- metadata.gz: dbfb5c90d3a43c9a0671af39bc3969ca544deb1ba58809800d018621d4dccded78efdba763dfb425299236cb8fd631dfe6b30786fdab45d1fe6b712070afd0fd
7
- data.tar.gz: b18afab1feb7f6e29cac1cfec75a7b4176c3a35bf3de85a6b411d4a6501617f363c5e757d04cd009094002cba78c45682f189ad9235908598db04e65aac3e0da
6
+ metadata.gz: 8ff11ab93295ca0d08551e513f81b6f086c115c264c7c3ae7843fcb34dcae099b549f2501b9cad65425708593a018b76af00ab2e76339317dbd9ad57a759a9ef
7
+ data.tar.gz: d6cb9f2f8fcc4c7b958905e93690cb8f7e319fad664780e4e1abb311b15d66f7c6f28b756874a5f1035c31ecd2fcf03935ee35f711e66d411595a86ea66b6b65
@@ -0,0 +1,50 @@
1
+ name: RSpec
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - master
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby:
15
+ - "2.6"
16
+ - "2.7"
17
+ - "3.0"
18
+ - "3.1"
19
+ - "3.2"
20
+ gemfile:
21
+ - gemfiles/rails_5.2.gemfile
22
+ - gemfiles/rails_6.0.gemfile
23
+ - gemfiles/rails_6.1.gemfile
24
+ - gemfiles/rails_7.0.gemfile
25
+ - gemfiles/rails_7.1.gemfile
26
+ exclude:
27
+ - gemfile: gemfiles/rails_5.2.gemfile
28
+ ruby: "3.0"
29
+ - gemfile: gemfiles/rails_5.2.gemfile
30
+ ruby: "3.1"
31
+ - gemfile: gemfiles/rails_5.2.gemfile
32
+ ruby: "3.2"
33
+ - gemfile: gemfiles/rails_7.0.gemfile
34
+ ruby: "2.6"
35
+ - gemfile: gemfiles/rails_7.1.gemfile
36
+ ruby: "2.6"
37
+ env:
38
+ BUNDLE_GEMFILE: ${{ format('{0}/{1}', github.workspace, matrix.gemfile) }}
39
+ BUNDLE_PATH: ${{ format('{0}/vendor/bundle', github.workspace) }}
40
+ BUNDLE_DEPLOYMENT: true
41
+ steps:
42
+ - name: Checkout
43
+ uses: actions/checkout@v1
44
+ - name: Setup ruby
45
+ uses: ruby/setup-ruby@v1
46
+ with:
47
+ ruby-version: ${{ matrix.ruby }}
48
+ bundler-cache: true
49
+ - name: RSpec
50
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -6,8 +6,6 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
- /Gemfile.lock
10
- /gemfiles/*.lock
11
9
 
12
10
  # rspec failure tracking
13
11
  .rspec_status
data/Appraisals ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise "rails-5.2" do
4
+ gem 'activemodel', '~> 5.2.8.1'
5
+ end
6
+
7
+ appraise "rails-6.0" do
8
+ gem 'activemodel', '~> 6.0.6.1'
9
+ end
10
+
11
+ appraise "rails-6.1" do
12
+ gem 'activemodel', '~> 6.1.7.6'
13
+ end
14
+
15
+ appraise "rails-7.0" do
16
+ gem 'activemodel', '~> 7.0.8'
17
+ end
18
+
19
+ appraise "rails-7.1" do
20
+ gem 'activemodel', '~> 7.1.1'
21
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nested_record (1.1.1)
5
+ activemodel (> 5.2, < 7.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (7.1.1)
11
+ activesupport (= 7.1.1)
12
+ activesupport (7.1.1)
13
+ base64
14
+ bigdecimal
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ connection_pool (>= 2.2.5)
17
+ drb
18
+ i18n (>= 1.6, < 2)
19
+ minitest (>= 5.1)
20
+ mutex_m
21
+ tzinfo (~> 2.0)
22
+ appraisal (2.5.0)
23
+ bundler
24
+ rake
25
+ thor (>= 0.14.0)
26
+ base64 (0.1.1)
27
+ bigdecimal (3.1.4)
28
+ concurrent-ruby (1.2.2)
29
+ connection_pool (2.4.1)
30
+ diff-lcs (1.5.0)
31
+ drb (2.1.1)
32
+ ruby2_keywords
33
+ i18n (1.14.1)
34
+ concurrent-ruby (~> 1.0)
35
+ minitest (5.20.0)
36
+ mutex_m (0.1.2)
37
+ rake (13.0.6)
38
+ rspec (3.12.0)
39
+ rspec-core (~> 3.12.0)
40
+ rspec-expectations (~> 3.12.0)
41
+ rspec-mocks (~> 3.12.0)
42
+ rspec-core (3.12.2)
43
+ rspec-support (~> 3.12.0)
44
+ rspec-expectations (3.12.3)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.12.0)
47
+ rspec-mocks (3.12.6)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.12.0)
50
+ rspec-support (3.12.1)
51
+ ruby2_keywords (0.0.5)
52
+ thor (1.2.2)
53
+ tzinfo (2.0.6)
54
+ concurrent-ruby (~> 1.0)
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ appraisal
61
+ bundler (>= 2)
62
+ nested_record!
63
+ rake (~> 13.0)
64
+ rspec (~> 3.0)
65
+
66
+ BUNDLED WITH
67
+ 2.2.14
data/README.md CHANGED
@@ -105,6 +105,124 @@ user.profile_attributes = {
105
105
  }
106
106
  ```
107
107
 
108
+ ## Advanced usage
109
+
110
+ `nested_record` can do many different things for you!
111
+
112
+ ### Validations
113
+
114
+ Every `NestedRecord::Base` descendant in fact is an `ActiveModel::Model` so standard validations are also supported.
115
+
116
+ ```ruby
117
+ class Profile < NestedRecord::Base
118
+ attribute :age, :integer
119
+ attribute :active, :boolean
120
+
121
+ validates :age, presence: true
122
+ end
123
+ ```
124
+
125
+ ### Don't bother with defining record micro-classes
126
+
127
+ If you want so, you can rewrite the above example this way:
128
+
129
+ ```ruby
130
+ class User < ApplicationRecord
131
+ has_one_nested :profile do
132
+ attribute :age, :integer
133
+ attribute :active, :boolean
134
+ has_one_nested :contacts do
135
+ attribute :email, :string
136
+ attribute :phone, :string
137
+ has_many_nested :socials do
138
+ attribute :name
139
+ attribute :url
140
+ end
141
+ end
142
+ end
143
+ end
144
+ ```
145
+
146
+ Record classes then available under _local types_ namespace module e.g. `User::LocalTypes::Profile`.
147
+
148
+ ### Concerns
149
+
150
+ Common attributes, validations and other settings can be DRY-ed to modules called _concerns_.
151
+
152
+ ```ruby
153
+ module TitleAndDescription
154
+ extend NestedRecord::Concern
155
+
156
+ attribute :title
157
+ attribute :description
158
+
159
+ validates :title, presence: true
160
+ end
161
+
162
+ class Article < NestedRecord::Base
163
+ has_one_nested :foo do
164
+ include TitleAndDescription
165
+ end
166
+ end
167
+ ```
168
+
169
+ ### `:class_name` option
170
+
171
+ By default, class name of nested record is automatically inferred from the association name but of course it's all customizable. There's a `:class_name` option for this!
172
+
173
+ Depending on what form do you use — `has_* :foo` or `has_* :foo do ... end`, the `:class_name` option means different things.
174
+
175
+ #### `:class_name` option when referring an external model
176
+
177
+ In a non-`&block` form, the `:class_name` behaves similar to the option with same name in ActiveRecord's `has_one`/`has_many` associations.
178
+
179
+ ```ruby
180
+ class User < ApplicationRecord
181
+ has_one_nested :profile, class_name: 'SomeNamespace::Profile'
182
+ end
183
+
184
+ class SomeNamespace::Profile < NestedRecord::Base
185
+ attribute :age, :integer
186
+ attribute :active, :boolean
187
+ end
188
+ ```
189
+
190
+ #### `:class_name` option when using with an embedded _local types_
191
+
192
+ When record definition is embedded, `:class_name` option denotes the name of the class in _local types_ namespace module under which it's defined.
193
+
194
+ ```ruby
195
+ class User < ApplicationRecord
196
+ has_one_nested :profile, class_name: 'ProfileRecord' do
197
+ attribute :age, :integer
198
+ attribute :active, :boolean
199
+ end
200
+ end
201
+ ```
202
+
203
+ Then the profile model is available under `User::LocalTypes::ProfileRecord` name.
204
+
205
+ You can also disable the const naming at all, passing `class_name: false`. In this case, the _local type_ is anonymous so no constant in _local types_ namespace is set.
206
+
207
+ `class_name: true` (the default) means infer the class name from association name e.g. `User::LocalTypes::Profile` constant is set by default.
208
+
209
+ ### `nested_accessors`
210
+
211
+ This is the `store_accessor` on steroids! Unlike `store_accessor` it's support nesting, type coercions and all other things this library can do. Think of it as a `has_one_nested` association with accessors lifted up one level.
212
+
213
+ ```ruby
214
+ class User < ApplicationRecord
215
+ nested_accessors from: :profile do
216
+ attribute :age, :integer
217
+ attribute :active, :integer
218
+ end
219
+ end
220
+
221
+ user = User.new
222
+ user.age = 33
223
+ user.active = true
224
+ ```
225
+
108
226
  ## Development
109
227
 
110
228
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,5 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
- gem "rails", "~> 5.2.3"
5
+ gem "activemodel", "~> 5.2.8.1"
4
6
 
5
- gemspec :path => "../"
7
+ gemspec path: "../"
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ nested_record (1.1.1)
5
+ activemodel (> 5.2, < 7.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (5.2.8.1)
11
+ activesupport (= 5.2.8.1)
12
+ activesupport (5.2.8.1)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ appraisal (2.5.0)
18
+ bundler
19
+ rake
20
+ thor (>= 0.14.0)
21
+ concurrent-ruby (1.2.2)
22
+ diff-lcs (1.5.0)
23
+ i18n (1.14.1)
24
+ concurrent-ruby (~> 1.0)
25
+ minitest (5.20.0)
26
+ rake (13.0.6)
27
+ rspec (3.12.0)
28
+ rspec-core (~> 3.12.0)
29
+ rspec-expectations (~> 3.12.0)
30
+ rspec-mocks (~> 3.12.0)
31
+ rspec-core (3.12.2)
32
+ rspec-support (~> 3.12.0)
33
+ rspec-expectations (3.12.3)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.12.0)
36
+ rspec-mocks (3.12.6)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.12.0)
39
+ rspec-support (3.12.1)
40
+ thor (1.3.0)
41
+ thread_safe (0.3.6)
42
+ tzinfo (1.2.11)
43
+ thread_safe (~> 0.1)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ activemodel (~> 5.2.8.1)
50
+ appraisal
51
+ bundler (>= 2)
52
+ nested_record!
53
+ rake (~> 13.0)
54
+ rspec (~> 3.0)
55
+
56
+ BUNDLED WITH
57
+ 2.3.22
@@ -1,5 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
- gem "rails", "~> 6.0.0"
5
+ gem "activemodel", "~> 6.0.6.1"
4
6
 
5
- gemspec :path => "../"
7
+ gemspec path: "../"
@@ -0,0 +1,59 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ nested_record (1.1.1)
5
+ activemodel (> 5.2, < 7.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (6.0.6.1)
11
+ activesupport (= 6.0.6.1)
12
+ activesupport (6.0.6.1)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ zeitwerk (~> 2.2, >= 2.2.2)
18
+ appraisal (2.5.0)
19
+ bundler
20
+ rake
21
+ thor (>= 0.14.0)
22
+ concurrent-ruby (1.2.2)
23
+ diff-lcs (1.5.0)
24
+ i18n (1.14.1)
25
+ concurrent-ruby (~> 1.0)
26
+ minitest (5.20.0)
27
+ rake (13.0.6)
28
+ rspec (3.12.0)
29
+ rspec-core (~> 3.12.0)
30
+ rspec-expectations (~> 3.12.0)
31
+ rspec-mocks (~> 3.12.0)
32
+ rspec-core (3.12.2)
33
+ rspec-support (~> 3.12.0)
34
+ rspec-expectations (3.12.3)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.12.0)
37
+ rspec-mocks (3.12.6)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.12.0)
40
+ rspec-support (3.12.1)
41
+ thor (1.3.0)
42
+ thread_safe (0.3.6)
43
+ tzinfo (1.2.11)
44
+ thread_safe (~> 0.1)
45
+ zeitwerk (2.6.12)
46
+
47
+ PLATFORMS
48
+ ruby
49
+
50
+ DEPENDENCIES
51
+ activemodel (~> 6.0.6.1)
52
+ appraisal
53
+ bundler (>= 2)
54
+ nested_record!
55
+ rake (~> 13.0)
56
+ rspec (~> 3.0)
57
+
58
+ BUNDLED WITH
59
+ 2.4.20
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activemodel", "~> 6.1.7.6"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ nested_record (1.1.1)
5
+ activemodel (> 5.2, < 7.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (6.1.7.6)
11
+ activesupport (= 6.1.7.6)
12
+ activesupport (6.1.7.6)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ zeitwerk (~> 2.3)
18
+ appraisal (2.5.0)
19
+ bundler
20
+ rake
21
+ thor (>= 0.14.0)
22
+ concurrent-ruby (1.2.2)
23
+ diff-lcs (1.5.0)
24
+ i18n (1.14.1)
25
+ concurrent-ruby (~> 1.0)
26
+ minitest (5.20.0)
27
+ rake (13.0.6)
28
+ rspec (3.12.0)
29
+ rspec-core (~> 3.12.0)
30
+ rspec-expectations (~> 3.12.0)
31
+ rspec-mocks (~> 3.12.0)
32
+ rspec-core (3.12.2)
33
+ rspec-support (~> 3.12.0)
34
+ rspec-expectations (3.12.3)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.12.0)
37
+ rspec-mocks (3.12.6)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.12.0)
40
+ rspec-support (3.12.1)
41
+ thor (1.3.0)
42
+ tzinfo (2.0.6)
43
+ concurrent-ruby (~> 1.0)
44
+ zeitwerk (2.6.12)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ activemodel (~> 6.1.7.6)
51
+ appraisal
52
+ bundler (>= 2)
53
+ nested_record!
54
+ rake (~> 13.0)
55
+ rspec (~> 3.0)
56
+
57
+ BUNDLED WITH
58
+ 2.4.20
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activemodel", "~> 7.0.8"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ nested_record (1.1.1)
5
+ activemodel (> 5.2, < 7.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (7.0.8)
11
+ activesupport (= 7.0.8)
12
+ activesupport (7.0.8)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ appraisal (2.5.0)
18
+ bundler
19
+ rake
20
+ thor (>= 0.14.0)
21
+ concurrent-ruby (1.2.2)
22
+ diff-lcs (1.5.0)
23
+ i18n (1.14.1)
24
+ concurrent-ruby (~> 1.0)
25
+ minitest (5.20.0)
26
+ rake (13.0.6)
27
+ rspec (3.12.0)
28
+ rspec-core (~> 3.12.0)
29
+ rspec-expectations (~> 3.12.0)
30
+ rspec-mocks (~> 3.12.0)
31
+ rspec-core (3.12.2)
32
+ rspec-support (~> 3.12.0)
33
+ rspec-expectations (3.12.3)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.12.0)
36
+ rspec-mocks (3.12.6)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.12.0)
39
+ rspec-support (3.12.1)
40
+ thor (1.3.0)
41
+ tzinfo (2.0.6)
42
+ concurrent-ruby (~> 1.0)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ activemodel (~> 7.0.8)
49
+ appraisal
50
+ bundler (>= 2)
51
+ nested_record!
52
+ rake (~> 13.0)
53
+ rspec (~> 3.0)
54
+
55
+ BUNDLED WITH
56
+ 2.4.20
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activemodel", "~> 7.1.1"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ nested_record (1.1.1)
5
+ activemodel (> 5.2, < 7.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (7.1.1)
11
+ activesupport (= 7.1.1)
12
+ activesupport (7.1.1)
13
+ base64
14
+ bigdecimal
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ connection_pool (>= 2.2.5)
17
+ drb
18
+ i18n (>= 1.6, < 2)
19
+ minitest (>= 5.1)
20
+ mutex_m
21
+ tzinfo (~> 2.0)
22
+ appraisal (2.5.0)
23
+ bundler
24
+ rake
25
+ thor (>= 0.14.0)
26
+ base64 (0.1.1)
27
+ bigdecimal (3.1.4)
28
+ concurrent-ruby (1.2.2)
29
+ connection_pool (2.4.1)
30
+ diff-lcs (1.5.0)
31
+ drb (2.1.1)
32
+ ruby2_keywords
33
+ i18n (1.14.1)
34
+ concurrent-ruby (~> 1.0)
35
+ minitest (5.20.0)
36
+ mutex_m (0.1.2)
37
+ rake (13.0.6)
38
+ rspec (3.12.0)
39
+ rspec-core (~> 3.12.0)
40
+ rspec-expectations (~> 3.12.0)
41
+ rspec-mocks (~> 3.12.0)
42
+ rspec-core (3.12.2)
43
+ rspec-support (~> 3.12.0)
44
+ rspec-expectations (3.12.3)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.12.0)
47
+ rspec-mocks (3.12.6)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.12.0)
50
+ rspec-support (3.12.1)
51
+ ruby2_keywords (0.0.5)
52
+ thor (1.3.0)
53
+ tzinfo (2.0.6)
54
+ concurrent-ruby (~> 1.0)
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ activemodel (~> 7.1.1)
61
+ appraisal
62
+ bundler (>= 2)
63
+ nested_record!
64
+ rake (~> 13.0)
65
+ rspec (~> 3.0)
66
+
67
+ BUNDLED WITH
68
+ 2.4.20
@@ -143,11 +143,11 @@ class NestedRecord::Base
143
143
  subclass ||=
144
144
  begin
145
145
  if type_name.start_with?('::')
146
- ActiveSupport::Dependencies.constantize(type_name)
146
+ NestedRecord.constantize(type_name)
147
147
  elsif subtypes_store_full?
148
- ActiveSupport::Dependencies.constantize(type_name)
148
+ NestedRecord.constantize(type_name)
149
149
  elsif subtypes_namespace
150
- ActiveSupport::Dependencies.safe_constantize("#{subtypes_namespace}::#{type_name}") || ActiveSupport::Dependencies.constantize(type_name)
150
+ NestedRecord.safe_constantize("#{subtypes_namespace}::#{type_name}") || NestedRecord.constantize(type_name)
151
151
  else
152
152
  NestedRecord.lookup_const(self, type_name)
153
153
  end
@@ -247,7 +247,9 @@ class NestedRecord::Base
247
247
  end
248
248
 
249
249
  def read_attribute(attr)
250
- attribute(attr)
250
+ name = attr.to_s
251
+ name = self.class.attribute_aliases[name] || name
252
+ @attributes.fetch_value(name)
251
253
  end
252
254
 
253
255
  def query_attribute(attr)
@@ -21,7 +21,7 @@ class NestedRecord::Collection
21
21
 
22
22
  def each
23
23
  return to_enum(:each) unless block_given?
24
- @ary.each(&proc)
24
+ @ary.each { |obj| yield obj }
25
25
  end
26
26
 
27
27
  def to_ary
@@ -70,19 +70,19 @@ class NestedRecord::Collection
70
70
 
71
71
  def select!
72
72
  return to_enum(:select!) unless block_given?
73
- @ary.select!(&proc)
73
+ @ary.select! { |obj| yield obj }
74
74
  self
75
75
  end
76
76
 
77
77
  def reject!
78
78
  return to_enum(:reject!) unless block_given?
79
- @ary.reject!(&proc)
79
+ @ary.reject! { |obj| yield obj }
80
80
  self
81
81
  end
82
82
 
83
83
  def sort_by!
84
84
  return to_enum(:sort_by!) unless block_given?
85
- @ary.sort_by!(&proc)
85
+ @ary.sort_by! { |obj| yield obj }
86
86
  self
87
87
  end
88
88
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class NestedRecord::CollectionProxy
2
4
  extend Forwardable
3
5
  include Enumerable
@@ -1,18 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NestedRecord
4
- # Derived from Rails source: https://github.com/rails/rails/blob/98a57aa5f610bc66af31af409c72173cdeeb3c9e/activerecord/lib/active_record/inheritance.rb#L181-L207
4
+ # TODO: Remove this when we drop support for Rails < 7.0
5
+ if ActiveSupport::VERSION::MAJOR < 7
6
+ def self.constantize(type_name)
7
+ ActiveSupport::Dependencies.constantize(type_name)
8
+ end
9
+
10
+ def self.safe_constantize(type_name)
11
+ ActiveSupport::Dependencies.safe_constantize(type_name)
12
+ end
13
+ else
14
+ def self.constantize(type_name)
15
+ type_name.constantize
16
+ end
5
17
 
18
+ def self.safe_constantize(type_name)
19
+ type_name.safe_constantize
20
+ end
21
+ end
22
+
23
+ # Derived from Rails source: https://github.com/rails/rails/blob/98a57aa5f610bc66af31af409c72173cdeeb3c9e/activerecord/lib/active_record/inheritance.rb#L181-L207
6
24
  def self.lookup_const(owner, type_name)
7
25
  if type_name.start_with?('::')
8
- ActiveSupport::Dependencies.constantize(type_name)
26
+ NestedRecord.constantize(type_name)
9
27
  else
10
28
  candidates = []
11
29
  owner.name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
12
30
  candidates << type_name
13
31
 
14
32
  candidates.each do |candidate|
15
- constant = ActiveSupport::Dependencies.safe_constantize(candidate)
33
+ constant = NestedRecord.safe_constantize(candidate)
16
34
  return constant if candidate == constant.to_s
17
35
  end
18
36
 
@@ -28,16 +28,20 @@ class NestedRecord::MacroRecorder
28
28
  after_initialize
29
29
  before_validation after_validation
30
30
  ].freeze.each do |meth|
31
- define_method(meth) do |*args, &block|
32
- @macros << [meth, args, block]
31
+ define_method(meth) do |*args, **kwargs, &block|
32
+ @macros << [meth, args, kwargs, block]
33
33
  end
34
34
  end
35
35
 
36
36
  def apply_to(mod_or_class)
37
37
  macros = @macros
38
38
  mod_or_class.module_eval do
39
- macros.each do |meth, args, block|
40
- public_send(meth, *args, &block)
39
+ macros.each do |meth, args, kwargs, block|
40
+ if kwargs.empty?
41
+ public_send(meth, *args, &block)
42
+ else
43
+ public_send(meth, *args, **kwargs, &block)
44
+ end
41
45
  end
42
46
  end
43
47
  end
@@ -95,24 +95,40 @@ class NestedRecord::Methods
95
95
 
96
96
  def validation_method_body
97
97
  name = @setup.name
98
- proc do
99
- collection = public_send(name)
100
- collection.map.with_index do |record, index|
101
- next true if record.valid?
102
- record.errors.each do |attribute, message|
103
- error_attribute = "#{name}[#{index}].#{attribute}"
104
- errors[error_attribute] << message
105
- errors[error_attribute].uniq!
106
- end
107
- record.errors.details.each_key do |attribute|
108
- error_attribute = "#{name}[#{index}].#{attribute}"
109
- record.errors.details[attribute].each do |error|
110
- errors.details[error_attribute] << error
111
- errors.details[error_attribute].uniq!
98
+ if ActiveModel::VERSION::MAJOR < 6 || (ActiveModel::VERSION::MAJOR == 6 && ActiveModel::VERSION::MINOR < 1)
99
+ proc do
100
+ collection = public_send(name)
101
+ collection.map.with_index do |record, index|
102
+ next true if record.valid?
103
+ record.errors.each do |attribute, message|
104
+ error_attribute = "#{name}[#{index}].#{attribute}"
105
+ errors[error_attribute] << message
106
+ errors[error_attribute].uniq!
112
107
  end
113
- end
114
- false
115
- end.all?
108
+ record.errors.details.each_key do |attribute|
109
+ error_attribute = "#{name}[#{index}].#{attribute}"
110
+ record.errors.details[attribute].each do |error|
111
+ errors.details[error_attribute] << error
112
+ errors.details[error_attribute].uniq!
113
+ end
114
+ end
115
+ false
116
+ end.all?
117
+ end
118
+ else
119
+ proc do
120
+ collection = public_send(name)
121
+ collection.map.with_index do |record, index|
122
+ next true if record.valid?
123
+ record.errors.group_by_attribute.each do |attribute, errors|
124
+ error_attribute = "#{name}[#{index}].#{attribute}"
125
+ errors.each do |error|
126
+ self.errors.import(error, attribute: error_attribute)
127
+ end
128
+ end
129
+ false
130
+ end.all?
131
+ end
116
132
  end
117
133
  end
118
134
  end
@@ -62,24 +62,40 @@ class NestedRecord::Methods
62
62
 
63
63
  def validation_method_body
64
64
  name = @setup.name
65
- proc do
66
- record = public_send(name)
67
- return true unless record
68
- return true if record.valid?
65
+ if ActiveModel::VERSION::MAJOR < 6 || (ActiveModel::VERSION::MAJOR == 6 && ActiveModel::VERSION::MINOR < 1)
66
+ proc do
67
+ record = public_send(name)
68
+ return true unless record
69
+ return true if record.valid?
69
70
 
70
- record.errors.each do |attribute, message|
71
- error_attribute = "#{name}.#{attribute}"
72
- errors[error_attribute] << message
73
- errors[error_attribute].uniq!
71
+ record.errors.each do |attribute, message|
72
+ error_attribute = "#{name}.#{attribute}"
73
+ errors[error_attribute] << message
74
+ errors[error_attribute].uniq!
75
+ end
76
+ record.errors.details.each_key do |attribute|
77
+ error_attribute = "#{name}.#{attribute}"
78
+ record.errors.details[attribute].each do |error|
79
+ errors.details[error_attribute] << error
80
+ errors.details[error_attribute].uniq!
81
+ end
82
+ end
83
+ false
74
84
  end
75
- record.errors.details.each_key do |attribute|
76
- error_attribute = "#{name}.#{attribute}"
77
- record.errors.details[attribute].each do |error|
78
- errors.details[error_attribute] << error
79
- errors.details[error_attribute].uniq!
85
+ else
86
+ proc do
87
+ record = public_send(name)
88
+ return true unless record
89
+ return true if record.valid?
90
+
91
+ record.errors.group_by_attribute.each do |attribute, errors|
92
+ error_attribute = "#{name}.#{attribute}"
93
+ errors.each do |error|
94
+ self.errors.import(error, attribute: error_attribute)
95
+ end
80
96
  end
97
+ false
81
98
  end
82
- false
83
99
  end
84
100
  end
85
101
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class NestedRecord::Type < ActiveRecord::Type::Json
3
+ class NestedRecord::Type < ActiveModel::Type::Value
4
4
  require 'nested_record/type/many'
5
5
  require 'nested_record/type/one'
6
6
 
@@ -13,11 +13,16 @@ class NestedRecord::Type < ActiveRecord::Type::Json
13
13
  end
14
14
 
15
15
  def deserialize(value)
16
- cast_value(super)
16
+ value = if value.is_a?(::String)
17
+ ActiveSupport::JSON.decode(value) rescue nil
18
+ else
19
+ value
20
+ end
21
+ cast_value(value)
17
22
  end
18
23
 
19
24
  def serialize(obj)
20
- super(obj&.as_json)
25
+ ActiveSupport::JSON.encode(obj.as_json) unless obj.nil?
21
26
  end
22
27
 
23
28
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NestedRecord
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.1'
5
5
  end
data/lib/nested_record.rb CHANGED
@@ -3,9 +3,11 @@ module NestedRecord
3
3
 
4
4
  require 'forwardable'
5
5
 
6
- require 'active_record'
6
+ require 'active_model'
7
7
  require 'active_support/dependencies'
8
+ require 'active_support/inflector'
8
9
  require 'active_support/concern'
10
+ require 'active_support/json'
9
11
 
10
12
  require 'nested_record/macro'
11
13
  require 'nested_record/base'
@@ -22,11 +22,10 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_development_dependency "bundler", "~> 2.0"
26
- spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "bundler", ">= 2"
26
+ spec.add_development_dependency "rake", "~> 13.0"
27
27
  spec.add_development_dependency "rspec", "~> 3.0"
28
- spec.add_development_dependency "pry"
29
- spec.add_development_dependency "pry-byebug"
28
+ spec.add_development_dependency "appraisal"
30
29
 
31
- spec.add_dependency "rails", ">= 5.2", "<= 6.0"
30
+ spec.add_dependency "activemodel", "> 5.2", "< 7.2"
32
31
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'bundler/setup'
2
2
  require 'nested_record'
3
- require 'pry'
4
3
 
5
4
  Dir[File.join(__dir__, 'support/**/*.rb')].each { |f| require f }
6
5
 
@@ -53,7 +53,7 @@ module TestModel
53
53
  include NestedRecord::Macro
54
54
 
55
55
  def read_attribute(attr)
56
- attribute(attr)
56
+ attribute(attr.to_s)
57
57
  end
58
58
 
59
59
  class_eval(&block) if block
@@ -64,9 +64,19 @@ module TestModel
64
64
  module Erase
65
65
  def erase_test_consts
66
66
  Array(@test_consts).reverse_each do |klass|
67
- ActiveSupport::Dependencies.remove_constant(klass.name)
67
+ remove_constant(klass.name)
68
+ end
69
+ ActiveSupport::Dependencies.clear unless zeitwerk?
70
+ end
71
+
72
+ def remove_constant(klass_name)
73
+ if ActiveSupport::Dependencies.respond_to?(:remove_constant)
74
+ ActiveSupport::Dependencies.remove_constant(klass_name)
75
+ else
76
+ base, _, object = klass_name.to_s.rpartition('::')
77
+ base = base.empty? ? Object : NestedRecord.constantize(base)
78
+ base.send :remove_const, object
68
79
  end
69
- ActiveSupport::Dependencies.clear
70
80
  end
71
81
 
72
82
  def test_const_dig_name!(name)
@@ -85,5 +95,9 @@ module TestModel
85
95
  end
86
96
  [namespace, name]
87
97
  end
98
+
99
+ def zeitwerk?
100
+ ActiveSupport::VERSION::MAJOR >= 7
101
+ end
88
102
  end
89
103
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nested_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Kochnev
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-31 00:00:00.000000000 Z
11
+ date: 2023-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
19
+ version: '2'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '2.0'
26
+ version: '2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: pry
56
+ name: appraisal
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,57 +67,53 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: pry-byebug
70
+ name: activemodel
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rails
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
73
+ - - ">"
88
74
  - !ruby/object:Gem::Version
89
75
  version: '5.2'
90
- - - "<="
76
+ - - "<"
91
77
  - !ruby/object:Gem::Version
92
- version: '6.0'
78
+ version: '7.2'
93
79
  type: :runtime
94
80
  prerelease: false
95
81
  version_requirements: !ruby/object:Gem::Requirement
96
82
  requirements:
97
- - - ">="
83
+ - - ">"
98
84
  - !ruby/object:Gem::Version
99
85
  version: '5.2'
100
- - - "<="
86
+ - - "<"
101
87
  - !ruby/object:Gem::Version
102
- version: '6.0'
103
- description:
88
+ version: '7.2'
89
+ description:
104
90
  email:
105
91
  - hashtable@yandex.ru
106
92
  executables: []
107
93
  extensions: []
108
94
  extra_rdoc_files: []
109
95
  files:
96
+ - ".github/workflows/rspec.yml"
110
97
  - ".gitignore"
111
98
  - ".rspec"
112
- - ".travis.yml"
99
+ - Appraisals
113
100
  - Gemfile
101
+ - Gemfile.lock
114
102
  - LICENSE.txt
115
103
  - README.md
116
104
  - Rakefile
117
105
  - bin/console
118
106
  - bin/setup
119
107
  - gemfiles/rails_5.2.gemfile
108
+ - gemfiles/rails_5.2.gemfile.lock
120
109
  - gemfiles/rails_6.0.gemfile
110
+ - gemfiles/rails_6.0.gemfile.lock
111
+ - gemfiles/rails_6.1.gemfile
112
+ - gemfiles/rails_6.1.gemfile.lock
113
+ - gemfiles/rails_7.0.gemfile
114
+ - gemfiles/rails_7.0.gemfile.lock
115
+ - gemfiles/rails_7.1.gemfile
116
+ - gemfiles/rails_7.1.gemfile.lock
121
117
  - lib/nested_record.rb
122
118
  - lib/nested_record/base.rb
123
119
  - lib/nested_record/collection.rb
@@ -150,7 +146,7 @@ homepage: https://github.com/marshall-lee/nested_record
150
146
  licenses:
151
147
  - MIT
152
148
  metadata: {}
153
- post_install_message:
149
+ post_install_message:
154
150
  rdoc_options: []
155
151
  require_paths:
156
152
  - lib
@@ -165,9 +161,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
161
  - !ruby/object:Gem::Version
166
162
  version: '0'
167
163
  requirements: []
168
- rubyforge_project:
169
- rubygems_version: 2.7.6
170
- signing_key:
164
+ rubygems_version: 3.4.20
165
+ signing_key:
171
166
  specification_version: 4
172
167
  summary: ActiveModel mapper for JSON fields
173
168
  test_files: []
data/.travis.yml DELETED
@@ -1,11 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.5
7
- - 2.6
8
- gemfile:
9
- - gemfiles/rails_5.2.gemfile
10
- - gemfiles/rails_6.0.gemfile
11
- before_install: gem install bundler -v 2.0.1