store_model 4.2.1 → 4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80b3d46c14f2f0952709d1c0bd2d4ea2a3455cbedbeeb428a48e42886ef59270
4
- data.tar.gz: 7f1b852caa46ca69e49e5f4a9ca58194b4bf2a9d63caa1dc295444b6913407b8
3
+ metadata.gz: c65c5b8e184e6b4f7c402a7a2a82df8228d2b55c7ad6352c3752ac988bc86943
4
+ data.tar.gz: f2f404a6330ded65170e6256adb71c109592c6187a85d221d6887c965eeb9a1c
5
5
  SHA512:
6
- metadata.gz: e895325edadf56ff398ae92f3968205efbc7e75f8ed5d1b06b2465224e223efef80ac366d968644030b9148550e88801cfad8908dd61348b31507ad4c793ae11
7
- data.tar.gz: 1766b1327befd59eefc5186220202edbea2478080f5546b5042e2d01feb1d4f536c3aba66b8b7c247c06811673d4f5430823d31b132965ba7b0fca34cb0e873e
6
+ metadata.gz: cf0146c740b94e5591d16794431120afc4c28dfb3477757571d4d77fb8833836fccdb94d5776f9199f92164ab36029def584d3a802ee186b531916d82c098e6b
7
+ data.tar.gz: ae1753153b834b2b02bfa2ec4afc767540833eea27f59e653c3dbf8435bba3c1810999fba5128d71ce97e38e31314bc5622c8a01eb3054e743acd337bfae1b09
data/README.md CHANGED
@@ -131,11 +131,13 @@ end
131
131
  * [Enums](./docs/enums.md)
132
132
  * [Nested models](./docs/nested_models.md)
133
133
  * [Unknown attributes](./docs/unknown_attributes.md)
134
+ * [Empty attributes](./docs/empty_attributes.md)
134
135
  3. [Array of stored models](./docs/array_of_stored_models.md)
135
- 4. [One of](./docs/one_of.md)
136
- 4. [Alternatives](./docs/alternatives.md)
137
- 5. [Defining custom types](./docs/defining_custom_types.md)
138
- 6. [Disabling Parent Tracking](./docs/enable_parent_assignment.md)
136
+ 4. [Hash of stored models](./docs/hash_of_stored_models.md)
137
+ 5. [One of](./docs/one_of.md)
138
+ 6. [Alternatives](./docs/alternatives.md)
139
+ 7. [Defining custom types](./docs/defining_custom_types.md)
140
+ 8. [Disabling Parent Tracking](./docs/enable_parent_assignment.md)
139
141
 
140
142
  ## Credits
141
143
 
@@ -14,6 +14,7 @@ module ActiveModel
14
14
  # @param record [ApplicationRecord] object to validate
15
15
  # @param attribute [String] name of the validated attribute
16
16
  # @param value [Object] value of the validated attribute
17
+ # rubocop:disable Metrics/MethodLength
17
18
  def validate_each(record, attribute, value)
18
19
  if value.nil?
19
20
  record.errors.add(attribute, :blank)
@@ -25,8 +26,11 @@ module ActiveModel
25
26
  call_json_strategy(record, attribute, value)
26
27
  when :array, :polymorphic_array
27
28
  call_array_strategy(record, attribute, value)
29
+ when :hash, :polymorphic_hash
30
+ call_hash_strategy(record, attribute, value)
28
31
  end
29
32
  end
33
+ # rubocop:enable Metrics/MethodLength
30
34
 
31
35
  private
32
36
 
@@ -39,6 +43,11 @@ module ActiveModel
39
43
  array_strategy.call(attribute, record.errors, value) if any_invalid
40
44
  end
41
45
 
46
+ def call_hash_strategy(record, attribute, value)
47
+ invalid_values = value.select { |_k, v| v.invalid?(record.validation_context) }
48
+ hash_strategy.call(attribute, record.errors, invalid_values) if invalid_values.present?
49
+ end
50
+
42
51
  def strategy
43
52
  @strategy ||= StoreModel::CombineErrorsStrategies.configure(options)
44
53
  end
@@ -46,6 +55,10 @@ module ActiveModel
46
55
  def array_strategy
47
56
  @array_strategy ||= StoreModel::CombineErrorsStrategies.configure_array(options)
48
57
  end
58
+
59
+ def hash_strategy
60
+ @hash_strategy ||= StoreModel::CombineErrorsStrategies.configure_hash(options)
61
+ end
49
62
  end
50
63
  end
51
64
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoreModel
4
+ module CombineErrorsStrategies
5
+ # +MergeHashErrorStrategy+ copies errors from the StoreModel::Model to the parent
6
+ # record attribute errors with hash key prefixes.
7
+ class MergeHashErrorStrategy
8
+ # Merges errors on +attribute+ from the child model with parent errors.
9
+ #
10
+ # @param attribute [String] name of the validated attribute
11
+ # @param base_errors [ActiveModel::Errors] errors object of the parent record
12
+ # @param store_models [Hash] a hash of store_models that have been validated
13
+ def call(attribute, base_errors, store_models)
14
+ store_models.each do |key, store_model|
15
+ store_model.errors.full_messages.each do |full_message|
16
+ base_errors.add(attribute, :invalid, message: "[#{key}] #{full_message}")
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -3,6 +3,7 @@
3
3
  require "store_model/combine_errors_strategies/mark_invalid_error_strategy"
4
4
  require "store_model/combine_errors_strategies/merge_error_strategy"
5
5
  require "store_model/combine_errors_strategies/merge_array_error_strategy"
6
+ require "store_model/combine_errors_strategies/merge_hash_error_strategy"
6
7
 
7
8
  module StoreModel
8
9
  # Module with built-in strategies for combining errors.
@@ -37,6 +38,20 @@ module StoreModel
37
38
  )
38
39
  end
39
40
 
41
+ # Finds a hash strategy based on +options+ and global config.
42
+ #
43
+ # @param options [Hash]
44
+ #
45
+ # @return [Object] strategy
46
+ def configure_hash(options)
47
+ configured_strategy = options[:merge_hash_errors] || StoreModel.config.merge_hash_errors
48
+
49
+ get_configured_strategy(
50
+ configured_strategy,
51
+ StoreModel::CombineErrorsStrategies::MergeHashErrorStrategy
52
+ )
53
+ end
54
+
40
55
  def get_configured_strategy(configured_strategy, true_strategy_class)
41
56
  if configured_strategy.respond_to?(:call)
42
57
  configured_strategy
@@ -11,10 +11,18 @@ module StoreModel
11
11
  # @return [Boolean]
12
12
  attr_accessor :merge_array_errors
13
13
 
14
+ # Controls usage of MergeHashErrorStrategy
15
+ # @return [Boolean]
16
+ attr_accessor :merge_hash_errors
17
+
14
18
  # Controls if the result of `as_json` will contain the unknown attributes of the model
15
19
  # @return [Boolean]
16
20
  attr_accessor :serialize_unknown_attributes
17
21
 
22
+ # Controls if the result of `as_json` will contain the nulls attributes of the model
23
+ # @return [Boolean]
24
+ attr_accessor :serialize_empty_attributes
25
+
18
26
  # Controls if the result of `as_json` will serialize enum fields using `as_json`
19
27
  # @return [Boolean]
20
28
  attr_accessor :serialize_enums_using_as_json
@@ -28,6 +36,7 @@ module StoreModel
28
36
  @serialize_unknown_attributes = true
29
37
  @enable_parent_assignment = true
30
38
  @serialize_enums_using_as_json = true
39
+ @serialize_empty_attributes = true
31
40
  end
32
41
  end
33
42
  end
@@ -32,10 +32,18 @@ module StoreModel
32
32
  def from_values(values)
33
33
  to_array_type.cast_value(values)
34
34
  end
35
+
36
+ # Defines a discriminator attribute with a value
37
+ # @param discriminator [Symbol, String] attribute name (default: :type)
38
+ # @param type [Symbol, String] attribute type (default: :string)
39
+ # @param value [String] the discriminator value
40
+ def discriminator_attribute(discriminator = "type", value:, type: :string)
41
+ attribute discriminator, type, default: value
42
+ end
35
43
  end
36
44
 
37
45
  attr_accessor :parent
38
- attr_writer :serialize_unknown_attributes, :serialize_enums_using_as_json
46
+ attr_writer :serialize_unknown_attributes, :serialize_enums_using_as_json, :serialize_empty_attributes
39
47
 
40
48
  delegate :each_value, to: :attributes
41
49
 
@@ -45,7 +53,7 @@ module StoreModel
45
53
  # @param options [Hash]
46
54
  #
47
55
  # @return [Hash]
48
- def as_json(options = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
56
+ def as_json(options = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
49
57
  serialize_unknown_attributes = if options.key?(:serialize_unknown_attributes)
50
58
  options[:serialize_unknown_attributes]
51
59
  else
@@ -58,10 +66,20 @@ module StoreModel
58
66
  StoreModel.config.serialize_enums_using_as_json
59
67
  end
60
68
 
69
+ serialize_empty_attributes = if options.key?(:serialize_empty_attributes)
70
+ options[:serialize_empty_attributes]
71
+ else
72
+ StoreModel.config.serialize_empty_attributes
73
+ end
74
+
75
+ # If the model is nested, we need to ensure that the serialization
76
+
61
77
  result = @attributes.keys.each_with_object({}) do |key, values|
62
78
  attr = @attributes.fetch(key)
63
- assign_serialization_options(attr, serialize_unknown_attributes, serialize_enums_using_as_json)
64
- values[key] = serialized_attribute(attr)
79
+ assign_serialization_options(attr, serialize_unknown_attributes, serialize_enums_using_as_json,
80
+ serialize_empty_attributes)
81
+ serialized = serialized_attribute(attr)
82
+ values[key] = serialized if serialize_empty_attributes || !serialized.nil?
65
83
  end.with_indifferent_access
66
84
 
67
85
  result.merge!(unknown_attributes) if serialize_unknown_attributes
@@ -226,6 +244,23 @@ module StoreModel
226
244
  end
227
245
  end
228
246
 
247
+ # Returns the value of the `@serialize_empty_attributes` instance
248
+ # variable. The default value is the value of the globally configured
249
+ # `serialize_empty_attributes` option.
250
+ #
251
+ # This method is used to determine whether empty values should be serialized
252
+ # when the `as_json` method is called in nested StoreModel::Model
253
+ # objects.
254
+ #
255
+ # @return [Boolean]
256
+ def serialize_empty_attributes?
257
+ if @serialize_empty_attributes.nil?
258
+ StoreModel.config.serialize_empty_attributes || true
259
+ else
260
+ @serialize_empty_attributes
261
+ end
262
+ end
263
+
229
264
  private
230
265
 
231
266
  def attribute?(attribute)
@@ -263,16 +298,18 @@ module StoreModel
263
298
 
264
299
  array.as_json(
265
300
  serialize_unknown_attributes: array.first.serialize_unknown_attributes?,
266
- serialize_enums_using_as_json: array.first.serialize_enums_using_as_json?
301
+ serialize_enums_using_as_json: array.first.serialize_enums_using_as_json?,
302
+ serialize_empty_attributes: array.first.serialize_empty_attributes?
267
303
  )
268
304
  end
269
305
 
270
- def assign_serialization_options(attr, serialize_unknown_attributes, serialize_enums_using_as_json)
306
+ def assign_serialization_options(attr, serialize_unknown_attributes, serialize_enums_using_as_json, serialize_empty_attributes) # rubocop:disable Layout/LineLength
271
307
  return unless Array(attr.value).all? { |value| value.is_a?(StoreModel::Model) }
272
308
 
273
309
  Array(attr.value).each do |value|
274
310
  value.serialize_unknown_attributes = serialize_unknown_attributes
275
311
  value.serialize_enums_using_as_json = serialize_enums_using_as_json
312
+ value.serialize_empty_attributes = serialize_empty_attributes
276
313
  end
277
314
  end
278
315
  end
@@ -14,5 +14,11 @@ module StoreModel
14
14
  def to_array_type
15
15
  Types::Many.new(self)
16
16
  end
17
+
18
+ # Converts StoreModel::Model to Types::Hash
19
+ # @return [Types::Hash]
20
+ def to_hash_type
21
+ Types::Hash.new(self)
22
+ end
17
23
  end
18
24
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+
5
+ module StoreModel
6
+ module Types
7
+ # Implements ActiveModel::Type::Value type for handling a hash of
8
+ # StoreModel::Model
9
+ class Hash < HashBase
10
+ # Initializes type for model class
11
+ #
12
+ # @param model_klass [StoreModel::Model] model class to handle
13
+ #
14
+ # @return [StoreModel::Types::Hash]
15
+ def initialize(model_klass)
16
+ @model_klass = model_klass
17
+ super()
18
+ end
19
+
20
+ # Returns type
21
+ #
22
+ # @return [Symbol]
23
+ def type
24
+ :hash
25
+ end
26
+
27
+ protected
28
+
29
+ def ensure_model_class(hash)
30
+ return {} unless hash.is_a?(::Hash)
31
+
32
+ hash.transform_values do |object|
33
+ next object if object.nil?
34
+
35
+ object.is_a?(@model_klass) ? object : cast_model_type_value(object)
36
+ end
37
+ end
38
+
39
+ def cast_model_type_value(value)
40
+ model_klass_type.cast_value(value)
41
+ end
42
+
43
+ def model_klass_type
44
+ @model_klass_type ||= @model_klass.to_type
45
+ end
46
+
47
+ def raise_cast_error(value)
48
+ raise StoreModel::Types::CastError,
49
+ "failed casting #{value.inspect}, only String or Hash instances are allowed"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+
5
+ module StoreModel
6
+ module Types
7
+ # Implements type for handling a hash of StoreModel::Model
8
+ class HashBase < Base
9
+ # Casts +value+ from DB or user to Hash of StoreModel::Model instances
10
+ #
11
+ # @param value [Object] a value to cast
12
+ #
13
+ # @return Hash
14
+ def cast_value(value)
15
+ case value
16
+ when String then decode_and_initialize(value)
17
+ when ::Hash then ensure_model_class(value)
18
+ when nil then value
19
+ else
20
+ raise_cast_error(value)
21
+ end
22
+ end
23
+
24
+ # Casts a value from the ruby type to a type that the database knows how
25
+ # to understand.
26
+ #
27
+ # @param value [Object] value to serialize
28
+ #
29
+ # @return [String] serialized value
30
+ def serialize(value)
31
+ return super unless value.is_a?(::Hash)
32
+ if value.empty? || value.values.any? { |v| !v.is_a?(StoreModel::Model) }
33
+ return ActiveSupport::JSON.encode(value)
34
+ end
35
+
36
+ ActiveSupport::JSON.encode(
37
+ value,
38
+ serialize_unknown_attributes: value.values.first.serialize_unknown_attributes?,
39
+ serialize_enums_using_as_json: value.values.first.serialize_enums_using_as_json?
40
+ )
41
+ end
42
+
43
+ # Determines whether the mutable value has been modified since it was read
44
+ #
45
+ # @param raw_old_value [Object] old value
46
+ # @param new_value [Object] new value
47
+ #
48
+ # @return [Boolean]
49
+ def changed_in_place?(raw_old_value, new_value)
50
+ cast_value(raw_old_value) != new_value
51
+ end
52
+
53
+ protected
54
+
55
+ def ensure_model_class(_hash)
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def cast_model_type_value(_value)
60
+ raise NotImplementedError
61
+ end
62
+
63
+ private
64
+
65
+ # rubocop:disable Style/RescueModifier
66
+ def decode_and_initialize(hash_value)
67
+ decoded = ActiveSupport::JSON.decode(hash_value) rescue {}
68
+ return {} unless decoded.is_a?(::Hash)
69
+
70
+ decoded.transform_values do |attributes|
71
+ next nil if attributes.nil?
72
+
73
+ cast_model_type_value(attributes)
74
+ end
75
+ end
76
+ # rubocop:enable Style/RescueModifier
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+
5
+ module StoreModel
6
+ module Types
7
+ # Implements ActiveModel::Type::Value type for handling a hash of
8
+ # polymorphic StoreModel::Model
9
+ class HashPolymorphic < HashBase
10
+ include PolymorphicHelper
11
+
12
+ # Initializes type for model class
13
+ #
14
+ # @param model_wrapper [Proc] proc that returns class based on value
15
+ #
16
+ # @return [StoreModel::Types::HashPolymorphic]
17
+ def initialize(model_wrapper)
18
+ @model_wrapper = model_wrapper
19
+ super()
20
+ end
21
+
22
+ # Returns type
23
+ #
24
+ # @return [Symbol]
25
+ def type
26
+ :polymorphic_hash
27
+ end
28
+
29
+ protected
30
+
31
+ def ensure_model_class(hash)
32
+ return {} unless hash.is_a?(::Hash)
33
+
34
+ hash.transform_values do |object|
35
+ next object if object.nil?
36
+ next object if implements_model?(object.class)
37
+
38
+ cast_model_type_value(object)
39
+ end
40
+ end
41
+
42
+ def cast_model_type_value(value)
43
+ model_klass = @model_wrapper.call(value)
44
+
45
+ raise_extract_wrapper_error(model_klass) unless implements_model?(model_klass)
46
+
47
+ model_klass.to_type.cast_value(value)
48
+ end
49
+
50
+ def raise_cast_error(value)
51
+ raise StoreModel::Types::CastError,
52
+ "failed casting #{value.inspect}, only String, " \
53
+ "Hash or instances which implement StoreModel::Model are allowed"
54
+ end
55
+ end
56
+ end
57
+ end
@@ -56,7 +56,7 @@ module StoreModel
56
56
  ActiveSupport::JSON.encode(value,
57
57
  serialize_unknown_attributes: value.serialize_unknown_attributes?,
58
58
  serialize_enums_using_as_json: value.serialize_enums_using_as_json?)
59
- when Hash
59
+ when ::Hash
60
60
  ActiveSupport::JSON.encode(value)
61
61
  else
62
62
  super
@@ -75,7 +75,7 @@ module StoreModel
75
75
  when String
76
76
  payload = ActiveSupport::JSON.decode(value) rescue {}
77
77
  model_instance(deserialize_by_types(payload))
78
- when Hash
78
+ when ::Hash
79
79
  model_instance(deserialize_by_types(value))
80
80
  when nil
81
81
  nil
@@ -18,6 +18,10 @@ module StoreModel
18
18
  def to_array_type
19
19
  Types::ManyPolymorphic.new(@block)
20
20
  end
21
+
22
+ def to_hash_type
23
+ Types::HashPolymorphic.new(@block)
24
+ end
21
25
  end
22
26
  end
23
27
  end
@@ -38,7 +38,7 @@ module StoreModel
38
38
  elsif value.class.ancestors.include?(StoreModel::Model)
39
39
  value
40
40
  elsif value.respond_to?(:to_h) # Hash itself included
41
- extract_model_klass(value).new(value.to_h)
41
+ extract_model_klass(value).to_type.cast_value(value.to_h)
42
42
  else
43
43
  raise_cast_error(value)
44
44
  end
@@ -53,7 +53,7 @@ module StoreModel
53
53
  #
54
54
  # @return [String] serialized value
55
55
  def serialize(value)
56
- return super unless value.is_a?(Hash) || implements_model?(value.class)
56
+ return super unless value.is_a?(::Hash) || implements_model?(value.class)
57
57
 
58
58
  if value.is_a?(StoreModel::Model)
59
59
  ActiveSupport::JSON.encode(
@@ -11,6 +11,10 @@ require "store_model/types/many_base"
11
11
  require "store_model/types/many"
12
12
  require "store_model/types/many_polymorphic"
13
13
 
14
+ require "store_model/types/hash_base"
15
+ require "store_model/types/hash"
16
+ require "store_model/types/hash_polymorphic"
17
+
14
18
  require "store_model/types/enum_type"
15
19
 
16
20
  require "store_model/types/one_of"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreModel # :nodoc:
4
- VERSION = "4.2.1"
4
+ VERSION = "4.3.0"
5
5
  end
data/lib/store_model.rb CHANGED
@@ -15,5 +15,61 @@ module StoreModel # :nodoc:
15
15
  def one_of(&block)
16
16
  Types::OneOf.new(&block)
17
17
  end
18
+
19
+ # Creates a union type for polymorphic attributes
20
+ # @param klasses [Array<Class>] array of classes that can be used
21
+ # @param discriminator [String, Symbol] the attribute key to check for type (default: 'type')
22
+ # @return instance [Types::OneOf]
23
+ def union(klasses, discriminator: "type")
24
+ discriminators_and_classes = klasses.map do |cls|
25
+ [cls._default_attributes[discriminator]&.value, cls]
26
+ end
27
+
28
+ validate_missing_discriminators!(discriminator, discriminators_and_classes)
29
+ validate_duplicate_discriminators!(discriminators_and_classes)
30
+
31
+ union_one_of(discriminator, Hash[discriminators_and_classes])
32
+ end
33
+
34
+ private
35
+
36
+ def validate_missing_discriminators!(discriminator, discriminators_and_classes)
37
+ missing_discriminator_classes = discriminators_and_classes.select do |(discriminator_value, _cls)|
38
+ discriminator_value.blank?
39
+ end.map(&:last)
40
+
41
+ return if missing_discriminator_classes.empty?
42
+
43
+ raise "discriminator_attribute not set for #{discriminator} on #{missing_discriminator_classes.join(', ')}"
44
+ end
45
+
46
+ def validate_duplicate_discriminators!(discriminators_and_classes)
47
+ discriminator_counts = discriminators_and_classes.group_by(&:first)
48
+ duplicates = discriminator_counts.select { |_discriminator_value, pairs| pairs.length > 1 }
49
+
50
+ return if duplicates.empty?
51
+
52
+ duplicate_messages = duplicates.map do |discriminator_value, pairs|
53
+ classes = pairs.map(&:last).map(&:name).join(", ")
54
+ "#{discriminator_value.inspect} => [#{classes}]"
55
+ end
56
+
57
+ raise "Duplicate discriminator values found: #{duplicate_messages.join('; ')}"
58
+ end
59
+
60
+ def union_one_of(discriminator, class_map)
61
+ Types::OneOf.new do |attributes|
62
+ next nil unless attributes
63
+
64
+ discriminator_value = attributes.with_indifferent_access[discriminator]
65
+
66
+ raise ArgumentError, "Missing discriminator attribute #{discriminator} for union" if discriminator_value.blank?
67
+
68
+ cls = class_map[discriminator_value]
69
+ raise ArgumentError, "Unknown discriminator value for union: #{discriminator_value}" if cls.blank?
70
+
71
+ cls
72
+ end
73
+ end
18
74
  end
19
75
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: store_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.1
4
+ version: 4.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DmitryTsepelev
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-02-01 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activerecord
@@ -82,6 +81,7 @@ files:
82
81
  - lib/store_model/combine_errors_strategies/mark_invalid_error_strategy.rb
83
82
  - lib/store_model/combine_errors_strategies/merge_array_error_strategy.rb
84
83
  - lib/store_model/combine_errors_strategies/merge_error_strategy.rb
84
+ - lib/store_model/combine_errors_strategies/merge_hash_error_strategy.rb
85
85
  - lib/store_model/configuration.rb
86
86
  - lib/store_model/enum.rb
87
87
  - lib/store_model/ext/active_model/attributes.rb
@@ -94,6 +94,9 @@ files:
94
94
  - lib/store_model/types.rb
95
95
  - lib/store_model/types/base.rb
96
96
  - lib/store_model/types/enum_type.rb
97
+ - lib/store_model/types/hash.rb
98
+ - lib/store_model/types/hash_base.rb
99
+ - lib/store_model/types/hash_polymorphic.rb
97
100
  - lib/store_model/types/many.rb
98
101
  - lib/store_model/types/many_base.rb
99
102
  - lib/store_model/types/many_polymorphic.rb
@@ -108,7 +111,6 @@ homepage: https://github.com/DmitryTsepelev/store_model
108
111
  licenses:
109
112
  - MIT
110
113
  metadata: {}
111
- post_install_message:
112
114
  rdoc_options: []
113
115
  require_paths:
114
116
  - lib
@@ -123,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
125
  - !ruby/object:Gem::Version
124
126
  version: '0'
125
127
  requirements: []
126
- rubygems_version: 3.5.11
127
- signing_key:
128
+ rubygems_version: 3.6.7
128
129
  specification_version: 4
129
130
  summary: Gem for working with JSON-backed attributes as ActiveRecord models
130
131
  test_files: []