active_record_compose 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +5 -5
- data/lib/active_record_compose/inner_model.rb +19 -67
- data/lib/active_record_compose/inner_model_collection.rb +15 -12
- data/lib/active_record_compose/version.rb +1 -1
- data/lib/active_record_compose.rb +0 -2
- data/sig/active_record_compose.rbs +7 -13
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a3112ceb79671ca112aa5dde2222e10a0bd4daed96f82ebaa641746165d8991
|
4
|
+
data.tar.gz: e021f41a5e3334b0e91f170712c011679023a384bbfe17c3df2a97858747323e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56cb8c6d615cbefb58fc774e96caa9add4cb72a8ca34188ce2d713f6b4f32ef75b7df4f273da2bd6966d08c1a8f1aadbeef838f3c5b436e5f1122efb7af5a961
|
7
|
+
data.tar.gz: 0aec57e80f57d0c3d1bf1d45e4cb39c3cebcae47c53a35b630817de592bd3893604ff58563eed2c6b23f4199d2f27bc39804a1a9e6fe20bbdb809defaae30e28
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.5.0] - 2024-10-09
|
4
|
+
|
5
|
+
- remove `:context` option. use `:destroy` option instead.
|
6
|
+
- remove `:destroy` option from `InnerModelCollection#destroy`.
|
7
|
+
|
8
|
+
## [0.4.1] - 2024-09-20
|
9
|
+
|
10
|
+
- Omitted optional argument for `InnerModelCollection#destroy`.
|
11
|
+
`InnerModel` equivalence is always performed based on the instance of the inner `model`.
|
12
|
+
Since there are no use cases that depend on the original behavior.
|
13
|
+
|
3
14
|
## [0.4.0] - 2024-09-15
|
4
15
|
|
5
16
|
- support `destrpy` option. and deprecated `context` option.
|
data/README.md
CHANGED
@@ -31,7 +31,7 @@ A callback is useful to define some processing before or after a save in a parti
|
|
31
31
|
However, if a callback is written directly in the AR model, it is necessary to consider the case where the model is updated in other contexts.
|
32
32
|
In particular, if you frequently create with test data, previously unnecessary processing will be called at every point of creation.
|
33
33
|
In addition to cost, the more complicated the callbacks you write, the more difficult it will be to create even a single test data.
|
34
|
-
If the callbacks are written in a class that inherits from `
|
34
|
+
If the callbacks are written in a class that inherits from `ActiveRecordCompose::Model`, the AR model itself will not be polluted, and the context can be limited.
|
35
35
|
|
36
36
|
```ruby
|
37
37
|
class AccountRegistration < ActiveRecordCompose::Model
|
@@ -70,7 +70,7 @@ Validates are basically fired in all cases where the model is manipulated. To av
|
|
70
70
|
and so on to work only in specific cases. This allows you to create context-sensitive validations for the same model operation.
|
71
71
|
However, this is the first step in making the model more and more complex. You will have to go around with `update(context: :foo)`
|
72
72
|
In some cases, you may have to go around with the context option, such as `update(context: :foo)` everywhere.
|
73
|
-
By writing validates in a class that extends `
|
73
|
+
By writing validates in a class that extends `ActiveRecordCompose::Model`, you can define context-specific validation without polluting the AR model itself.
|
74
74
|
|
75
75
|
```ruby
|
76
76
|
class AccountRegistration < ActiveRecordCompose::Model
|
@@ -116,7 +116,7 @@ account_registration.valid? #=> false
|
|
116
116
|
|
117
117
|
In an AR model, you can add, for example, `autosave: true` or `accepts_nested_attributes_for` to an association to update the related models at the same time.
|
118
118
|
There are ways to update related models at the same time. The operation is safe because it is transactional.
|
119
|
-
`
|
119
|
+
`ActiveRecordCompose::Model` has an internal array called models. By adding an AR object to this models array
|
120
120
|
By adding an AR object to the models, the object stored in the models provides an atomic update operation via #save.
|
121
121
|
|
122
122
|
```ruby
|
@@ -167,12 +167,12 @@ class AccountResignation < ActiveRecordCompose::Model
|
|
167
167
|
models.push(profile, destroy: true)
|
168
168
|
end
|
169
169
|
|
170
|
-
attr_reader :account, :profile
|
171
|
-
|
172
170
|
before_save :set_resigned_at
|
173
171
|
|
174
172
|
private
|
175
173
|
|
174
|
+
attr_reader :account, :profile
|
175
|
+
|
176
176
|
def set_resigned_at
|
177
177
|
account.resigned_at = Time.zone.now
|
178
178
|
end
|
@@ -7,65 +7,32 @@ module ActiveRecordCompose
|
|
7
7
|
# @param model [Object] the model instance.
|
8
8
|
# @param destroy [Boolean] given true, destroy model.
|
9
9
|
# @param destroy [Proc] when proc returning true, destroy model.
|
10
|
-
def initialize(
|
11
|
-
@owner = owner
|
10
|
+
def initialize(model, destroy: false)
|
12
11
|
@model = model
|
13
|
-
@
|
14
|
-
if context
|
15
|
-
c = context
|
16
|
-
|
17
|
-
if c.is_a?(Proc)
|
18
|
-
# @type var c: ((^() -> (context)) | (^(_ARLike) -> (context)))
|
19
|
-
if c.arity == 0
|
20
|
-
deprecator.warn(
|
21
|
-
'`:context` will be removed in 0.5.0. Use `:destroy` option instead. ' \
|
22
|
-
'for example, `models.push(model, context: -> { foo? ? :destroy : :save })` ' \
|
23
|
-
'is replaced by `models.push(model, destroy: -> { foo? })`.',
|
24
|
-
)
|
25
|
-
|
26
|
-
# @type var c: ^() -> (context)
|
27
|
-
-> { c.call == :destroy }
|
28
|
-
else
|
29
|
-
deprecator.warn(
|
30
|
-
'`:context` will be removed in 0.5.0. Use `:destroy` option instead. ' \
|
31
|
-
'for example, `models.push(model, context: ->(m) { m.bar? ? :destroy : :save })` ' \
|
32
|
-
'is replaced by `models.push(model, destroy: ->(m) { m.bar? })`.',
|
33
|
-
)
|
34
|
-
|
35
|
-
# @type var c: ^(_ARLike) -> (context)
|
36
|
-
->(model) { c.call(model) == :destroy }
|
37
|
-
end
|
38
|
-
elsif %i[save destroy].include?(c)
|
39
|
-
deprecator.warn(
|
40
|
-
'`:context` will be removed in 0.5.0. Use `:destroy` option instead. ' \
|
41
|
-
"for example, `models.push(model, context: #{c.inspect})` " \
|
42
|
-
"is replaced by `models.push(model, destroy: #{(c == :destroy).inspect})`.",
|
43
|
-
)
|
44
|
-
|
45
|
-
# @type var c: (:save | :destory)
|
46
|
-
c == :destroy
|
47
|
-
else
|
48
|
-
c
|
49
|
-
end
|
50
|
-
else
|
51
|
-
destroy
|
52
|
-
end
|
12
|
+
@destroy_context_type = destroy
|
53
13
|
end
|
54
14
|
|
55
15
|
delegate :errors, to: :model
|
56
16
|
|
17
|
+
# Determines whether to save or delete the target object.
|
18
|
+
# Depends on the `destroy` value of the InnerModel object initialization option.
|
19
|
+
#
|
20
|
+
# On the other hand, there are values `mark_for_destruction` and `marked_for_destruction?` in ActiveRecord.
|
21
|
+
# However, these values are not substituted here.
|
22
|
+
# These values only work if the `autosave` option is enabled for the parent model,
|
23
|
+
# and are not appropriate for other cases.
|
24
|
+
#
|
25
|
+
# @return [Boolean] returns true on destroy, false on save.
|
57
26
|
def destroy_context?
|
58
|
-
d =
|
27
|
+
d = destroy_context_type
|
59
28
|
if d.is_a?(Proc)
|
60
29
|
if d.arity == 0
|
61
|
-
# @type var d: ^() ->
|
62
|
-
d.call
|
30
|
+
# @type var d: ^() -> bool
|
31
|
+
!!d.call
|
63
32
|
else
|
64
|
-
# @type var d: ^(_ARLike) ->
|
65
|
-
d.call(model)
|
33
|
+
# @type var d: ^(_ARLike) -> bool
|
34
|
+
!!d.call(model)
|
66
35
|
end
|
67
|
-
elsif d.is_a?(Symbol)
|
68
|
-
owner.send(d)
|
69
36
|
else
|
70
37
|
!!d
|
71
38
|
end
|
@@ -94,35 +61,20 @@ module ActiveRecordCompose
|
|
94
61
|
# @return [Boolean]
|
95
62
|
def ==(other)
|
96
63
|
return false unless self.class == other.class
|
97
|
-
return false unless __raw_model == other.__raw_model
|
98
|
-
return false unless __destroy == other.__destroy
|
64
|
+
return false unless __raw_model == other.__raw_model # steep:ignore
|
99
65
|
|
100
66
|
true
|
101
67
|
end
|
102
68
|
|
69
|
+
# @private
|
103
70
|
# Returns a model instance of raw, but it should
|
104
71
|
# be noted that application developers are not expected to use this interface.
|
105
72
|
#
|
106
73
|
# @return [Object] raw model instance
|
107
74
|
def __raw_model = model
|
108
75
|
|
109
|
-
# Returns a model instance of raw, but it should
|
110
|
-
# be noted that application developers are not expected to use this interface.
|
111
|
-
#
|
112
|
-
# @return [Boolean] raw destroy instance
|
113
|
-
# @return [Proc] raw destroy instance
|
114
|
-
def __destroy = destroy
|
115
|
-
|
116
76
|
private
|
117
77
|
|
118
|
-
attr_reader :
|
119
|
-
|
120
|
-
def deprecator
|
121
|
-
if ActiveRecord.respond_to?(:deprecator)
|
122
|
-
ActiveRecord.deprecator
|
123
|
-
else # for rails 7.0.x or lower
|
124
|
-
ActiveSupport::Deprecation
|
125
|
-
end
|
126
|
-
end
|
78
|
+
attr_reader :model, :destroy_context_type
|
127
79
|
end
|
128
80
|
end
|
@@ -8,6 +8,7 @@ module ActiveRecordCompose
|
|
8
8
|
|
9
9
|
def initialize(owner)
|
10
10
|
@owner = owner
|
11
|
+
@models = []
|
11
12
|
end
|
12
13
|
|
13
14
|
# Enumerates model objects.
|
@@ -35,10 +36,11 @@ module ActiveRecordCompose
|
|
35
36
|
#
|
36
37
|
# @param model [Object] the model instance
|
37
38
|
# @param destroy [Boolean] given true, destroy model.
|
38
|
-
# @param
|
39
|
+
# @param destroy [Proc] when proc returning true, destroy model.
|
40
|
+
# @param destroy [Symbol] applies boolean value of result of sending a message to `owner` to evaluation.
|
39
41
|
# @return [self] returns itself.
|
40
|
-
def push(model, destroy: false
|
41
|
-
models << wrap(model, destroy
|
42
|
+
def push(model, destroy: false)
|
43
|
+
models << wrap(model, destroy:)
|
42
44
|
self
|
43
45
|
end
|
44
46
|
|
@@ -59,17 +61,16 @@ module ActiveRecordCompose
|
|
59
61
|
# Returns nil if the deletion fails, self if it succeeds.
|
60
62
|
#
|
61
63
|
# @param model [Object] the model instance
|
62
|
-
# @param destroy [Boolean] given true, destroy model.
|
63
|
-
# @param context [Symbol] :save or :destroy
|
64
64
|
# @return [self] Successful deletion
|
65
65
|
# @return [nil] If deletion fails
|
66
|
-
def delete(model
|
67
|
-
wrapped = wrap(model
|
66
|
+
def delete(model)
|
67
|
+
wrapped = wrap(model)
|
68
68
|
return nil unless models.delete(wrapped)
|
69
69
|
|
70
70
|
self
|
71
71
|
end
|
72
72
|
|
73
|
+
# @private
|
73
74
|
# Enumerates model objects, but it should be noted that
|
74
75
|
# application developers are not expected to use this interface.
|
75
76
|
#
|
@@ -85,17 +86,19 @@ module ActiveRecordCompose
|
|
85
86
|
|
86
87
|
private
|
87
88
|
|
88
|
-
attr_reader :owner
|
89
|
-
|
90
|
-
def models = @models ||= []
|
89
|
+
attr_reader :owner, :models
|
91
90
|
|
92
|
-
def wrap(model, destroy
|
91
|
+
def wrap(model, destroy: false)
|
93
92
|
if model.is_a?(ActiveRecordCompose::InnerModel) # steep:ignore
|
94
93
|
# @type var model: ActiveRecordCompose::InnerModel
|
95
94
|
model
|
96
95
|
else
|
96
|
+
if destroy.is_a?(Symbol)
|
97
|
+
method = destroy
|
98
|
+
destroy = -> { owner.__send__(method) }
|
99
|
+
end
|
97
100
|
# @type var model: ActiveRecordCompose::_ARLike
|
98
|
-
ActiveRecordCompose::InnerModel.new(
|
101
|
+
ActiveRecordCompose::InnerModel.new(model, destroy:)
|
99
102
|
end
|
100
103
|
end
|
101
104
|
end
|
@@ -3,8 +3,6 @@
|
|
3
3
|
require 'active_record'
|
4
4
|
|
5
5
|
require_relative 'active_record_compose/version'
|
6
|
-
require_relative 'active_record_compose/inner_model'
|
7
|
-
require_relative 'active_record_compose/inner_model_collection'
|
8
6
|
require_relative 'active_record_compose/model'
|
9
7
|
|
10
8
|
module ActiveRecordCompose
|
@@ -15,8 +15,7 @@ module ActiveRecordCompose
|
|
15
15
|
end
|
16
16
|
|
17
17
|
type attribute_name = (String | Symbol)
|
18
|
-
type
|
19
|
-
type context_proc = ((^() -> context) | (^(_ARLike) -> context))
|
18
|
+
type destroy_context_type = (bool | Symbol | (^() -> boolish) | (^(_ARLike) -> boolish))
|
20
19
|
|
21
20
|
module DelegateAttribute
|
22
21
|
extend ActiveSupport::Concern
|
@@ -30,28 +29,23 @@ module ActiveRecordCompose
|
|
30
29
|
|
31
30
|
class InnerModelCollection
|
32
31
|
include ::Enumerable[_ARLike]
|
33
|
-
@owner: Model
|
34
|
-
@models: Array[InnerModel]
|
35
32
|
|
36
33
|
def initialize: (Model) -> void
|
37
34
|
def each: () { (_ARLike) -> void } -> InnerModelCollection | () -> Enumerator[_ARLike, self]
|
38
35
|
def <<: (_ARLike) -> self
|
39
|
-
def push: (_ARLike, ?destroy:
|
36
|
+
def push: (_ARLike, ?destroy: destroy_context_type) -> self
|
40
37
|
def empty?: -> bool
|
41
38
|
def clear: -> self
|
42
|
-
def delete: (_ARLike | InnerModel
|
39
|
+
def delete: (_ARLike | InnerModel) -> InnerModelCollection?
|
43
40
|
|
44
41
|
private
|
45
42
|
attr_reader owner: Model
|
46
|
-
|
47
|
-
def wrap: (_ARLike | InnerModel, destroy:
|
43
|
+
attr_reader models: Array[InnerModel]
|
44
|
+
def wrap: (_ARLike | InnerModel, ?destroy: destroy_context_type) -> InnerModel
|
48
45
|
end
|
49
46
|
|
50
47
|
class InnerModel
|
51
|
-
|
52
|
-
@context: (context | context_proc)
|
53
|
-
|
54
|
-
def initialize: (Model, _ARLike, ?destroy: bool, ?context: (nil | context | context_proc)) -> void
|
48
|
+
def initialize: (_ARLike, ?destroy: destroy_context_type) -> void
|
55
49
|
def destroy_context?: -> bool
|
56
50
|
def save: -> bool
|
57
51
|
def save!: -> untyped
|
@@ -60,8 +54,8 @@ module ActiveRecordCompose
|
|
60
54
|
def ==: (untyped) -> bool
|
61
55
|
|
62
56
|
private
|
63
|
-
attr_reader owner: Model
|
64
57
|
attr_reader model: _ARLike
|
58
|
+
attr_reader destroy_context_type: destroy_context_type
|
65
59
|
end
|
66
60
|
|
67
61
|
class Model
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_compose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hamajyotan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-09
|
11
|
+
date: 2024-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -52,7 +52,7 @@ metadata:
|
|
52
52
|
homepage_uri: https://github.com/hamajyotan/active_record_compose
|
53
53
|
source_code_uri: https://github.com/hamajyotan/active_record_compose
|
54
54
|
changelog_uri: https://github.com/hamajyotan/active_record_compose/blob/main/CHANGELOG.md
|
55
|
-
documentation_uri: https://www.rubydoc.info/gems/active_record_compose/0.
|
55
|
+
documentation_uri: https://www.rubydoc.info/gems/active_record_compose/0.5.0
|
56
56
|
rubygems_mfa_required: 'true'
|
57
57
|
post_install_message:
|
58
58
|
rdoc_options: []
|
@@ -69,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: '0'
|
71
71
|
requirements: []
|
72
|
-
rubygems_version: 3.5.
|
72
|
+
rubygems_version: 3.5.11
|
73
73
|
signing_key:
|
74
74
|
specification_version: 4
|
75
75
|
summary: activemodel form object pattern
|