diff --git a/activemodel/lib/active_model/attributes.rb b/activemodel/lib/active_model/attributes.rb deleted file mode 100644 index 046ae67ad7b31..0000000000000 --- a/activemodel/lib/active_model/attributes.rb +++ /dev/null @@ -1,107 +0,0 @@ -# frozen_string_literal: true - -require "active_model/attribute_set" -require "active_model/attribute/user_provided_default" - -module ActiveModel - module Attributes #:nodoc: - extend ActiveSupport::Concern - include ActiveModel::AttributeMethods - - included do - attribute_method_suffix "=" - class_attribute :attribute_types, :_default_attributes, instance_accessor: false - self.attribute_types = Hash.new(Type.default_value) - self._default_attributes = AttributeSet.new({}) - end - - module ClassMethods - def attribute(name, type = Type::Value.new, **options) - name = name.to_s - if type.is_a?(Symbol) - type = ActiveModel::Type.lookup(type, **options.except(:default)) - end - self.attribute_types = attribute_types.merge(name => type) - define_default_attribute(name, options.fetch(:default, NO_DEFAULT_PROVIDED), type) - define_attribute_method(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 - - NO_DEFAULT_PROVIDED = Object.new # :nodoc: - private_constant :NO_DEFAULT_PROVIDED - - def define_default_attribute(name, value, type) - self._default_attributes = _default_attributes.deep_dup - if value == NO_DEFAULT_PROVIDED - default_attribute = _default_attributes[name].with_type(type) - else - default_attribute = Attribute::UserProvidedDefault.new( - name, - value, - type, - _default_attributes.fetch(name.to_s) { nil }, - ) - end - _default_attributes[name] = default_attribute - end - end - - def initialize(*) - @attributes = self.class._default_attributes.deep_dup - super - 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 - - @attributes.write_from_user(name, value) - value - end - - def attribute(attr_name) - name = if self.class.attribute_alias?(attr_name) - self.class.attribute_alias(attr_name).to_s - else - attr_name.to_s - end - @attributes.fetch_value(name) - 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 diff --git a/activemodel/test/cases/attributes_dirty_test.rb b/activemodel/test/cases/attributes_dirty_test.rb deleted file mode 100644 index c991176389c68..0000000000000 --- a/activemodel/test/cases/attributes_dirty_test.rb +++ /dev/null @@ -1,205 +0,0 @@ -# frozen_string_literal: true - -require "cases/helper" - -class AttributesDirtyTest < ActiveModel::TestCase - class DirtyModel - include ActiveModel::Model - include ActiveModel::Attributes - include ActiveModel::Dirty - attribute :name, :string - attribute :color, :string - attribute :size, :integer - - def save - changes_applied - end - - def reload - clear_changes_information - end - end - - setup do - @model = DirtyModel.new - end - - test "setting attribute will result in change" do - assert_not_predicate @model, :changed? - assert_not_predicate @model, :name_changed? - @model.name = "Ringo" - assert_predicate @model, :changed? - assert_predicate @model, :name_changed? - end - - test "list of changed attribute keys" do - assert_equal [], @model.changed - @model.name = "Paul" - assert_equal ["name"], @model.changed - end - - test "changes to attribute values" do - assert !@model.changes["name"] - @model.name = "John" - assert_equal [nil, "John"], @model.changes["name"] - end - - test "checking if an attribute has changed to a particular value" do - @model.name = "Ringo" - assert @model.name_changed?(from: nil, to: "Ringo") - assert_not @model.name_changed?(from: "Pete", to: "Ringo") - assert @model.name_changed?(to: "Ringo") - assert_not @model.name_changed?(to: "Pete") - assert @model.name_changed?(from: nil) - assert_not @model.name_changed?(from: "Pete") - end - - test "changes accessible through both strings and symbols" do - @model.name = "David" - assert_not_nil @model.changes[:name] - assert_not_nil @model.changes["name"] - end - - test "be consistent with symbols arguments after the changes are applied" do - @model.name = "David" - assert @model.attribute_changed?(:name) - @model.save - @model.name = "Rafael" - assert @model.attribute_changed?(:name) - end - - test "attribute mutation" do - @model.name = "Yam" - @model.save - assert_not_predicate @model, :name_changed? - @model.name.replace("Hadad") - assert_predicate @model, :name_changed? - end - - test "resetting attribute" do - @model.name = "Bob" - @model.restore_name! - assert_nil @model.name - assert_not_predicate @model, :name_changed? - end - - test "setting color to same value should not result in change being recorded" do - @model.color = "red" - assert_predicate @model, :color_changed? - @model.save - assert_not_predicate @model, :color_changed? - assert_not_predicate @model, :changed? - @model.color = "red" - assert_not_predicate @model, :color_changed? - assert_not_predicate @model, :changed? - end - - test "saving should reset model's changed status" do - @model.name = "Alf" - assert_predicate @model, :changed? - @model.save - assert_not_predicate @model, :changed? - assert_not_predicate @model, :name_changed? - end - - test "saving should preserve previous changes" do - @model.name = "Jericho Cane" - @model.save - assert_equal [nil, "Jericho Cane"], @model.previous_changes["name"] - end - - test "setting new attributes should not affect previous changes" do - @model.name = "Jericho Cane" - @model.save - @model.name = "DudeFella ManGuy" - assert_equal [nil, "Jericho Cane"], @model.name_previous_change - end - - test "saving should preserve model's previous changed status" do - @model.name = "Jericho Cane" - @model.save - assert_predicate @model, :name_previously_changed? - end - - test "previous value is preserved when changed after save" do - assert_equal({}, @model.changed_attributes) - @model.name = "Paul" - assert_equal({ "name" => nil }, @model.changed_attributes) - - @model.save - - @model.name = "John" - assert_equal({ "name" => "Paul" }, @model.changed_attributes) - end - - test "changing the same attribute multiple times retains the correct original value" do - @model.name = "Otto" - @model.save - @model.name = "DudeFella ManGuy" - @model.name = "Mr. Manfredgensonton" - assert_equal ["Otto", "Mr. Manfredgensonton"], @model.name_change - assert_equal @model.name_was, "Otto" - end - - test "using attribute_will_change! with a symbol" do - @model.size = 1 - assert_predicate @model, :size_changed? - end - - test "reload should reset all changes" do - @model.name = "Dmitry" - @model.name_changed? - @model.save - @model.name = "Bob" - - assert_equal [nil, "Dmitry"], @model.previous_changes["name"] - assert_equal "Dmitry", @model.changed_attributes["name"] - - @model.reload - - assert_equal ActiveSupport::HashWithIndifferentAccess.new, @model.previous_changes - assert_equal ActiveSupport::HashWithIndifferentAccess.new, @model.changed_attributes - end - - test "restore_attributes should restore all previous data" do - @model.name = "Dmitry" - @model.color = "Red" - @model.save - @model.name = "Bob" - @model.color = "White" - - @model.restore_attributes - - assert_not_predicate @model, :changed? - assert_equal "Dmitry", @model.name - assert_equal "Red", @model.color - end - - test "restore_attributes can restore only some attributes" do - @model.name = "Dmitry" - @model.color = "Red" - @model.save - @model.name = "Bob" - @model.color = "White" - - @model.restore_attributes(["name"]) - - assert_predicate @model, :changed? - assert_equal "Dmitry", @model.name - assert_equal "White", @model.color - end - - test "changing the attribute reports a change only when the cast value changes" do - @model.size = "2.3" - @model.save - @model.size = "2.1" - - assert_equal false, @model.changed? - - @model.size = "5.1" - - assert_equal true, @model.changed? - assert_equal true, @model.size_changed? - assert_equal({ "size" => [2, 5] }, @model.changes) - end -end diff --git a/activemodel/test/cases/attributes_test.rb b/activemodel/test/cases/attributes_test.rb deleted file mode 100644 index 7c1d813ce022c..0000000000000 --- a/activemodel/test/cases/attributes_test.rb +++ /dev/null @@ -1,77 +0,0 @@ -# frozen_string_literal: true - -require "cases/helper" - -module ActiveModel - class AttributesTest < ActiveModel::TestCase - class ModelForAttributesTest - include ActiveModel::Model - include ActiveModel::Attributes - - attribute :integer_field, :integer - attribute :string_field, :string - attribute :decimal_field, :decimal - attribute :string_with_default, :string, default: "default string" - attribute :date_field, :date, default: -> { Date.new(2016, 1, 1) } - attribute :boolean_field, :boolean - end - - class ChildModelForAttributesTest < ModelForAttributesTest - end - - class GrandchildModelForAttributesTest < ChildModelForAttributesTest - attribute :integer_field, :string - end - - test "properties assignment" do - data = ModelForAttributesTest.new( - integer_field: "2.3", - string_field: "Rails FTW", - decimal_field: "12.3", - boolean_field: "0" - ) - - assert_equal 2, data.integer_field - assert_equal "Rails FTW", data.string_field - assert_equal BigDecimal("12.3"), data.decimal_field - assert_equal "default string", data.string_with_default - assert_equal Date.new(2016, 1, 1), data.date_field - assert_equal false, data.boolean_field - - data.integer_field = 10 - data.string_with_default = nil - data.boolean_field = "1" - - assert_equal 10, data.integer_field - assert_nil data.string_with_default - assert_equal true, data.boolean_field - end - - test "nonexistent attribute" do - assert_raise ActiveModel::UnknownAttributeError do - ModelForAttributesTest.new(nonexistent: "nonexistent") - end - end - - test "children inherit attributes" do - data = ChildModelForAttributesTest.new(integer_field: "4.4") - - assert_equal 4, data.integer_field - end - - test "children can override parents" do - data = GrandchildModelForAttributesTest.new(integer_field: "4.4") - - assert_equal "4.4", data.integer_field - end - - test "attributes with proc defaults can be marshalled" do - data = ModelForAttributesTest.new - attributes = data.instance_variable_get(:@attributes) - round_tripped = Marshal.load(Marshal.dump(data)) - new_attributes = round_tripped.instance_variable_get(:@attributes) - - assert_equal attributes, new_attributes - end - end -end