activeentity 0.0.1.beta1
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 +7 -0
 - data/MIT-LICENSE +42 -0
 - data/README.md +145 -0
 - data/Rakefile +29 -0
 - data/lib/active_entity.rb +73 -0
 - data/lib/active_entity/aggregations.rb +276 -0
 - data/lib/active_entity/associations.rb +146 -0
 - data/lib/active_entity/associations/embedded/association.rb +134 -0
 - data/lib/active_entity/associations/embedded/builder/association.rb +100 -0
 - data/lib/active_entity/associations/embedded/builder/collection_association.rb +69 -0
 - data/lib/active_entity/associations/embedded/builder/embedded_in.rb +38 -0
 - data/lib/active_entity/associations/embedded/builder/embeds_many.rb +13 -0
 - data/lib/active_entity/associations/embedded/builder/embeds_one.rb +16 -0
 - data/lib/active_entity/associations/embedded/builder/singular_association.rb +28 -0
 - data/lib/active_entity/associations/embedded/collection_association.rb +188 -0
 - data/lib/active_entity/associations/embedded/collection_proxy.rb +310 -0
 - data/lib/active_entity/associations/embedded/embedded_in_association.rb +31 -0
 - data/lib/active_entity/associations/embedded/embeds_many_association.rb +15 -0
 - data/lib/active_entity/associations/embedded/embeds_one_association.rb +19 -0
 - data/lib/active_entity/associations/embedded/singular_association.rb +35 -0
 - data/lib/active_entity/attribute_assignment.rb +85 -0
 - data/lib/active_entity/attribute_decorators.rb +90 -0
 - data/lib/active_entity/attribute_methods.rb +330 -0
 - data/lib/active_entity/attribute_methods/before_type_cast.rb +78 -0
 - data/lib/active_entity/attribute_methods/primary_key.rb +98 -0
 - data/lib/active_entity/attribute_methods/query.rb +35 -0
 - data/lib/active_entity/attribute_methods/read.rb +47 -0
 - data/lib/active_entity/attribute_methods/serialization.rb +90 -0
 - data/lib/active_entity/attribute_methods/time_zone_conversion.rb +91 -0
 - data/lib/active_entity/attribute_methods/write.rb +63 -0
 - data/lib/active_entity/attributes.rb +165 -0
 - data/lib/active_entity/base.rb +303 -0
 - data/lib/active_entity/coders/json.rb +15 -0
 - data/lib/active_entity/coders/yaml_column.rb +50 -0
 - data/lib/active_entity/core.rb +281 -0
 - data/lib/active_entity/define_callbacks.rb +17 -0
 - data/lib/active_entity/enum.rb +234 -0
 - data/lib/active_entity/errors.rb +80 -0
 - data/lib/active_entity/gem_version.rb +17 -0
 - data/lib/active_entity/inheritance.rb +278 -0
 - data/lib/active_entity/integration.rb +78 -0
 - data/lib/active_entity/locale/en.yml +45 -0
 - data/lib/active_entity/model_schema.rb +115 -0
 - data/lib/active_entity/nested_attributes.rb +592 -0
 - data/lib/active_entity/readonly_attributes.rb +47 -0
 - data/lib/active_entity/reflection.rb +441 -0
 - data/lib/active_entity/serialization.rb +25 -0
 - data/lib/active_entity/store.rb +242 -0
 - data/lib/active_entity/translation.rb +24 -0
 - data/lib/active_entity/type.rb +73 -0
 - data/lib/active_entity/type/date.rb +9 -0
 - data/lib/active_entity/type/date_time.rb +9 -0
 - data/lib/active_entity/type/decimal_without_scale.rb +15 -0
 - data/lib/active_entity/type/hash_lookup_type_map.rb +25 -0
 - data/lib/active_entity/type/internal/timezone.rb +17 -0
 - data/lib/active_entity/type/json.rb +30 -0
 - data/lib/active_entity/type/modifiers/array.rb +72 -0
 - data/lib/active_entity/type/registry.rb +92 -0
 - data/lib/active_entity/type/serialized.rb +71 -0
 - data/lib/active_entity/type/text.rb +11 -0
 - data/lib/active_entity/type/time.rb +21 -0
 - data/lib/active_entity/type/type_map.rb +62 -0
 - data/lib/active_entity/type/unsigned_integer.rb +17 -0
 - data/lib/active_entity/validate_embedded_association.rb +305 -0
 - data/lib/active_entity/validations.rb +50 -0
 - data/lib/active_entity/validations/absence.rb +25 -0
 - data/lib/active_entity/validations/associated.rb +60 -0
 - data/lib/active_entity/validations/length.rb +26 -0
 - data/lib/active_entity/validations/presence.rb +68 -0
 - data/lib/active_entity/validations/subset.rb +76 -0
 - data/lib/active_entity/validations/uniqueness_in_embedding.rb +99 -0
 - data/lib/active_entity/version.rb +10 -0
 - data/lib/tasks/active_entity_tasks.rake +6 -0
 - metadata +155 -0
 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActiveEntity
         
     | 
| 
      
 4 
     | 
    
         
            +
              module AttributeMethods
         
     | 
| 
      
 5 
     | 
    
         
            +
                # = Active Entity Attribute Methods Before Type Cast
         
     | 
| 
      
 6 
     | 
    
         
            +
                #
         
     | 
| 
      
 7 
     | 
    
         
            +
                # ActiveEntity::AttributeMethods::BeforeTypeCast provides a way to
         
     | 
| 
      
 8 
     | 
    
         
            +
                # read the value of the attributes before typecasting and deserialization.
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   class Task < ActiveEntity::Base
         
     | 
| 
      
 11 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 12 
     | 
    
         
            +
                #
         
     | 
| 
      
 13 
     | 
    
         
            +
                #   task = Task.new(id: '1', completed_on: '2012-10-21')
         
     | 
| 
      
 14 
     | 
    
         
            +
                #   task.id           # => 1
         
     | 
| 
      
 15 
     | 
    
         
            +
                #   task.completed_on # => Sun, 21 Oct 2012
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                #   task.attributes_before_type_cast
         
     | 
| 
      
 18 
     | 
    
         
            +
                #   # => {"id"=>"1", "completed_on"=>"2012-10-21", ... }
         
     | 
| 
      
 19 
     | 
    
         
            +
                #   task.read_attribute_before_type_cast('id')           # => "1"
         
     | 
| 
      
 20 
     | 
    
         
            +
                #   task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
         
     | 
| 
      
 21 
     | 
    
         
            +
                #
         
     | 
| 
      
 22 
     | 
    
         
            +
                # In addition to #read_attribute_before_type_cast and #attributes_before_type_cast,
         
     | 
| 
      
 23 
     | 
    
         
            +
                # it declares a method for all attributes with the <tt>*_before_type_cast</tt>
         
     | 
| 
      
 24 
     | 
    
         
            +
                # suffix.
         
     | 
| 
      
 25 
     | 
    
         
            +
                #
         
     | 
| 
      
 26 
     | 
    
         
            +
                #   task.id_before_type_cast           # => "1"
         
     | 
| 
      
 27 
     | 
    
         
            +
                #   task.completed_on_before_type_cast # => "2012-10-21"
         
     | 
| 
      
 28 
     | 
    
         
            +
                module BeforeTypeCast
         
     | 
| 
      
 29 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    attribute_method_suffix "_before_type_cast"
         
     | 
| 
      
 33 
     | 
    
         
            +
                    attribute_method_suffix "_came_from_user?"
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  # Returns the value of the attribute identified by +attr_name+ before
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # typecasting and deserialization.
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #   class Task < ActiveEntity::Base
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   task = Task.new(id: '1', completed_on: '2012-10-21')
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #   task.read_attribute('id')                            # => 1
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #   task.read_attribute_before_type_cast('id')           # => '1'
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #   task.read_attribute('completed_on')                  # => Sun, 21 Oct 2012
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #   task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
         
     | 
| 
      
 47 
     | 
    
         
            +
                  #   task.read_attribute_before_type_cast(:completed_on)  # => "2012-10-21"
         
     | 
| 
      
 48 
     | 
    
         
            +
                  def read_attribute_before_type_cast(attr_name)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    @attributes[attr_name.to_s].value_before_type_cast
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  # Returns a hash of attributes before typecasting and deserialization.
         
     | 
| 
      
 53 
     | 
    
         
            +
                  #
         
     | 
| 
      
 54 
     | 
    
         
            +
                  #   class Task < ActiveEntity::Base
         
     | 
| 
      
 55 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  #
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #   task = Task.new(title: nil, is_done: true, completed_on: '2012-10-21')
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #   task.attributes
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>Sun, 21 Oct 2012, "created_at"=>nil, "updated_at"=>nil}
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #   task.attributes_before_type_cast
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #   # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
         
     | 
| 
      
 62 
     | 
    
         
            +
                  def attributes_before_type_cast
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @attributes.values_before_type_cast
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  private
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    # Handle *_before_type_cast for method_missing.
         
     | 
| 
      
 69 
     | 
    
         
            +
                    def attribute_before_type_cast(attribute_name)
         
     | 
| 
      
 70 
     | 
    
         
            +
                      read_attribute_before_type_cast(attribute_name)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    def attribute_came_from_user?(attribute_name)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      @attributes[attribute_name].came_from_user?
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,98 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "set"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module ActiveEntity
         
     | 
| 
      
 6 
     | 
    
         
            +
              module AttributeMethods
         
     | 
| 
      
 7 
     | 
    
         
            +
                module PrimaryKey
         
     | 
| 
      
 8 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  # Returns this record's primary key value wrapped in an array if one is
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # available.
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def to_key
         
     | 
| 
      
 13 
     | 
    
         
            +
                    key = id
         
     | 
| 
      
 14 
     | 
    
         
            +
                    [key] if key
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  # Returns the primary key column's value.
         
     | 
| 
      
 18 
     | 
    
         
            +
                  def id
         
     | 
| 
      
 19 
     | 
    
         
            +
                    primary_key = self.class.primary_key
         
     | 
| 
      
 20 
     | 
    
         
            +
                    _read_attribute(primary_key) if primary_key
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  # Sets the primary key column's value.
         
     | 
| 
      
 24 
     | 
    
         
            +
                  def id=(value)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    primary_key = self.class.primary_key
         
     | 
| 
      
 26 
     | 
    
         
            +
                    _write_attribute(primary_key, value) if primary_key
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  # Queries the primary key column's value.
         
     | 
| 
      
 30 
     | 
    
         
            +
                  def id?
         
     | 
| 
      
 31 
     | 
    
         
            +
                    query_attribute(self.class.primary_key)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  # Returns the primary key column's value before type cast.
         
     | 
| 
      
 35 
     | 
    
         
            +
                  def id_before_type_cast
         
     | 
| 
      
 36 
     | 
    
         
            +
                    read_attribute_before_type_cast(self.class.primary_key)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  # Returns the primary key column's previous value.
         
     | 
| 
      
 40 
     | 
    
         
            +
                  def id_was
         
     | 
| 
      
 41 
     | 
    
         
            +
                    attribute_was(self.class.primary_key)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  private
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    def attribute_method?(attr_name)
         
     | 
| 
      
 47 
     | 
    
         
            +
                      attr_name == "id" || super
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    module ClassMethods
         
     | 
| 
      
 51 
     | 
    
         
            +
                      ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database).to_set
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                      def instance_method_already_implemented?(method_name)
         
     | 
| 
      
 54 
     | 
    
         
            +
                        super || primary_key && ID_ATTRIBUTE_METHODS.include?(method_name)
         
     | 
| 
      
 55 
     | 
    
         
            +
                      end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                      def dangerous_attribute_method?(method_name)
         
     | 
| 
      
 58 
     | 
    
         
            +
                        super && !ID_ATTRIBUTE_METHODS.include?(method_name)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                      # Defines the primary key field -- can be overridden in subclasses.
         
     | 
| 
      
 62 
     | 
    
         
            +
                      # Overwriting will negate any effect of the +primary_key_prefix_type+
         
     | 
| 
      
 63 
     | 
    
         
            +
                      # setting, though.
         
     | 
| 
      
 64 
     | 
    
         
            +
                      def primary_key
         
     | 
| 
      
 65 
     | 
    
         
            +
                        unless defined? @primary_key
         
     | 
| 
      
 66 
     | 
    
         
            +
                          @primary_key =
         
     | 
| 
      
 67 
     | 
    
         
            +
                            if has_attribute?("id")
         
     | 
| 
      
 68 
     | 
    
         
            +
                              "id"
         
     | 
| 
      
 69 
     | 
    
         
            +
                            else
         
     | 
| 
      
 70 
     | 
    
         
            +
                              nil
         
     | 
| 
      
 71 
     | 
    
         
            +
                            end
         
     | 
| 
      
 72 
     | 
    
         
            +
                        end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                        @primary_key
         
     | 
| 
      
 75 
     | 
    
         
            +
                      end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                      # Sets the name of the primary key column.
         
     | 
| 
      
 78 
     | 
    
         
            +
                      #
         
     | 
| 
      
 79 
     | 
    
         
            +
                      #   class Project < ActiveEntity::Base
         
     | 
| 
      
 80 
     | 
    
         
            +
                      #     self.primary_key = 'sysid'
         
     | 
| 
      
 81 
     | 
    
         
            +
                      #   end
         
     | 
| 
      
 82 
     | 
    
         
            +
                      #
         
     | 
| 
      
 83 
     | 
    
         
            +
                      # You can also define the #primary_key method yourself:
         
     | 
| 
      
 84 
     | 
    
         
            +
                      #
         
     | 
| 
      
 85 
     | 
    
         
            +
                      #   class Project < ActiveEntity::Base
         
     | 
| 
      
 86 
     | 
    
         
            +
                      #     def self.primary_key
         
     | 
| 
      
 87 
     | 
    
         
            +
                      #       'foo_' + super
         
     | 
| 
      
 88 
     | 
    
         
            +
                      #     end
         
     | 
| 
      
 89 
     | 
    
         
            +
                      #   end
         
     | 
| 
      
 90 
     | 
    
         
            +
                      #
         
     | 
| 
      
 91 
     | 
    
         
            +
                      #   Project.primary_key # => "foo_id"
         
     | 
| 
      
 92 
     | 
    
         
            +
                      def primary_key=(value)
         
     | 
| 
      
 93 
     | 
    
         
            +
                        @primary_key = value&.to_s
         
     | 
| 
      
 94 
     | 
    
         
            +
                      end
         
     | 
| 
      
 95 
     | 
    
         
            +
                    end
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
              end
         
     | 
| 
      
 98 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActiveEntity
         
     | 
| 
      
 4 
     | 
    
         
            +
              module AttributeMethods
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Query
         
     | 
| 
      
 6 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    attribute_method_suffix "?"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def query_attribute(attr_name)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    value = self[attr_name]
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    case value
         
     | 
| 
      
 16 
     | 
    
         
            +
                    when true        then true
         
     | 
| 
      
 17 
     | 
    
         
            +
                    when false, nil  then false
         
     | 
| 
      
 18 
     | 
    
         
            +
                    else
         
     | 
| 
      
 19 
     | 
    
         
            +
                      if Numeric === value || value !~ /[^0-9]/
         
     | 
| 
      
 20 
     | 
    
         
            +
                        !value.to_i.zero?
         
     | 
| 
      
 21 
     | 
    
         
            +
                      else
         
     | 
| 
      
 22 
     | 
    
         
            +
                        return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
         
     | 
| 
      
 23 
     | 
    
         
            +
                        !value.blank?
         
     | 
| 
      
 24 
     | 
    
         
            +
                      end
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  private
         
     | 
| 
      
 29 
     | 
    
         
            +
                    # Handle *? for method_missing.
         
     | 
| 
      
 30 
     | 
    
         
            +
                    def attribute?(attribute_name)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      query_attribute(attribute_name)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,47 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActiveEntity
         
     | 
| 
      
 4 
     | 
    
         
            +
              module AttributeMethods
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Read
         
     | 
| 
      
 6 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  module ClassMethods # :nodoc:
         
     | 
| 
      
 9 
     | 
    
         
            +
                    private
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                      def define_method_attribute(name)
         
     | 
| 
      
 12 
     | 
    
         
            +
                        ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
         
     | 
| 
      
 13 
     | 
    
         
            +
                          generated_attribute_methods, name
         
     | 
| 
      
 14 
     | 
    
         
            +
                        ) do |temp_method_name, attr_name_expr|
         
     | 
| 
      
 15 
     | 
    
         
            +
                          generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
         
     | 
| 
      
 16 
     | 
    
         
            +
                            def #{temp_method_name}
         
     | 
| 
      
 17 
     | 
    
         
            +
                              name = #{attr_name_expr}
         
     | 
| 
      
 18 
     | 
    
         
            +
                              _read_attribute(name) { |n| missing_attribute(n, caller) }
         
     | 
| 
      
 19 
     | 
    
         
            +
                            end
         
     | 
| 
      
 20 
     | 
    
         
            +
                          RUBY
         
     | 
| 
      
 21 
     | 
    
         
            +
                        end
         
     | 
| 
      
 22 
     | 
    
         
            +
                      end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  # Returns the value of the attribute identified by <tt>attr_name</tt> after
         
     | 
| 
      
 26 
     | 
    
         
            +
                  # it has been typecast (for example, "2004-12-12" in a date column is cast
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # to a date object, like Date.new(2004, 12, 12)).
         
     | 
| 
      
 28 
     | 
    
         
            +
                  def read_attribute(attr_name, &block)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    name = attr_name.to_s
         
     | 
| 
      
 30 
     | 
    
         
            +
                    if self.class.attribute_alias?(name)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      name = self.class.attribute_alias(name)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    _read_attribute(name, &block)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  # This method exists to avoid the expensive primary_key check internally, without
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # breaking compatibility with the read_attribute API
         
     | 
| 
      
 39 
     | 
    
         
            +
                  def _read_attribute(attr_name, &block) # :nodoc
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @attributes.fetch_value(attr_name.to_s, &block)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  alias :attribute :_read_attribute
         
     | 
| 
      
 44 
     | 
    
         
            +
                  private :attribute
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,90 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActiveEntity
         
     | 
| 
      
 4 
     | 
    
         
            +
              module AttributeMethods
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Serialization
         
     | 
| 
      
 6 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  class ColumnNotSerializableError < StandardError
         
     | 
| 
      
 9 
     | 
    
         
            +
                    def initialize(name, type)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      super <<~EOS
         
     | 
| 
      
 11 
     | 
    
         
            +
                        Column `#{name}` of type #{type.class} does not support `serialize` feature.
         
     | 
| 
      
 12 
     | 
    
         
            +
                        Usually it means that you are trying to use `serialize`
         
     | 
| 
      
 13 
     | 
    
         
            +
                        on a column that already implements serialization natively.
         
     | 
| 
      
 14 
     | 
    
         
            +
                      EOS
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  module ClassMethods
         
     | 
| 
      
 19 
     | 
    
         
            +
                    # If you have an attribute that needs to be saved to the database as an
         
     | 
| 
      
 20 
     | 
    
         
            +
                    # object, and retrieved as the same object, then specify the name of that
         
     | 
| 
      
 21 
     | 
    
         
            +
                    # attribute using this method and it will be handled automatically. The
         
     | 
| 
      
 22 
     | 
    
         
            +
                    # serialization is done through YAML. If +class_name+ is specified, the
         
     | 
| 
      
 23 
     | 
    
         
            +
                    # serialized object must be of that class on assignment and retrieval.
         
     | 
| 
      
 24 
     | 
    
         
            +
                    # Otherwise SerializationTypeMismatch will be raised.
         
     | 
| 
      
 25 
     | 
    
         
            +
                    #
         
     | 
| 
      
 26 
     | 
    
         
            +
                    # Empty objects as <tt>{}</tt>, in the case of +Hash+, or <tt>[]</tt>, in the case of
         
     | 
| 
      
 27 
     | 
    
         
            +
                    # +Array+, will always be persisted as null.
         
     | 
| 
      
 28 
     | 
    
         
            +
                    #
         
     | 
| 
      
 29 
     | 
    
         
            +
                    # Keep in mind that database adapters handle certain serialization tasks
         
     | 
| 
      
 30 
     | 
    
         
            +
                    # for you. For instance: +json+ and +jsonb+ types in PostgreSQL will be
         
     | 
| 
      
 31 
     | 
    
         
            +
                    # converted between JSON object/array syntax and Ruby +Hash+ or +Array+
         
     | 
| 
      
 32 
     | 
    
         
            +
                    # objects transparently. There is no need to use #serialize in this
         
     | 
| 
      
 33 
     | 
    
         
            +
                    # case.
         
     | 
| 
      
 34 
     | 
    
         
            +
                    #
         
     | 
| 
      
 35 
     | 
    
         
            +
                    # For more complex cases, such as conversion to or from your application
         
     | 
| 
      
 36 
     | 
    
         
            +
                    # domain objects, consider using the ActiveEntity::Attributes API.
         
     | 
| 
      
 37 
     | 
    
         
            +
                    #
         
     | 
| 
      
 38 
     | 
    
         
            +
                    # ==== Parameters
         
     | 
| 
      
 39 
     | 
    
         
            +
                    #
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # * +attr_name+ - The field name that should be serialized.
         
     | 
| 
      
 41 
     | 
    
         
            +
                    # * +class_name_or_coder+ - Optional, a coder object, which responds to +.load+ and +.dump+
         
     | 
| 
      
 42 
     | 
    
         
            +
                    #   or a class name that the object type should be equal to.
         
     | 
| 
      
 43 
     | 
    
         
            +
                    #
         
     | 
| 
      
 44 
     | 
    
         
            +
                    # ==== Example
         
     | 
| 
      
 45 
     | 
    
         
            +
                    #
         
     | 
| 
      
 46 
     | 
    
         
            +
                    #   # Serialize a preferences attribute.
         
     | 
| 
      
 47 
     | 
    
         
            +
                    #   class User < ActiveEntity::Base
         
     | 
| 
      
 48 
     | 
    
         
            +
                    #     serialize :preferences
         
     | 
| 
      
 49 
     | 
    
         
            +
                    #   end
         
     | 
| 
      
 50 
     | 
    
         
            +
                    #
         
     | 
| 
      
 51 
     | 
    
         
            +
                    #   # Serialize preferences using JSON as coder.
         
     | 
| 
      
 52 
     | 
    
         
            +
                    #   class User < ActiveEntity::Base
         
     | 
| 
      
 53 
     | 
    
         
            +
                    #     serialize :preferences, JSON
         
     | 
| 
      
 54 
     | 
    
         
            +
                    #   end
         
     | 
| 
      
 55 
     | 
    
         
            +
                    #
         
     | 
| 
      
 56 
     | 
    
         
            +
                    #   # Serialize preferences as Hash using YAML coder.
         
     | 
| 
      
 57 
     | 
    
         
            +
                    #   class User < ActiveEntity::Base
         
     | 
| 
      
 58 
     | 
    
         
            +
                    #     serialize :preferences, Hash
         
     | 
| 
      
 59 
     | 
    
         
            +
                    #   end
         
     | 
| 
      
 60 
     | 
    
         
            +
                    def serialize(attr_name, class_name_or_coder = Object)
         
     | 
| 
      
 61 
     | 
    
         
            +
                      # When ::JSON is used, force it to go through the Active Support JSON encoder
         
     | 
| 
      
 62 
     | 
    
         
            +
                      # to ensure special objects (e.g. Active Entity models) are dumped correctly
         
     | 
| 
      
 63 
     | 
    
         
            +
                      # using the #as_json hook.
         
     | 
| 
      
 64 
     | 
    
         
            +
                      coder = if class_name_or_coder == ::JSON
         
     | 
| 
      
 65 
     | 
    
         
            +
                        Coders::JSON
         
     | 
| 
      
 66 
     | 
    
         
            +
                      elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
         
     | 
| 
      
 67 
     | 
    
         
            +
                        class_name_or_coder
         
     | 
| 
      
 68 
     | 
    
         
            +
                      else
         
     | 
| 
      
 69 
     | 
    
         
            +
                        Coders::YAMLColumn.new(attr_name, class_name_or_coder)
         
     | 
| 
      
 70 
     | 
    
         
            +
                      end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                      decorate_attribute_type(attr_name, :serialize) do |type|
         
     | 
| 
      
 73 
     | 
    
         
            +
                        if type_incompatible_with_serialize?(type, class_name_or_coder)
         
     | 
| 
      
 74 
     | 
    
         
            +
                          raise ColumnNotSerializableError.new(attr_name, type)
         
     | 
| 
      
 75 
     | 
    
         
            +
                        end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                        Type::Serialized.new(type, coder)
         
     | 
| 
      
 78 
     | 
    
         
            +
                      end
         
     | 
| 
      
 79 
     | 
    
         
            +
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                    private
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                      def type_incompatible_with_serialize?(type, class_name)
         
     | 
| 
      
 84 
     | 
    
         
            +
                        type.is_a?(ActiveEntity::Type::Json) && class_name == ::JSON ||
         
     | 
| 
      
 85 
     | 
    
         
            +
                          type.respond_to?(:type_cast_array, true) && class_name == ::Array
         
     | 
| 
      
 86 
     | 
    
         
            +
                      end
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
              end
         
     | 
| 
      
 90 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,91 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActiveEntity
         
     | 
| 
      
 4 
     | 
    
         
            +
              module AttributeMethods
         
     | 
| 
      
 5 
     | 
    
         
            +
                module TimeZoneConversion
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class TimeZoneConverter < DelegateClass(Type::Value) # :nodoc:
         
     | 
| 
      
 7 
     | 
    
         
            +
                    def deserialize(value)
         
     | 
| 
      
 8 
     | 
    
         
            +
                      convert_time_to_time_zone(super)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    def cast(value)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      return if value.nil?
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                      if value.is_a?(Hash)
         
     | 
| 
      
 15 
     | 
    
         
            +
                        set_time_zone_without_conversion(super)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      elsif value.respond_to?(:in_time_zone)
         
     | 
| 
      
 17 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 18 
     | 
    
         
            +
                          super(user_input_in_time_zone(value)) || super
         
     | 
| 
      
 19 
     | 
    
         
            +
                        rescue ArgumentError
         
     | 
| 
      
 20 
     | 
    
         
            +
                          nil
         
     | 
| 
      
 21 
     | 
    
         
            +
                        end
         
     | 
| 
      
 22 
     | 
    
         
            +
                      else
         
     | 
| 
      
 23 
     | 
    
         
            +
                        map_avoiding_infinite_recursion(super) { |v| cast(v) }
         
     | 
| 
      
 24 
     | 
    
         
            +
                      end
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    private
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                      def convert_time_to_time_zone(value)
         
     | 
| 
      
 30 
     | 
    
         
            +
                        return if value.nil?
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                        if value.acts_like?(:time)
         
     | 
| 
      
 33 
     | 
    
         
            +
                          value.in_time_zone
         
     | 
| 
      
 34 
     | 
    
         
            +
                        elsif value.is_a?(::Float)
         
     | 
| 
      
 35 
     | 
    
         
            +
                          value
         
     | 
| 
      
 36 
     | 
    
         
            +
                        else
         
     | 
| 
      
 37 
     | 
    
         
            +
                          map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
         
     | 
| 
      
 38 
     | 
    
         
            +
                        end
         
     | 
| 
      
 39 
     | 
    
         
            +
                      end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                      def set_time_zone_without_conversion(value)
         
     | 
| 
      
 42 
     | 
    
         
            +
                        ::Time.zone.local_to_utc(value).try(:in_time_zone) if value
         
     | 
| 
      
 43 
     | 
    
         
            +
                      end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                      def map_avoiding_infinite_recursion(value)
         
     | 
| 
      
 46 
     | 
    
         
            +
                        map(value) do |v|
         
     | 
| 
      
 47 
     | 
    
         
            +
                          if value.equal?(v)
         
     | 
| 
      
 48 
     | 
    
         
            +
                            nil
         
     | 
| 
      
 49 
     | 
    
         
            +
                          else
         
     | 
| 
      
 50 
     | 
    
         
            +
                            yield(v)
         
     | 
| 
      
 51 
     | 
    
         
            +
                          end
         
     | 
| 
      
 52 
     | 
    
         
            +
                        end
         
     | 
| 
      
 53 
     | 
    
         
            +
                      end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 59 
     | 
    
         
            +
                    mattr_accessor :time_zone_aware_attributes, instance_writer: false, default: false
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false, default: []
         
     | 
| 
      
 62 
     | 
    
         
            +
                    class_attribute :time_zone_aware_types, instance_writer: false, default: [ :datetime, :time ]
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  module ClassMethods # :nodoc:
         
     | 
| 
      
 66 
     | 
    
         
            +
                    private
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      def inherited(subclass)
         
     | 
| 
      
 69 
     | 
    
         
            +
                        super
         
     | 
| 
      
 70 
     | 
    
         
            +
                        # We need to apply this decorator here, rather than on module inclusion. The closure
         
     | 
| 
      
 71 
     | 
    
         
            +
                        # created by the matcher would otherwise evaluate for `ActiveEntity::Base`, not the
         
     | 
| 
      
 72 
     | 
    
         
            +
                        # sub class being decorated. As such, changes to `time_zone_aware_attributes`, or
         
     | 
| 
      
 73 
     | 
    
         
            +
                        # `skip_time_zone_conversion_for_attributes` would not be picked up.
         
     | 
| 
      
 74 
     | 
    
         
            +
                        subclass.class_eval do
         
     | 
| 
      
 75 
     | 
    
         
            +
                          matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
         
     | 
| 
      
 76 
     | 
    
         
            +
                          decorate_matching_attribute_types(matcher, "_time_zone_conversion") do |type|
         
     | 
| 
      
 77 
     | 
    
         
            +
                            TimeZoneConverter.new(type)
         
     | 
| 
      
 78 
     | 
    
         
            +
                          end
         
     | 
| 
      
 79 
     | 
    
         
            +
                        end
         
     | 
| 
      
 80 
     | 
    
         
            +
                      end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                      def create_time_zone_conversion_attribute?(name, cast_type)
         
     | 
| 
      
 83 
     | 
    
         
            +
                        enabled_for_column = time_zone_aware_attributes &&
         
     | 
| 
      
 84 
     | 
    
         
            +
                          !skip_time_zone_conversion_for_attributes.include?(name.to_sym)
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                        enabled_for_column && time_zone_aware_types.include?(cast_type.type)
         
     | 
| 
      
 87 
     | 
    
         
            +
                      end
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActiveEntity
         
     | 
| 
      
 4 
     | 
    
         
            +
              module AttributeMethods
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Write
         
     | 
| 
      
 6 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    attribute_method_suffix "="
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  module ClassMethods # :nodoc:
         
     | 
| 
      
 13 
     | 
    
         
            +
                    private
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                      def define_method_attribute=(name)
         
     | 
| 
      
 16 
     | 
    
         
            +
                        ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
         
     | 
| 
      
 17 
     | 
    
         
            +
                          generated_attribute_methods, name, writer: true,
         
     | 
| 
      
 18 
     | 
    
         
            +
                        ) do |temp_method_name, attr_name_expr|
         
     | 
| 
      
 19 
     | 
    
         
            +
                          generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
         
     | 
| 
      
 20 
     | 
    
         
            +
                            def #{temp_method_name}(value)
         
     | 
| 
      
 21 
     | 
    
         
            +
                              name = #{attr_name_expr}
         
     | 
| 
      
 22 
     | 
    
         
            +
                              _write_attribute(name, value)
         
     | 
| 
      
 23 
     | 
    
         
            +
                            end
         
     | 
| 
      
 24 
     | 
    
         
            +
                          RUBY
         
     | 
| 
      
 25 
     | 
    
         
            +
                        end
         
     | 
| 
      
 26 
     | 
    
         
            +
                      end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  # Updates the attribute identified by <tt>attr_name</tt> with the
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # specified +value+. Empty strings for Integer and Float columns are
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # turned into +nil+.
         
     | 
| 
      
 32 
     | 
    
         
            +
                  def write_attribute(attr_name, value)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    name = attr_name.to_s
         
     | 
| 
      
 34 
     | 
    
         
            +
                    if self.class.attribute_alias?(name)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      name = self.class.attribute_alias(name)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    _write_attribute(name, value)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  # This method exists to avoid the expensive primary_key check internally, without
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # breaking compatibility with the write_attribute API
         
     | 
| 
      
 43 
     | 
    
         
            +
                  def _write_attribute(attr_name, value) # :nodoc:
         
     | 
| 
      
 44 
     | 
    
         
            +
                    return if readonly_attribute?(attr_name) && readonly_enabled?
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    @attributes.write_from_user(attr_name.to_s, value)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    value
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  private
         
     | 
| 
      
 51 
     | 
    
         
            +
                    def write_attribute_without_type_cast(attr_name, value)
         
     | 
| 
      
 52 
     | 
    
         
            +
                      name = attr_name.to_s
         
     | 
| 
      
 53 
     | 
    
         
            +
                      @attributes.write_cast_value(name, value)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      value
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    # Handle *= for method_missing.
         
     | 
| 
      
 58 
     | 
    
         
            +
                    def attribute=(attribute_name, value)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      _write_attribute(attribute_name, value)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     |