active_record_compose 0.1.0 → 0.1.2

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: f87118b489cd061b4912c625ec2b9bdc91ad4b024e69cd6a6c45ab9c884018f3
4
- data.tar.gz: 22eec41668831a5f97d5935502d4c4d61de723b78dd2f70d2dca2bbfb4d9fa52
3
+ metadata.gz: e22d1fa89d36de73833897c0bead3b9b0405fe357aad4565d873741648a3664e
4
+ data.tar.gz: d9c543c3c0048428d22a0f591bd6086c6da991a9768d6836f84b212126ff9cab
5
5
  SHA512:
6
- metadata.gz: 180d9e45c2e18dc362d0169a22040759614882e09254c4fc8ad80ead07302c280446cab288c5042f81f33d339ab00b114d888536f691ab817063dc5dc6765cc0
7
- data.tar.gz: a4ba3164829709bbdbb38f0232b555ef210b6ce0783348317c430ffb9d1931f9b9b48bec3f28fefe757ee9ce6f9c8b3dcfb3a53ec557650eab4d6e7a8870e13f
6
+ metadata.gz: 85dcb6f44d523a9cd85905dca4bfb5557594b123872d61015fab442e4a92957bd05835f43f2113fbb44b5771e3f4c4b8856a4bbb97d3a6ef39f4a35803a5457b
7
+ data.tar.gz: 31f30d80ebbf8ab7f752330f25e5cc8777f2e4801a3648c71c5e36e1d6717e46530540b555c7efe96cb0e2f144d93206d7f181b6aedcfab79a140b1e37ce86cd
data/.rubocop.yml CHANGED
@@ -3,6 +3,9 @@ AllCops:
3
3
  NewCops: enable
4
4
  SuggestExtensions: false
5
5
 
6
+ Gemspec/DevelopmentDependencies:
7
+ Enabled: false
8
+
6
9
  Style/Documentation:
7
10
  Enabled: false
8
11
 
@@ -29,3 +32,6 @@ Layout/LineLength:
29
32
 
30
33
  Metrics/BlockLength:
31
34
  Enabled: false
35
+
36
+ Naming/MemoizedInstanceVariableName:
37
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2023-07-29
3
+ ## [0.1.2] - 2024-01-09
4
+
5
+ - fix and add doc.
6
+ - add development dependency
7
+ - avoid instance variable name conflict (`@models` to `@__models`)
8
+ - add #empty?, #clear to InnerModelCollection
9
+ - add #delete to InnerModelCollection
10
+
11
+ ## [0.1.1] - 2024-01-08
12
+
13
+ - fix 0.1.0 release date.
14
+ - add doc.
15
+ - Make it easier for application developers to work with `#models`
16
+
17
+ ## [0.1.0] - 2024-01-06
4
18
 
5
19
  - Initial release
data/README.md CHANGED
@@ -199,7 +199,7 @@ It provides a macro description that expresses access to the attributes of the A
199
199
 
200
200
  ```ruby
201
201
  class AccountRegistration < ActiveRecordCompose::Model
202
- def initialize(account)
202
+ def initialize(account, attributes = {})
203
203
  @account = account
204
204
  super(attributes)
205
205
  models.push(account)
@@ -1,6 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordCompose
4
+ # = Delegate \Attribute
5
+ #
6
+ # It provides a macro description that expresses access to the attributes of the AR model through delegation.
7
+ #
8
+ # class AccountRegistration < ActiveRecordCompose::Model
9
+ # def initialize(account, attributes = {})
10
+ # @account = account
11
+ # super(attributes)
12
+ # models.push(account)
13
+ # end
14
+ #
15
+ # attribute :original_attribute, :string, default: 'qux'
16
+ #
17
+ # # like a `delegate :name, :name=, to: :account`
18
+ # delegate_attribute :name, to: :account
19
+ #
20
+ # private
21
+ #
22
+ # attr_reader :account
23
+ # end
24
+ #
25
+ # account = Account.new
26
+ # account.name = 'foo'
27
+ #
28
+ # registration = AccountRegistration.new(account)
29
+ # registration.name #=> 'foo' # delegate to account#name
30
+ #
31
+ # registration.name = 'bar' # delegate to account#name=
32
+ # account.name #=> 'bar'
33
+ #
34
+ # # Attributes defined in delegate_attribute will be included in the original `#attributes`.
35
+ # registration.attributes #=> { 'original_attribute' => 'qux', 'name' => 'bar' }
36
+ #
4
37
  module DelegateAttribute
5
38
  extend ActiveSupport::Concern
6
39
 
@@ -1,40 +1,66 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/core_ext/object'
4
+
3
5
  module ActiveRecordCompose
4
6
  class InnerModel
5
- def initialize(inner_model, context: :save)
6
- @inner_model = inner_model
7
+ # @param model [Object] the model instance.
8
+ # @param context [Symbol] :save or :destroy
9
+ def initialize(model, context: :save)
10
+ @model = model
7
11
  @context = context
8
12
  end
9
13
 
10
- delegate :errors, to: :inner_model
14
+ delegate :errors, to: :model
11
15
 
16
+ # @return [Symbol] :save or :destroy
12
17
  def context
13
- @context.respond_to?(:call) ? @context.call(inner_model) : @context
18
+ ret = @context.respond_to?(:call) ? @context.call(model) : @context
19
+ ret.presence_in(%i[save destroy]) || :save
14
20
  end
15
21
 
22
+ # @return [InnerModel] self
16
23
  def save!
17
24
  case context
18
25
  when :destroy
19
- inner_model.destroy!
26
+ model.destroy!
20
27
  else
21
- inner_model.save!
28
+ model.save!
22
29
  end
23
30
  end
24
31
 
32
+ # @return [Boolean]
25
33
  def invalid?
26
34
  case context
27
35
  when :destroy
28
36
  false
29
37
  else
30
- inner_model.invalid?
38
+ model.invalid?
31
39
  end
32
40
  end
33
41
 
42
+ # @return [Boolean]
34
43
  def valid? = !invalid?
35
44
 
45
+ # Returns true if equivalent.
46
+ #
47
+ # @return [Object] other
48
+ def ==(other)
49
+ return false unless self.class == other.class
50
+ return false unless __raw_model == other.__raw_model
51
+ return false unless context == other.context
52
+
53
+ true
54
+ end
55
+
56
+ # Returns a model instance of raw, but it should
57
+ # be noted that application developers are not expected to use this interface.
58
+ #
59
+ # @return [Object] raw model instance
60
+ def __raw_model = model
61
+
36
62
  private
37
63
 
38
- attr_reader :inner_model
64
+ attr_reader :model
39
65
  end
40
66
  end
@@ -6,36 +6,86 @@ module ActiveRecordCompose
6
6
  class InnerModelCollection
7
7
  include Enumerable
8
8
 
9
- def initialize
10
- @inner_models = []
11
- end
12
-
9
+ # Enumerates model objects.
10
+ #
11
+ # @yieldparam [Object] the model instance
12
+ # @return [Enumerator] when not block given.
13
+ # @return [InnerModelCollection] self
13
14
  def each
14
15
  return enum_for(:each) unless block_given?
15
16
 
16
- inner_models.each { yield _1 }
17
+ models.each { yield _1.__raw_model }
18
+ self
19
+ end
20
+
21
+ # Appends model to collection.
22
+ #
23
+ # @param model [Object] the model instance
24
+ # @return [InnerModelCollection] self
25
+ def <<(model)
26
+ models << wrap(model, context: :save)
27
+ self
28
+ end
29
+
30
+ # Appends model to collection.
31
+ #
32
+ # @param model [Object] the model instance
33
+ # @param context [Symbol] :save or :destroy
34
+ # @return [InnerModelCollection] self
35
+ def push(model, context: :save)
36
+ models << wrap(model, context:)
17
37
  self
18
38
  end
19
39
 
20
- def <<(inner_model)
21
- inner_models << wrap(inner_model, context: :save)
40
+ # Returns true if the element exists.
41
+ #
42
+ # @return [Boolean] Returns true if the element exists
43
+ def empty? = models.empty?
44
+
45
+ # Set to empty.
46
+ #
47
+ # @return [InnerModelCollection] self
48
+ def clear
49
+ models.clear
22
50
  self
23
51
  end
24
52
 
25
- def push(inner_model, context: :save)
26
- inner_models << wrap(inner_model, context:)
53
+ # Removes the specified model from the collection.
54
+ # Returns nil if the deletion fails, self if it succeeds.
55
+ #
56
+ # @param model [Object] the model instance
57
+ # @param context [Symbol] :save or :destroy
58
+ # @return [InnerModelCollection] Successful deletion
59
+ # @return [nil] If deletion fails
60
+ def delete(model, context: :save)
61
+ wrapped = wrap(model, context:)
62
+ return nil unless models.delete(wrapped)
63
+
64
+ self
65
+ end
66
+
67
+ # Enumerates model objects, but it should be noted that
68
+ # application developers are not expected to use this interface.
69
+ #
70
+ # @yieldparam [InnerModel] rawpped model instance.
71
+ # @return [Enumerator] when not block given.
72
+ # @return [InnerModelCollection] self
73
+ def __each_by_wrapped
74
+ return enum_for(:__each_by_wrapped) unless block_given?
75
+
76
+ models.each { yield _1 }
27
77
  self
28
78
  end
29
79
 
30
80
  private
31
81
 
32
- attr_reader :inner_models
82
+ def models = @models ||= []
33
83
 
34
- def wrap(inner_model, context:)
35
- if inner_model.is_a?(ActiveRecordCompose::InnerModel)
36
- inner_model
84
+ def wrap(model, context:)
85
+ if model.is_a?(ActiveRecordCompose::InnerModel)
86
+ model
37
87
  else
38
- ActiveRecordCompose::InnerModel.new(inner_model, context:)
88
+ ActiveRecordCompose::InnerModel.new(model, context:)
39
89
  end
40
90
  end
41
91
  end
@@ -32,6 +32,31 @@ module ActiveRecordCompose
32
32
 
33
33
  def save! = save || raise(error_class_on_save_error.new('Failed to save the model.', self))
34
34
 
35
+ # Behavior is same to `#save`, but `before_create` and `after_create` hooks fires.
36
+ #
37
+ # class ComposedModel < ActiveRecordCompose::Model
38
+ # # ...
39
+ #
40
+ # before_save { puts 'before_save called!' }
41
+ # before_create { puts 'before_create called!' }
42
+ # before_update { puts 'before_update called!' }
43
+ # after_save { puts 'after_save called!' }
44
+ # after_create { puts 'after_create called!' }
45
+ # after_update { puts 'after_update called!' }
46
+ # end
47
+ #
48
+ # model = ComposedModel.new
49
+ #
50
+ # model.save
51
+ # # before_save called!
52
+ # # after_save called!
53
+ #
54
+ # model.create
55
+ # # before_save called!
56
+ # # before_create called!
57
+ # # after_create called!
58
+ # # after_save called!
59
+ #
35
60
  def create(attributes = {})
36
61
  assign_attributes(attributes)
37
62
  return false if invalid?
@@ -39,10 +64,37 @@ module ActiveRecordCompose
39
64
  save_in_transaction { run_callbacks(:save) { run_callbacks(:create) { save_models } } }
40
65
  end
41
66
 
67
+ # Behavior is same to `#create`, but raises an exception prematurely on failure.
68
+ #
42
69
  def create!(attributes = {})
43
70
  create(attributes) || raise(error_class_on_save_error.new('Failed to create the model.', self))
44
71
  end
45
72
 
73
+ # Behavior is same to `#save`, but `before_update` and `after_update` hooks fires.
74
+ #
75
+ # class ComposedModel < ActiveRecordCompose::Model
76
+ # # ...
77
+ #
78
+ # before_save { puts 'before_save called!' }
79
+ # before_create { puts 'before_create called!' }
80
+ # before_update { puts 'before_update called!' }
81
+ # after_save { puts 'after_save called!' }
82
+ # after_create { puts 'after_create called!' }
83
+ # after_update { puts 'after_update called!' }
84
+ # end
85
+ #
86
+ # model = ComposedModel.new
87
+ #
88
+ # model.save
89
+ # # before_save called!
90
+ # # after_save called!
91
+ #
92
+ # model.update
93
+ # # before_save called!
94
+ # # before_update called!
95
+ # # after_update called!
96
+ # # after_save called!
97
+ #
46
98
  def update(attributes = {})
47
99
  assign_attributes(attributes)
48
100
  return false if invalid?
@@ -50,15 +102,19 @@ module ActiveRecordCompose
50
102
  save_in_transaction { run_callbacks(:save) { run_callbacks(:update) { save_models } } }
51
103
  end
52
104
 
105
+ # Behavior is same to `#update`, but raises an exception prematurely on failure.
106
+ #
53
107
  def update!(attributes = {})
54
108
  update(attributes) || raise(error_class_on_save_error.new('Failed to update the model.', self))
55
109
  end
56
110
 
57
111
  private
58
112
 
59
- def models = @models ||= ActiveRecordCompose::InnerModelCollection.new
113
+ def models = @__models ||= ActiveRecordCompose::InnerModelCollection.new
60
114
 
61
- def validate_models = models.select { _1.invalid? }.each { errors.merge!(_1) }
115
+ def wrapped_models = models.__each_by_wrapped
116
+
117
+ def validate_models = wrapped_models.select { _1.invalid? }.each { errors.merge!(_1) }
62
118
 
63
119
  def save_in_transaction
64
120
  run_callbacks(:commit) do
@@ -74,6 +130,6 @@ module ActiveRecordCompose
74
130
  end.present?
75
131
  end
76
132
 
77
- def save_models = models.all? { _1.save! }
133
+ def save_models = wrapped_models.all? { _1.save! }
78
134
  end
79
135
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordCompose
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.2'
5
5
  end
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.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - hamajyotan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-06 00:00:00.000000000 Z
11
+ date: 2024-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '6.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  description: activemodel form object pattern
28
42
  email:
29
43
  - hamajyotan@gmail.com
@@ -49,6 +63,10 @@ homepage: https://github.com/active_record_compose
49
63
  licenses:
50
64
  - MIT
51
65
  metadata:
66
+ homepage_uri: https://github.com/active_record_compose
67
+ source_code_uri: https://github.com/active_record_compose
68
+ changelog_uri: https://github.com/active_record_compose/blob/main/CHANGELOG.md
69
+ documentation_uri: https://www.rubydoc.info/gems/active_record_compose/0.1.2
52
70
  rubygems_mfa_required: 'true'
53
71
  post_install_message:
54
72
  rdoc_options: []