diff options
author | Sean Griffin <sean@seantheprogrammer.com> | 2017-10-23 14:48:46 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-23 14:48:46 -0400 |
commit | b7912a30402a6958b4e10c2ed90c9098db1715c9 (patch) | |
tree | fe31063da966024f1223f3b22405e80389cf6bc6 /activemodel/lib | |
parent | 9439c454ac7bbef828c767eb1ecd2d169098ee1e (diff) | |
parent | 7e9ded512dd58a923a3be038843708dbba4215f6 (diff) | |
download | rails-b7912a30402a6958b4e10c2ed90c9098db1715c9.tar.gz rails-b7912a30402a6958b4e10c2ed90c9098db1715c9.tar.bz2 rails-b7912a30402a6958b4e10c2ed90c9098db1715c9.zip |
Merge pull request #30920 from lugray/attributes_to_am
Start bringing attributes API to AM
Diffstat (limited to 'activemodel/lib')
-rw-r--r-- | activemodel/lib/active_model/attributes.rb | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/activemodel/lib/active_model/attributes.rb b/activemodel/lib/active_model/attributes.rb new file mode 100644 index 0000000000..3e34d3b83a --- /dev/null +++ b/activemodel/lib/active_model/attributes.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require "active_model/type" + +module ActiveModel + module Attributes #:nodoc: + extend ActiveSupport::Concern + include ActiveModel::AttributeMethods + include ActiveModel::Dirty + + included do + attribute_method_suffix "=" + class_attribute :attribute_types, :_default_attributes, instance_accessor: false + self.attribute_types = {} + self._default_attributes = {} + end + + module ClassMethods + def attribute(name, cast_type = Type::Value.new, **options) + self.attribute_types = attribute_types.merge(name.to_s => cast_type) + self._default_attributes = _default_attributes.merge(name.to_s => options[:default]) + define_attribute_methods(name) + end + + private + + def define_method_attribute=(name) + safe_name = name.unpack("h*".freeze).first + ActiveModel::AttributeMethods::AttrNames.set_name_cache safe_name, name + + generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 + def __temp__#{safe_name}=(value) + name = ::ActiveModel::AttributeMethods::AttrNames::ATTR_#{safe_name} + write_attribute(name, value) + end + alias_method #{(name + '=').inspect}, :__temp__#{safe_name}= + undef_method :__temp__#{safe_name}= + STR + end + end + + def initialize(*) + super + clear_changes_information + end + + private + + def write_attribute(attr_name, value) + name = if self.class.attribute_alias?(attr_name) + self.class.attribute_alias(attr_name).to_s + else + attr_name.to_s + end + + cast_type = self.class.attribute_types[name] + + deserialized_value = ActiveModel::Type.lookup(cast_type).cast(value) + attribute_will_change!(name) unless deserialized_value == attribute(name) + instance_variable_set("@#{name}", deserialized_value) + deserialized_value + end + + def attribute(name) + if instance_variable_defined?("@#{name}") + instance_variable_get("@#{name}") + else + default = self.class._default_attributes[name] + default.respond_to?(:call) ? default.call : default + end + end + + # Handle *= for method_missing. + def attribute=(attribute_name, value) + write_attribute(attribute_name, value) + end + end + + module AttributeMethods #:nodoc: + AttrNames = Module.new { + def self.set_name_cache(name, value) + const_name = "ATTR_#{name}" + unless const_defined? const_name + const_set const_name, value.dup.freeze + end + end + } + end +end |