store_model 0.5.1 → 0.5.2

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: 3e08694a9eb910d42bd5c9a1f6f2b23746494aad264315e8b7c1de863148fb72
4
- data.tar.gz: e5fd75336b9c22c9b75a5de967e2019e54bef594ff7d526fa56dc0ccdac9237e
3
+ metadata.gz: ddf27da9ed2536f94b6363448b5198695e8c15113b94e4e160a10980a8709532
4
+ data.tar.gz: f508d45e6a30c2634a89fdbd8204643aa597f1c879958314bb0c83b4fe3fd27f
5
5
  SHA512:
6
- metadata.gz: b229005093bd41076d547b093880954c060623ce2906b782e7e675ae5416b7f27b5876172d16d137d4be33a521449a196f30f170b946df174e4b0732ebad16a1
7
- data.tar.gz: 5add920a20c6b2f56121fe360c70f878de2ea194f7a0e5347168a5d9e4f72a7eed660d4966b8b4b0476c57fe90e99425da9b219abc59f7b487a91b21679bbddf
6
+ metadata.gz: fccc4d5dee04b782758ada583a9a840b585805786869912a1d82e50a8df5dcfb682afc97b1dffe45961640a095395f1da4f3b27c0e94afeddc59de5a218c658e
7
+ data.tar.gz: ad0e9c6f11accc117b45a9647d525ad9a19acc47704d22261129e46ec648461b77585e3d4ff828ad3a00b46bf3b6968789af97a2ac8e1789d8c965c9da034c98
data/README.md CHANGED
@@ -89,6 +89,7 @@ product.save
89
89
  * [Unknown attributes](./docs/unknown_attributes.md)
90
90
  3. [Array of stored models](./docs/array_of_stored_models.md)
91
91
  4. [Alternatives](./docs/alternatives.md)
92
+ 5. [Defining custom types](./docs/defining_custom_types.md)
92
93
 
93
94
  ## License
94
95
 
@@ -5,7 +5,15 @@ require "store_model/combine_errors_strategies"
5
5
 
6
6
  module ActiveModel
7
7
  module Validations
8
+ # +StoreModelValidator+ is a subclass of ActiveModel::EachValidator for
9
+ # checking StoreModel::Model attributes.
8
10
  class StoreModelValidator < ActiveModel::EachValidator
11
+ # Validates _json_ attribute using the configured strategy or
12
+ # invalidates _array_ attribute when at least one element is invalid.
13
+ #
14
+ # @param record [ApplicationRecord] object to validate
15
+ # @param attribute [String] name of the validated attribute
16
+ # @param value [Object] value of the validated attribute
9
17
  def validate_each(record, attribute, value)
10
18
  if value.nil?
11
19
  record.errors.add(attribute, :blank)
@@ -4,7 +4,7 @@ require "store_model/model"
4
4
  require "store_model/configuration"
5
5
  require "active_model/validations/store_model_validator"
6
6
 
7
- module StoreModel
7
+ module StoreModel # :nodoc:
8
8
  class << self
9
9
  def config
10
10
  @config ||= Configuration.new
@@ -4,10 +4,15 @@ require "store_model/combine_errors_strategies/mark_invalid_error_strategy"
4
4
  require "store_model/combine_errors_strategies/merge_error_strategy"
5
5
 
6
6
  module StoreModel
7
+ # Module with built-in strategies for combining errors.
7
8
  module CombineErrorsStrategies
8
9
  module_function
9
10
 
10
- # Finds a strategy based on options and global config
11
+ # Finds a strategy based on +options+ and global config.
12
+ #
13
+ # @param options [Hash]
14
+ #
15
+ # @return [Object] strategy
11
16
  def configure(options)
12
17
  configured_strategy = options[:merge_errors] || StoreModel.config.merge_errors
13
18
 
@@ -2,7 +2,14 @@
2
2
 
3
3
  module StoreModel
4
4
  module CombineErrorsStrategies
5
+ # +MarkInvalidErrorStrategy+ marks attribute invalid in the parent record.
5
6
  class MarkInvalidErrorStrategy
7
+ # Invalidates +attribute+ in the parent record.
8
+ #
9
+ # @param attribute [String] name of the validated attribute
10
+ # @param base_errors [ActiveModel::Errors] errors object of the parent record
11
+ # @param _store_model_errors [ActiveModel::Errors] errors object of the
12
+ # StoreModel::Model attribute
6
13
  def call(attribute, base_errors, _store_model_errors)
7
14
  base_errors.add(attribute, :invalid)
8
15
  end
@@ -2,7 +2,15 @@
2
2
 
3
3
  module StoreModel
4
4
  module CombineErrorsStrategies
5
+ # +MergeErrorStrategy+ copies errors from the StoreModel::Model to the parent
6
+ # record (for Rails < 6.1) or marks the attribute invalid (for Rails >= 6.1).
5
7
  class MergeErrorStrategy
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_model_errors [ActiveModel::Errors] errors object of the StoreModel::Model
13
+ # attribute
6
14
  def call(_attribute, base_errors, store_model_errors)
7
15
  if Rails::VERSION::MAJOR < 6 || Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR.zero?
8
16
  base_errors.copy!(store_model_errors)
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreModel
4
- # StoreModel configuration:
5
- #
6
- # - `merge_errors` - set up to `true` to merge errors or specify your
7
- # own strategy
8
- #
4
+ # StoreModel configuration.
9
5
  class Configuration
6
+ # Controls usage of MergeErrorStrategy
7
+ # @return [Boolean]
10
8
  attr_accessor :merge_errors
11
9
  end
12
10
  end
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreModel
4
+ # Allows defining Rails-like enums
4
5
  module Enum
6
+ # Defines new enum
7
+ #
8
+ # @param name [String] name of the enum to define
9
+ # @param values [Object]
10
+ # @param kwargs [Object]
5
11
  def enum(name, values = nil, **kwargs)
6
12
  values ||= kwargs[:in] || kwargs
7
13
 
@@ -6,8 +6,9 @@ require "store_model/type_builders"
6
6
  require "store_model/nested_attributes"
7
7
 
8
8
  module StoreModel
9
+ # When included into class configures it to handle JSON column
9
10
  module Model
10
- def self.included(base)
11
+ def self.included(base) # :nodoc:
11
12
  base.include ActiveModel::Model
12
13
  base.include ActiveModel::Attributes
13
14
  base.include StoreModel::NestedAttributes
@@ -16,21 +17,37 @@ module StoreModel
16
17
  base.extend StoreModel::TypeBuilders
17
18
  end
18
19
 
20
+ # Returns a hash representing the model. Some configuration can be
21
+ # passed through +options+.
22
+ #
23
+ # @param options [Hash]
24
+ #
25
+ # @return [Hash]
19
26
  def as_json(options = {})
20
27
  attributes.with_indifferent_access.as_json(options)
21
28
  end
22
29
 
30
+ # Compares two StoreModel::Model instances
31
+ #
32
+ # @param other [StoreModel::Model]
33
+ #
34
+ # @return [Boolean]
23
35
  def ==(other)
24
36
  return super unless other.is_a?(self.class)
25
37
 
26
- attributes.all? { |name, value| value == other.send(name) }
38
+ attributes.all? { |name, value| value == other.attributes[name] }
27
39
  end
28
40
 
29
- # Allows to call :presence validation on the association itself
41
+ # Allows to call :presence validation on the association itself.
42
+ #
43
+ # @return [Boolean]
30
44
  def blank?
31
45
  attributes.values.all?(&:blank?)
32
46
  end
33
47
 
48
+ # String representation of the object.
49
+ #
50
+ # @return [String]
34
51
  def inspect
35
52
  attribute_string = attributes.map { |name, value| "#{name}: #{value || 'nil'}" }.join(", ")
36
53
  "#<#{self.class.name} #{attribute_string}>"
@@ -38,17 +55,31 @@ module StoreModel
38
55
 
39
56
  delegate :attribute_types, to: :class
40
57
 
58
+ # Returns the type of the attribute with the given name
59
+ #
60
+ # @param attr_name [String] name of the attribute
61
+ #
62
+ # @return [ActiveModel::Type::Value]
41
63
  def type_for_attribute(attr_name)
42
64
  attr_name = attr_name.to_s
43
65
  attribute_types[attr_name]
44
66
  end
45
67
 
68
+ # Checks if the attribute with a given name is defined
69
+ #
70
+ # @param attr_name [String] name of the attribute
71
+ #
72
+ # @return [Boolean]
46
73
  # rubocop:disable Naming/PredicateName
47
74
  def has_attribute?(attr_name)
48
75
  attribute_types.key?(attr_name.to_s)
49
76
  end
50
77
  # rubocop:enable Naming/PredicateName
51
78
 
79
+ # Contains a hash of attributes which are not defined but exist in the
80
+ # underlying JSON data
81
+ #
82
+ # @return [Hash]
52
83
  def unknown_attributes
53
84
  @unknown_attributes ||= {}
54
85
  end
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreModel
4
+ # Contains methods for working with nested StoreModel::Model attributes.
4
5
  module NestedAttributes
5
- def self.included(base)
6
+ def self.included(base) # :nodoc:
6
7
  base.extend ClassMethods
7
8
  end
8
9
 
9
- module ClassMethods
10
+ module ClassMethods # :nodoc:
11
+ # Enables handling of nested StoreModel::Model attributes
12
+ #
13
+ # @param associations [Array] list of associations to define attributes
10
14
  def accepts_nested_attributes_for(*associations)
11
15
  associations.each do |association|
12
16
  case attribute_types[association.to_s]
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreModel
4
+ # Contains methods for converting StoreModel::Model to ActiveModel::Type::Value.
4
5
  module TypeBuilders
6
+ # Converts StoreModel::Model to Types::JsonType
7
+ # @return [Types::JsonType]
5
8
  def to_type
6
9
  Types::JsonType.new(self)
7
10
  end
8
11
 
12
+ # Converts StoreModel::Model to Types::ArrayType
13
+ # @return [Types::ArrayType]
9
14
  def to_array_type
10
15
  Types::ArrayType.new(self)
11
16
  end
@@ -5,6 +5,7 @@ require "store_model/types/array_type"
5
5
  require "store_model/types/enum_type"
6
6
 
7
7
  module StoreModel
8
+ # Contains all custom types.
8
9
  module Types
9
10
  class CastError < StandardError; end
10
11
  end
@@ -4,15 +4,30 @@ require "active_model"
4
4
 
5
5
  module StoreModel
6
6
  module Types
7
+ # Implements ActiveModel::Type::Value type for handling an array of
8
+ # StoreModel::Model
7
9
  class ArrayType < ActiveModel::Type::Value
10
+ # Initializes type for model class
11
+ #
12
+ # @param model_klass [StoreModel::Model] model class to handle
13
+ #
14
+ # @return [StoreModel::Types::ArrayType]
8
15
  def initialize(model_klass)
9
16
  @model_klass = model_klass
10
17
  end
11
18
 
19
+ # Returns type
20
+ #
21
+ # @return [Symbol]
12
22
  def type
13
23
  :array
14
24
  end
15
25
 
26
+ # Casts +value+ from DB or user to StoreModel::Model instance
27
+ #
28
+ # @param value [Object] a value to cast
29
+ #
30
+ # @return StoreModel::Model
16
31
  def cast_value(value)
17
32
  case value
18
33
  when String then decode_and_initialize(value)
@@ -24,6 +39,12 @@ module StoreModel
24
39
  end
25
40
  end
26
41
 
42
+ # Casts a value from the ruby type to a type that the database knows how
43
+ # to understand.
44
+ #
45
+ # @param value [Object] value to serialize
46
+ #
47
+ # @return [String] serialized value
27
48
  def serialize(value)
28
49
  case value
29
50
  when Array
@@ -33,6 +54,12 @@ module StoreModel
33
54
  end
34
55
  end
35
56
 
57
+ # Determines whether the mutable value has been modified since it was read
58
+ #
59
+ # @param raw_old_value [Object] old value
60
+ # @param new_value [Object] new value
61
+ #
62
+ # @return [Boolean]
36
63
  def changed_in_place?(raw_old_value, new_value)
37
64
  cast_value(raw_old_value) != new_value
38
65
  end
@@ -4,15 +4,29 @@ require "active_model"
4
4
 
5
5
  module StoreModel
6
6
  module Types
7
+ # Implements ActiveModel::Type::Value type for handling Rails-like enums
7
8
  class EnumType < ActiveModel::Type::Value
9
+ # Initializes type for mapping
10
+ #
11
+ # @param mapping [Hash] mapping for enum values
12
+ #
13
+ # @return [StoreModel::Types::EnumType]
8
14
  def initialize(mapping)
9
15
  @mapping = mapping
10
16
  end
11
17
 
18
+ # Returns type
19
+ #
20
+ # @return [Symbol]
12
21
  def type
13
22
  :integer
14
23
  end
15
24
 
25
+ # Casts +value+ from DB or user to StoreModel::Model instance
26
+ #
27
+ # @param value [Object] a value to cast
28
+ #
29
+ # @return StoreModel::Model
16
30
  def cast_value(value)
17
31
  return if value.blank?
18
32
 
@@ -4,15 +4,29 @@ require "active_model"
4
4
 
5
5
  module StoreModel
6
6
  module Types
7
+ # Implements ActiveModel::Type::Value type for handling an instance of StoreModel::Model
7
8
  class JsonType < ActiveModel::Type::Value
9
+ # Initializes type for model class
10
+ #
11
+ # @param model_klass [StoreModel::Model] model class to handle
12
+ #
13
+ # @return [StoreModel::Types::JsonType]
8
14
  def initialize(model_klass)
9
15
  @model_klass = model_klass
10
16
  end
11
17
 
18
+ # Returns type
19
+ #
20
+ # @return [Symbol]
12
21
  def type
13
22
  :json
14
23
  end
15
24
 
25
+ # Casts +value+ from DB or user to StoreModel::Model instance
26
+ #
27
+ # @param value [Object] a value to cast
28
+ #
29
+ # @return StoreModel::Model
16
30
  def cast_value(value)
17
31
  case value
18
32
  when String then decode_and_initialize(value)
@@ -24,6 +38,12 @@ module StoreModel
24
38
  handle_unknown_attribute(value, e)
25
39
  end
26
40
 
41
+ # Casts a value from the ruby type to a type that the database knows how
42
+ # to understand.
43
+ #
44
+ # @param value [Object] value to serialize
45
+ #
46
+ # @return [String] serialized value
27
47
  def serialize(value)
28
48
  case value
29
49
  when Hash, @model_klass
@@ -33,6 +53,12 @@ module StoreModel
33
53
  end
34
54
  end
35
55
 
56
+ # Determines whether the mutable value has been modified since it was read
57
+ #
58
+ # @param raw_old_value [Object] old value
59
+ # @param new_value [Object] new value
60
+ #
61
+ # @return [Boolean]
36
62
  def changed_in_place?(raw_old_value, new_value)
37
63
  cast_value(raw_old_value) != new_value
38
64
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module StoreModel
4
- VERSION = "0.5.1"
3
+ module StoreModel # :nodoc:
4
+ VERSION = "0.5.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: store_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - DmitryTsepelev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-06 00:00:00.000000000 Z
11
+ date: 2019-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails