options_model 0.0.12 → 0.0.17
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/README.md +9 -9
- data/lib/options_model/base.rb +3 -5
- data/lib/options_model/concerns/attribute_assignment.rb +5 -7
- data/lib/options_model/concerns/attributes.rb +46 -56
- data/lib/options_model/concerns/serialization.rb +5 -1
- data/lib/options_model/version.rb +1 -1
- metadata +20 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 59d10f339948881cc65723b200408cc41afda4e2f20a8a57e41d202d1a5577a7
         | 
| 4 | 
            +
              data.tar.gz: 3d6efd95aad8412bea1030ae9409567e93405c683528ef5e8a3cfc75855319ec
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: e513c7a36b7c2d4805ee61fe63a0a736fa201b205b1f1554806ad6c3a2097d97422188b9a94b564f587b909752d34cc31e2563a66718d933a6e7510687375306
         | 
| 7 | 
            +
              data.tar.gz: 247f472c517adba88c39ae3a1e336d818237c145aff57a04a3b23df4b49542574f167bf99db88c714fc0d87a3e668219c8034ef3b467baa559a64ac15b49343c
         | 
    
        data/README.md
    CHANGED
    
    | @@ -13,21 +13,21 @@ support attribute: | |
| 13 13 |  | 
| 14 14 | 
             
            ```ruby
         | 
| 15 15 | 
             
            class Person < OptionsModel::Base
         | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 16 | 
            +
              attribute :name, :string
         | 
| 17 | 
            +
              attribute :age, :integer
         | 
| 18 18 |  | 
| 19 | 
            -
             | 
| 19 | 
            +
              validates :name, presence: true
         | 
| 20 20 | 
             
            end
         | 
| 21 21 |  | 
| 22 22 | 
             
            class Book < OptionsModel::Base
         | 
| 23 | 
            -
             | 
| 23 | 
            +
              embeds_one :author, class_name: 'Person'
         | 
| 24 24 |  | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 25 | 
            +
              attribute :title,     :string
         | 
| 26 | 
            +
              attribute :tags,      :string,   array:   true
         | 
| 27 | 
            +
              attribute :price,     :decimal,  default: 0
         | 
| 28 | 
            +
              attribute :bought_at, :datetime, default: -> { Time.new } 
         | 
| 29 29 |  | 
| 30 | 
            -
             | 
| 30 | 
            +
              validates :title, presence: true
         | 
| 31 31 | 
             
            end
         | 
| 32 32 | 
             
            ```
         | 
| 33 33 |  | 
    
        data/lib/options_model/base.rb
    CHANGED
    
    | @@ -10,9 +10,7 @@ module OptionsModel | |
| 10 10 | 
             
                validate do
         | 
| 11 11 | 
             
                  self.class.attribute_names.each do |attribute_name|
         | 
| 12 12 | 
             
                    attribute = public_send(attribute_name)
         | 
| 13 | 
            -
                    if attribute.is_a?(self.class) && attribute.invalid?
         | 
| 14 | 
            -
                      errors.add attribute_name, :invalid
         | 
| 15 | 
            -
                    end
         | 
| 13 | 
            +
                    errors.add attribute_name, :invalid if attribute.is_a?(self.class) && attribute.invalid?
         | 
| 16 14 | 
             
                  end
         | 
| 17 15 | 
             
                end
         | 
| 18 16 |  | 
| @@ -22,14 +20,14 @@ module OptionsModel | |
| 22 20 | 
             
                    nested_attributes == other.nested_attributes &&
         | 
| 23 21 | 
             
                    unused_attributes == other.unused_attributes
         | 
| 24 22 | 
             
                end
         | 
| 25 | 
            -
                alias  | 
| 23 | 
            +
                alias eql? ==
         | 
| 26 24 |  | 
| 27 25 | 
             
                def hash
         | 
| 28 26 | 
             
                  [attributes, nested_attributes, unused_attributes].hash
         | 
| 29 27 | 
             
                end
         | 
| 30 28 |  | 
| 31 29 | 
             
                def inspect
         | 
| 32 | 
            -
                  "#<#{self.class.name}:OptionsModel #{ | 
| 30 | 
            +
                  "#<#{self.class.name}:OptionsModel #{to_h}>"
         | 
| 33 31 | 
             
                end
         | 
| 34 32 |  | 
| 35 33 | 
             
                def self.inspect
         | 
| @@ -15,12 +15,10 @@ module OptionsModel | |
| 15 15 | 
             
                    update_attributes(other)
         | 
| 16 16 | 
             
                  end
         | 
| 17 17 |  | 
| 18 | 
            -
                  def  | 
| 18 | 
            +
                  def replace(other)
         | 
| 19 19 | 
             
                    return unless other
         | 
| 20 20 |  | 
| 21 | 
            -
                    unless other.respond_to?(:to_h)
         | 
| 22 | 
            -
                      raise ArgumentError, "#{other} must be respond to `to_h`"
         | 
| 23 | 
            -
                    end
         | 
| 21 | 
            +
                    raise ArgumentError, "#{other} must be respond to `to_h`" unless other.respond_to?(:to_h)
         | 
| 24 22 |  | 
| 25 23 | 
             
                    other.to_h.each do |k, v|
         | 
| 26 24 | 
             
                      if respond_to?("#{k}=")
         | 
| @@ -31,6 +29,8 @@ module OptionsModel | |
| 31 29 | 
             
                    end
         | 
| 32 30 | 
             
                  end
         | 
| 33 31 |  | 
| 32 | 
            +
                  alias update_attributes replace
         | 
| 33 | 
            +
             | 
| 34 34 | 
             
                  def [](key)
         | 
| 35 35 | 
             
                    public_send(key) if respond_to?(key)
         | 
| 36 36 | 
             
                  end
         | 
| @@ -45,9 +45,7 @@ module OptionsModel | |
| 45 45 | 
             
                  end
         | 
| 46 46 |  | 
| 47 47 | 
             
                  def fetch(key, default = nil)
         | 
| 48 | 
            -
                    if self.class.attribute_names.exclude?(key.to_sym) && default.nil? && !block_given?
         | 
| 49 | 
            -
                      raise KeyError, "attribute not found"
         | 
| 50 | 
            -
                    end
         | 
| 48 | 
            +
                    raise KeyError, "attribute not found" if self.class.attribute_names.exclude?(key.to_sym) && default.nil? && !block_given?
         | 
| 51 49 |  | 
| 52 50 | 
             
                    value = respond_to?(key) ? public_send(key) : nil
         | 
| 53 51 | 
             
                    return value if value
         | 
| @@ -16,10 +16,9 @@ module OptionsModel | |
| 16 16 |  | 
| 17 17 | 
             
                      attribute_defaults[name] = default
         | 
| 18 18 | 
             
                      default_extractor =
         | 
| 19 | 
            -
                         | 
| 20 | 
            -
                        when default.respond_to?(:call)
         | 
| 19 | 
            +
                        if default.respond_to?(:call)
         | 
| 21 20 | 
             
                          ".call"
         | 
| 22 | 
            -
                         | 
| 21 | 
            +
                        elsif default.duplicable?
         | 
| 23 22 | 
             
                          ".deep_dup"
         | 
| 24 23 | 
             
                        else
         | 
| 25 24 | 
             
                          ""
         | 
| @@ -55,13 +54,11 @@ module OptionsModel | |
| 55 54 | 
             
                          end
         | 
| 56 55 | 
             
                          STR
         | 
| 57 56 |  | 
| 58 | 
            -
                          if cast_type == :boolean
         | 
| 59 | 
            -
                            generated_attribute_methods.send :alias_method, :"#{name}?", name
         | 
| 60 | 
            -
                          end
         | 
| 57 | 
            +
                          generated_attribute_methods.send :alias_method, :"#{name}?", name if cast_type == :boolean
         | 
| 61 58 | 
             
                        end
         | 
| 62 59 | 
             
                      end
         | 
| 63 60 |  | 
| 64 | 
            -
                       | 
| 61 | 
            +
                      attribute_names_for_inlining << name
         | 
| 65 62 |  | 
| 66 63 | 
             
                      self
         | 
| 67 64 | 
             
                    end
         | 
| @@ -69,9 +66,8 @@ module OptionsModel | |
| 69 66 | 
             
                    def enum_attribute(name, enum, default: nil, allow_nil: false)
         | 
| 70 67 | 
             
                      check_not_finalized!
         | 
| 71 68 |  | 
| 72 | 
            -
                      unless enum.is_a?(Array) && enum.any?
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                      end
         | 
| 69 | 
            +
                      raise ArgumentError, "enum should be an Array and can't empty" unless enum.is_a?(Array) && enum.any?
         | 
| 70 | 
            +
             | 
| 75 71 | 
             
                      enum = enum.map(&:to_s)
         | 
| 76 72 |  | 
| 77 73 | 
             
                      attribute name, :string, default: default
         | 
| @@ -80,11 +76,11 @@ module OptionsModel | |
| 80 76 | 
             
                      generated_class_methods.synchronize do
         | 
| 81 77 | 
             
                        generated_class_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
         | 
| 82 78 | 
             
                        def #{pluralized_name}
         | 
| 83 | 
            -
                          %w(#{enum.join( | 
| 79 | 
            +
                          %w(#{enum.join(' ')}).freeze
         | 
| 84 80 | 
             
                        end
         | 
| 85 81 | 
             
                        STR
         | 
| 86 82 |  | 
| 87 | 
            -
                        validates name, inclusion: {in: enum}, allow_nil: allow_nil
         | 
| 83 | 
            +
                        validates name, inclusion: { in: enum }, allow_nil: allow_nil
         | 
| 88 84 | 
             
                      end
         | 
| 89 85 |  | 
| 90 86 | 
             
                      self
         | 
| @@ -93,17 +89,15 @@ module OptionsModel | |
| 93 89 | 
             
                    def embeds_one(name, class_name: nil, anonymous_class: nil)
         | 
| 94 90 | 
             
                      check_not_finalized!
         | 
| 95 91 |  | 
| 96 | 
            -
                      if class_name.blank? && anonymous_class.nil?
         | 
| 97 | 
            -
                        raise ArgumentError, "must provide at least one of `class_name` or `anonymous_class`"
         | 
| 98 | 
            -
                      end
         | 
| 92 | 
            +
                      raise ArgumentError, "must provide at least one of `class_name` or `anonymous_class`" if class_name.blank? && anonymous_class.nil?
         | 
| 99 93 |  | 
| 100 94 | 
             
                      name = name.to_sym
         | 
| 101 95 | 
             
                      check_name_validity! name
         | 
| 102 96 |  | 
| 103 | 
            -
                      if class_name.present?
         | 
| 104 | 
            -
                         | 
| 97 | 
            +
                      nested_classes[name] = if class_name.present?
         | 
| 98 | 
            +
                        class_name.constantize
         | 
| 105 99 | 
             
                      else
         | 
| 106 | 
            -
                         | 
| 100 | 
            +
                        anonymous_class
         | 
| 107 101 | 
             
                      end
         | 
| 108 102 |  | 
| 109 103 | 
             
                      generated_attribute_methods.synchronize do
         | 
| @@ -130,7 +124,7 @@ module OptionsModel | |
| 130 124 | 
             
                        STR
         | 
| 131 125 | 
             
                      end
         | 
| 132 126 |  | 
| 133 | 
            -
                       | 
| 127 | 
            +
                      attribute_names_for_nesting << name
         | 
| 134 128 |  | 
| 135 129 | 
             
                      self
         | 
| 136 130 | 
             
                    end
         | 
| @@ -160,60 +154,56 @@ module OptionsModel | |
| 160 154 | 
             
                    end
         | 
| 161 155 |  | 
| 162 156 | 
             
                    def finalize!(nested = true)
         | 
| 163 | 
            -
                      if nested
         | 
| 164 | 
            -
                        nested_classes.values.each(&:finalize!)
         | 
| 165 | 
            -
                      end
         | 
| 157 | 
            +
                      nested_classes.values.each(&:finalize!) if nested
         | 
| 166 158 |  | 
| 167 159 | 
             
                      @finalized = true
         | 
| 168 160 | 
             
                    end
         | 
| 169 161 |  | 
| 170 162 | 
             
                    protected
         | 
| 171 163 |  | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 164 | 
            +
                      def check_name_validity!(symbolized_name)
         | 
| 165 | 
            +
                        if dangerous_attribute_method?(symbolized_name)
         | 
| 166 | 
            +
                          raise ArgumentError, "#{symbolized_name} is defined by #{OptionsModel::Base}. Check to make sure that you don't have an attribute or method with the same name."
         | 
| 167 | 
            +
                        end
         | 
| 176 168 |  | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 169 | 
            +
                        if attribute_names_for_inlining.include?(symbolized_name) || attribute_names_for_nesting.include?(symbolized_name)
         | 
| 170 | 
            +
                          raise ArgumentError, "duplicate define attribute `#{symbolized_name}`"
         | 
| 171 | 
            +
                        end
         | 
| 179 172 | 
             
                      end
         | 
| 180 | 
            -
                    end
         | 
| 181 173 |  | 
| 182 | 
            -
             | 
| 183 | 
            -
             | 
| 184 | 
            -
                        raise "can't modify finalized #{self}"
         | 
| 174 | 
            +
                      def check_not_finalized!
         | 
| 175 | 
            +
                        raise "can't modify finalized #{self}" if finalized?
         | 
| 185 176 | 
             
                      end
         | 
| 186 | 
            -
                    end
         | 
| 187 177 |  | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 178 | 
            +
                      # A method name is 'dangerous' if it is already (re)defined by OptionsModel, but
         | 
| 179 | 
            +
                      # not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
         | 
| 180 | 
            +
                      def dangerous_attribute_method?(name) # :nodoc:
         | 
| 181 | 
            +
                        method_defined_within?(name, OptionsModel::Base)
         | 
| 182 | 
            +
                      end
         | 
| 193 183 |  | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 184 | 
            +
                      def method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
         | 
| 185 | 
            +
                        if klass.method_defined?(name) || klass.private_method_defined?(name)
         | 
| 186 | 
            +
                          if superklass.method_defined?(name) || superklass.private_method_defined?(name)
         | 
| 187 | 
            +
                            klass.instance_method(name).owner != superklass.instance_method(name).owner
         | 
| 188 | 
            +
                          else
         | 
| 189 | 
            +
                            true
         | 
| 190 | 
            +
                          end
         | 
| 198 191 | 
             
                        else
         | 
| 199 | 
            -
                           | 
| 192 | 
            +
                          false
         | 
| 200 193 | 
             
                        end
         | 
| 201 | 
            -
                      else
         | 
| 202 | 
            -
                        false
         | 
| 203 194 | 
             
                      end
         | 
| 204 | 
            -
                    end
         | 
| 205 195 |  | 
| 206 | 
            -
             | 
| 207 | 
            -
             | 
| 208 | 
            -
             | 
| 209 | 
            -
             | 
| 210 | 
            -
             | 
| 196 | 
            +
                      def generated_attribute_methods
         | 
| 197 | 
            +
                        @generated_attribute_methods ||= Module.new do
         | 
| 198 | 
            +
                          extend Mutex_m
         | 
| 199 | 
            +
                        end.tap { |mod| include mod }
         | 
| 200 | 
            +
                      end
         | 
| 211 201 |  | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 202 | 
            +
                      def generated_class_methods
         | 
| 203 | 
            +
                        @generated_class_methods ||= Module.new do
         | 
| 204 | 
            +
                          extend Mutex_m
         | 
| 205 | 
            +
                        end.tap { |mod| extend mod }
         | 
| 206 | 
            +
                      end
         | 
| 217 207 | 
             
                  end
         | 
| 218 208 | 
             
                end
         | 
| 219 209 | 
             
              end
         | 
| @@ -35,7 +35,7 @@ module OptionsModel | |
| 35 35 | 
             
                      return new unless yaml
         | 
| 36 36 | 
             
                      return new unless yaml.is_a?(String) && /^---/.match?(yaml)
         | 
| 37 37 |  | 
| 38 | 
            -
                      hash = YAML. | 
| 38 | 
            +
                      hash = YAML.safe_load(yaml, permitted_classes: permitted_attribute_classes) || {}
         | 
| 39 39 |  | 
| 40 40 | 
             
                      unless hash.is_a? Hash
         | 
| 41 41 | 
             
                        raise ArgumentError,
         | 
| @@ -52,6 +52,10 @@ module OptionsModel | |
| 52 52 | 
             
                    def with_unused_attributes?
         | 
| 53 53 | 
             
                      @with_unused_attributes
         | 
| 54 54 | 
             
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    def permitted_attribute_classes
         | 
| 57 | 
            +
                      @permitted_attribute_classes ||= [Symbol]
         | 
| 58 | 
            +
                    end
         | 
| 55 59 | 
             
                  end
         | 
| 56 60 | 
             
                end
         | 
| 57 61 | 
             
              end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: options_model
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.17
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - jasl
         | 
| 8 | 
            -
            autorequire: | 
| 8 | 
            +
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2020-11-04 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activemodel
         | 
| @@ -50,6 +50,20 @@ dependencies: | |
| 50 50 | 
             
                - - "<"
         | 
| 51 51 | 
             
                  - !ruby/object:Gem::Version
         | 
| 52 52 | 
             
                    version: '7'
         | 
| 53 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 54 | 
            +
              name: psych
         | 
| 55 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 56 | 
            +
                requirements:
         | 
| 57 | 
            +
                - - "~>"
         | 
| 58 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 59 | 
            +
                    version: '3.2'
         | 
| 60 | 
            +
              type: :runtime
         | 
| 61 | 
            +
              prerelease: false
         | 
| 62 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 63 | 
            +
                requirements:
         | 
| 64 | 
            +
                - - "~>"
         | 
| 65 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 66 | 
            +
                    version: '3.2'
         | 
| 53 67 | 
             
            description: An ActiveModel implementation that make easier to handle model which
         | 
| 54 68 | 
             
              will be serialized in a real model.
         | 
| 55 69 | 
             
            email:
         | 
| @@ -73,7 +87,7 @@ homepage: https://github.com/jasl-lab/options_model | |
| 73 87 | 
             
            licenses:
         | 
| 74 88 | 
             
            - MIT
         | 
| 75 89 | 
             
            metadata: {}
         | 
| 76 | 
            -
            post_install_message: | 
| 90 | 
            +
            post_install_message:
         | 
| 77 91 | 
             
            rdoc_options: []
         | 
| 78 92 | 
             
            require_paths:
         | 
| 79 93 | 
             
            - lib
         | 
| @@ -88,8 +102,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 88 102 | 
             
                - !ruby/object:Gem::Version
         | 
| 89 103 | 
             
                  version: '0'
         | 
| 90 104 | 
             
            requirements: []
         | 
| 91 | 
            -
            rubygems_version: 3. | 
| 92 | 
            -
            signing_key: | 
| 105 | 
            +
            rubygems_version: 3.1.4
         | 
| 106 | 
            +
            signing_key:
         | 
| 93 107 | 
             
            specification_version: 4
         | 
| 94 108 | 
             
            summary: Make easier to handle model which will be serialized in a real model.
         | 
| 95 109 | 
             
            test_files: []
         |