diff options
Diffstat (limited to 'activemodel')
-rw-r--r-- | activemodel/lib/active_model/type.rb | 2 | ||||
-rw-r--r-- | activemodel/lib/active_model/type/immutable_string.rb | 28 | ||||
-rw-r--r-- | activemodel/lib/active_model/type/string.rb | 28 | ||||
-rw-r--r-- | activemodel/test/cases/type/string_test.rb | 7 |
4 files changed, 45 insertions, 20 deletions
diff --git a/activemodel/lib/active_model/type.rb b/activemodel/lib/active_model/type.rb index f8ca7d0512..bec851594f 100644 --- a/activemodel/lib/active_model/type.rb +++ b/activemodel/lib/active_model/type.rb @@ -9,6 +9,7 @@ require 'active_model/type/date_time' require 'active_model/type/decimal' require 'active_model/type/decimal_without_scale' require 'active_model/type/float' +require 'active_model/type/immutable_string' require 'active_model/type/integer' require 'active_model/type/string' require 'active_model/type/text' @@ -49,6 +50,7 @@ module ActiveModel register(:date_time, Type::DateTime) register(:decimal, Type::Decimal) register(:float, Type::Float) + register(:immutable_string, Type::ImmutableString) register(:integer, Type::Integer) register(:string, Type::String) register(:text, Type::Text) diff --git a/activemodel/lib/active_model/type/immutable_string.rb b/activemodel/lib/active_model/type/immutable_string.rb new file mode 100644 index 0000000000..cfa4b3fb4b --- /dev/null +++ b/activemodel/lib/active_model/type/immutable_string.rb @@ -0,0 +1,28 @@ +module ActiveModel + module Type + class ImmutableString < Value # :nodoc: + def type + :string + end + + def serialize(value) + case value + when ::Numeric, ActiveSupport::Duration then value.to_s + when true then "t" + when false then "f" + else super + end + end + + private + + def cast_value(value) + case value + when true then "t" + when false then "f" + else value.to_s.freeze + end + end + end + end +end diff --git a/activemodel/lib/active_model/type/string.rb b/activemodel/lib/active_model/type/string.rb index fd1630c751..4c8dc15778 100644 --- a/activemodel/lib/active_model/type/string.rb +++ b/activemodel/lib/active_model/type/string.rb @@ -1,34 +1,22 @@ +require "active_model/type/immutable_string" + module ActiveModel module Type - class String < Value # :nodoc: - def type - :string - end - + class String < ImmutableString # :nodoc: def changed_in_place?(raw_old_value, new_value) if new_value.is_a?(::String) raw_old_value != new_value end end - def serialize(value) - case value - when ::Numeric, ActiveSupport::Duration then value.to_s - when ::String then ::String.new(value) - when true then "t" - when false then "f" - else super - end - end - private def cast_value(value) - case value - when true then "t" - when false then "f" - # String.new is slightly faster than dup - else ::String.new(value.to_s) + result = super + if ::String === result + ::String.new(result) + else + result end end end diff --git a/activemodel/test/cases/type/string_test.rb b/activemodel/test/cases/type/string_test.rb index 8ec771ea42..7b25a1ef74 100644 --- a/activemodel/test/cases/type/string_test.rb +++ b/activemodel/test/cases/type/string_test.rb @@ -10,6 +10,13 @@ module ActiveModel assert_equal "123", type.cast(123) end + test "immutable strings are not duped coming out" do + s = "foo" + type = Type::ImmutableString.new + assert_same s, type.cast(s) + assert_same s, type.deserialize(s) + end + test "values are duped coming out" do s = "foo" type = Type::String.new |