active_record_compose 0.11.3 → 0.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 154ee35310ede836e5d89ecd703efadbbc2b7fba0a6229797e9b38b5288eba47
4
- data.tar.gz: 42c565c5093680ae089bac356541561dc83ff73759941f268af22365338126db
3
+ metadata.gz: 954ce34124a1c8e83a45710e104dd965c407afb5ba296b74d4a4e5f9d13d971a
4
+ data.tar.gz: c1bb35ef5458a804f243b886c037aff3794822477ea2aaf5a57bfb12a4001477
5
5
  SHA512:
6
- metadata.gz: a5a9f0a46534ea0dbb3423275a68b521543c67074d8fcd7c637d46f86fcc42f93ac6792b2d80f83b6a0aae367f6dd461e6fb4d0e06730f40da3aefd0751393e9
7
- data.tar.gz: c5bb3aaae6e84b23bc264ce5a1ad7b369f248c1fb1f1494b2753a1a82681ecc3df8c5f10a6b68854cda319c65da59e69435dd1c4381f44ff585d81a2400b5bac
6
+ metadata.gz: 2e7f81f304cec10420cb4f405ad8ad7f93f3811c7f43bf9952c05dbca84e651bbf0c851e648349d7e93986cf67cb177110785588a47c8951718f4d271cf53944
7
+ data.tar.gz: 8ac490bd69c0d51e6e89f1f198a4e052eccbeedcf1b234edfa8c9635819fe336bbe10b6b64b6b55907524543ad34eb9343892b00f54f2737a65c45c120456afa
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.12.0] - 2025-08-21
4
+
5
+ - Omits default arguments for `#update` and `#update!`. It's to align I/F with ActiveRecord.
6
+ (https://github.com/hamajyotan/active_record_compose/pull/25)
7
+ - `#update(attributes = {})` to `#update(attributes)`
8
+ - `#update!(attributes = {})` to `#update!(attributes)`
9
+ - Omitted Specify instance variables in the `:to` option of `delegate_attribute`.
10
+ (https://github.com/hamajyotan/active_record_compose/pull/29)
11
+ - Omitted `#destroy` and `#touch` from `ActiveRecordCompose::Model`.
12
+ These were unintentionally provided by the `ActiveRecord::Transactions` module. The but in fact did not work correctly.
13
+ (https://github.com/hamajyotan/active_record_compose/pull/27)
14
+
3
15
  ## [0.11.3] - 2025-07-13
4
16
 
5
17
  - refactor: Aggregation attribute module.
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecordCompose
4
+ module Attributes
5
+ # @private
6
+ class AttributePredicate
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+
11
+ def call
12
+ case value
13
+ when true then true
14
+ when false, nil then false
15
+ else
16
+ if value.respond_to?(:zero?)
17
+ !value.zero?
18
+ else
19
+ value.present?
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :value
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "attribute_predicate"
4
+
3
5
  module ActiveRecordCompose
4
6
  module Attributes
5
7
  # @private
@@ -17,7 +19,11 @@ module ActiveRecordCompose
17
19
 
18
20
  def define_delegated_attribute(klass)
19
21
  klass.delegate(reader, writer, to:, allow_nil:)
20
- klass.define_attribute_methods(attribute)
22
+ klass.module_eval <<~RUBY, __FILE__, __LINE__ + 1
23
+ def #{reader}?
24
+ ActiveRecordCompose::Attributes::AttributePredicate.new(#{reader}).call
25
+ end
26
+ RUBY
21
27
  end
22
28
 
23
29
  # @return [String] The attribute name as string
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "attribute_predicate"
4
+
3
5
  module ActiveRecordCompose
4
6
  module Attributes
5
7
  # @private
@@ -50,19 +52,10 @@ module ActiveRecordCompose
50
52
 
51
53
  private
52
54
 
53
- def attribute?(attr_name)
54
- value = public_send(attr_name)
55
+ def attribute?(attr_name) = query?(public_send(attr_name))
55
56
 
56
- case value
57
- when true then true
58
- when false, nil then false
59
- else
60
- if value.respond_to?(:zero?)
61
- !value.zero?
62
- else
63
- value.present?
64
- end
65
- end
57
+ def query?(value)
58
+ ActiveRecordCompose::Attributes::AttributePredicate.new(value).call
66
59
  end
67
60
  end
68
61
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "attributes/attribute_predicate"
3
4
  require_relative "attributes/delegation"
4
5
  require_relative "attributes/querying"
5
6
 
@@ -62,9 +63,6 @@ module ActiveRecordCompose
62
63
  end
63
64
 
64
65
  module ClassMethods
65
- ALLOW_NIL_DEFAULT = Object.new.freeze # steep:ignore
66
- private_constant :ALLOW_NIL_DEFAULT
67
-
68
66
  # Defines the reader and writer for the specified attribute.
69
67
  #
70
68
  # @example
@@ -97,34 +95,10 @@ module ActiveRecordCompose
97
95
  # registration.attributes
98
96
  # # => { "original_attribute" => "qux", "name" => "bar" }
99
97
  #
100
- def delegate_attribute(*attributes, to:, allow_nil: ALLOW_NIL_DEFAULT) # steep:ignore
101
- # steep:ignore:start
98
+ def delegate_attribute(*attributes, to:, allow_nil: false)
102
99
  if to.start_with?("@")
103
- suggested_reader_name = to.to_s.sub(/^@+/, "")
104
- suggested_method =
105
- if to.start_with?("@@")
106
- "def #{suggested_reader_name} = #{to}"
107
- else
108
- "attr_reader :#{suggested_reader_name}"
109
- end
110
-
111
- message = <<~MSG
112
- Direct use of instance or class variables in `to:` will be removed in the next minor version.
113
- Please define a reader method (private is fine) and refer to it by name instead.
114
-
115
- For example,
116
- delegate_attribute #{attributes.map { ":#{_1}" }.join(", ")}, to: :#{to}#{", allow_nil: #{allow_nil}" if allow_nil != ALLOW_NIL_DEFAULT}
117
-
118
- Instead of the above, use the following
119
- delegate_attribute #{attributes.map { ":#{_1}" }.join(", ")}, to: :#{suggested_reader_name}#{", allow_nil: #{allow_nil}" if allow_nil != ALLOW_NIL_DEFAULT}
120
- private
121
- #{suggested_method}
122
-
123
- MSG
124
- (ActiveRecord.respond_to?(:deprecator) ? ActiveRecord.deprecator : ActiveSupport::Deprecation).warn(message)
100
+ raise ArgumentError, "Instance variables cannot be specified in delegate to. (#{to})"
125
101
  end
126
- allow_nil = false if allow_nil == ALLOW_NIL_DEFAULT
127
- # steep:ignore:end
128
102
 
129
103
  delegations = attributes.map { Delegation.new(attribute: _1, to:, allow_nil:) }
130
104
  delegations.each { _1.define_delegated_attribute(self) }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "validations"
4
-
5
3
  module ActiveRecordCompose
6
4
  # @private
7
5
  #
@@ -23,8 +21,6 @@ module ActiveRecordCompose
23
21
  include ActiveModel::Validations::Callbacks
24
22
 
25
23
  included do
26
- include ActiveRecordCompose::Validations
27
-
28
24
  define_model_callbacks :save
29
25
  define_model_callbacks :create
30
26
  define_model_callbacks :update
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "attributes"
4
- require_relative "callbacks"
5
4
  require_relative "composed_collection"
6
5
  require_relative "persistence"
6
+ require_relative "transaction_support"
7
+ require_relative "validations"
7
8
 
8
9
  module ActiveRecordCompose
9
10
  # This is the core class of {ActiveRecordCompose}.
@@ -83,7 +84,8 @@ module ActiveRecordCompose
83
84
 
84
85
  include ActiveRecordCompose::Attributes
85
86
  include ActiveRecordCompose::Persistence
86
- include ActiveRecordCompose::Callbacks
87
+ include ActiveRecordCompose::Validations
88
+ include ActiveRecordCompose::TransactionSupport
87
89
 
88
90
  begin
89
91
  # @group Model Core
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "callbacks"
3
4
  require_relative "composed_collection"
4
- require_relative "transaction_support"
5
5
 
6
6
  module ActiveRecordCompose
7
7
  using ComposedCollection::PackagePrivate
@@ -9,7 +9,7 @@ module ActiveRecordCompose
9
9
  # @private
10
10
  module Persistence
11
11
  extend ActiveSupport::Concern
12
- include ActiveRecordCompose::TransactionSupport
12
+ include ActiveRecordCompose::Callbacks
13
13
 
14
14
  # Save the models that exist in models.
15
15
  # Returns false if any of the targets fail, true if all succeed.
@@ -24,11 +24,9 @@ module ActiveRecordCompose
24
24
  #
25
25
  # @return [Boolean] returns true on success, false on failure.
26
26
  def save(**options)
27
- with_transaction_returning_status do
28
- with_callbacks { save_models(**options, bang: false) }
29
- rescue ActiveRecord::RecordInvalid
30
- false
31
- end
27
+ with_callbacks { save_models(**options, bang: false) }
28
+ rescue ActiveRecord::RecordInvalid
29
+ false
32
30
  end
33
31
 
34
32
  # Save the models that exist in models.
@@ -43,28 +41,22 @@ module ActiveRecordCompose
43
41
  # If the contexts differ, we recommend separating them into different model definitions.
44
42
  #
45
43
  def save!(**options)
46
- with_transaction_returning_status do
47
- with_callbacks { save_models(**options, bang: true) }
48
- end || raise_on_save_error
44
+ with_callbacks { save_models(**options, bang: true) } || raise_on_save_error
49
45
  end
50
46
 
51
47
  # Assign attributes and save.
52
48
  #
53
49
  # @return [Boolean] returns true on success, false on failure.
54
- def update(attributes = {})
55
- with_transaction_returning_status do
56
- assign_attributes(attributes)
57
- save
58
- end
50
+ def update(attributes)
51
+ assign_attributes(attributes)
52
+ save
59
53
  end
60
54
 
61
55
  # Behavior is same to `#update`, but raises an exception prematurely on failure.
62
56
  #
63
- def update!(attributes = {})
64
- with_transaction_returning_status do
65
- assign_attributes(attributes)
66
- save!
67
- end
57
+ def update!(attributes)
58
+ assign_attributes(attributes)
59
+ save!
68
60
  end
69
61
 
70
62
  private
@@ -6,18 +6,19 @@ module ActiveRecordCompose
6
6
  extend ActiveSupport::Concern
7
7
  include ActiveRecord::Transactions
8
8
 
9
- module ClassMethods
10
- def lease_connection
11
- if ar_class.respond_to?(:lease_connection)
12
- ar_class.lease_connection # steep:ignore
13
- else
14
- ar_class.connection
15
- end
16
- end
9
+ included do
10
+ # ActiveRecord::Transactions is defined so that methods such as save,
11
+ # destroy and touch are wrapped with_transaction_returning_status.
12
+ # However, ActiveRecordCompose::Model does not support destroy and touch, and
13
+ # we want to keep these operations as undefined behavior, so we remove the definition here.
14
+ undef_method :destroy, :touch
15
+ end
17
16
 
18
- def connection = ar_class.connection
17
+ module ClassMethods
18
+ delegate :with_connection, :lease_connection, to: :ar_class
19
19
 
20
- def with_connection(&) = ar_class.with_connection(&) # steep:ignore
20
+ # In ActiveRecord, it is soft deprecated.
21
+ delegate :connection, to: :ar_class
21
22
 
22
23
  def composite_primary_key? = false # steep:ignore
23
24
 
@@ -8,6 +8,7 @@ module ActiveRecordCompose
8
8
  # @private
9
9
  module Validations
10
10
  extend ActiveSupport::Concern
11
+ include ActiveModel::Validations::Callbacks
11
12
 
12
13
  included do
13
14
  validate :validate_models
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordCompose
4
- VERSION = "0.11.3"
4
+ VERSION = "0.12.0"
5
5
  end
@@ -15,6 +15,16 @@ module ActiveRecordCompose
15
15
  def delegated_attributes=: (Array[Delegation]) -> untyped
16
16
  end
17
17
 
18
+ class AttributePredicate
19
+ def initialize: (untyped value) -> void
20
+ def call: -> bool
21
+
22
+ @value: untyped
23
+
24
+ private
25
+ attr_reader value: untyped
26
+ end
27
+
18
28
  class Delegation
19
29
  def initialize: (attribute: String, to: Symbol, ?allow_nil: bool) -> void
20
30
  def attribute: () -> Symbol
@@ -40,6 +50,7 @@ module ActiveRecordCompose
40
50
 
41
51
  private
42
52
  def attribute?: (attribute_name) -> untyped
53
+ def query?: (untyped value) -> bool
43
54
  end
44
55
  end
45
56
 
@@ -87,6 +98,7 @@ module ActiveRecordCompose
87
98
  end
88
99
 
89
100
  module TransactionSupport
101
+ extend ActiveSupport::Concern
90
102
  include ActiveRecord::Transactions
91
103
 
92
104
  def id: -> untyped
@@ -108,8 +120,8 @@ module ActiveRecordCompose
108
120
 
109
121
  def save: (**untyped options) -> bool
110
122
  def save!: (**untyped options) -> untyped
111
- def update: (?Hash[attribute_name, untyped]) -> bool
112
- def update!: (?Hash[attribute_name, untyped]) -> untyped
123
+ def update: (Hash[attribute_name, untyped]) -> bool
124
+ def update!: (Hash[attribute_name, untyped]) -> untyped
113
125
 
114
126
  private
115
127
  def models: -> ComposedCollection
@@ -79,14 +79,10 @@ module ActiveRecordCompose
79
79
  def initialize: (?Hash[attribute_name, untyped]) -> void
80
80
  def save: (**untyped options) -> bool
81
81
  def save!: (**untyped options) -> untyped
82
- def update: (?Hash[attribute_name, untyped]) -> bool
83
- def update!: (?Hash[attribute_name, untyped]) -> untyped
84
- def id: -> untyped
82
+ def update: (Hash[attribute_name, untyped]) -> bool
83
+ def update!: (Hash[attribute_name, untyped]) -> untyped
85
84
 
86
85
  private
87
86
  def models: -> ComposedCollection
88
- def save_models: (bang: bool, **untyped options) -> bool
89
- def raise_on_save_error: -> bot
90
- def raise_on_save_error_message: -> String
91
87
  end
92
88
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_compose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.3
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - hamajyotan
@@ -45,6 +45,7 @@ files:
45
45
  - README.md
46
46
  - lib/active_record_compose.rb
47
47
  - lib/active_record_compose/attributes.rb
48
+ - lib/active_record_compose/attributes/attribute_predicate.rb
48
49
  - lib/active_record_compose/attributes/delegation.rb
49
50
  - lib/active_record_compose/attributes/querying.rb
50
51
  - lib/active_record_compose/callbacks.rb