Skip to content

Commit 8bdf5e3

Browse files
authored
Merge pull request rails#48106 from Shopify/deep-dup-modules
`Object#deep_dup` no longer duplicate named classes and modules.
2 parents b717a5a + 2fd61a9 commit 8bdf5e3

File tree

4 files changed

+70
-2
lines changed

4 files changed

+70
-2
lines changed

activerecord/test/cases/serialized_attribute_test.rb

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
class SerializedAttributeTest < ActiveRecord::TestCase
1010
def setup
1111
ActiveRecord.use_yaml_unsafe_load = true
12+
@yaml_column_permitted_classes_default = ActiveRecord.yaml_column_permitted_classes
13+
end
14+
15+
def teardown
16+
Topic.serialize("content")
17+
ActiveRecord.yaml_column_permitted_classes = @yaml_column_permitted_classes_default
1218
end
1319

1420
fixtures :topics, :posts
@@ -23,8 +29,8 @@ class ImportantTopic < Topic
2329
serialize :important, type: Hash
2430
end
2531

26-
teardown do
27-
Topic.serialize("content")
32+
class ClassifiedTopic < Topic
33+
serialize :important, type: Class
2834
end
2935

3036
def test_serialize_does_not_eagerly_load_columns
@@ -166,6 +172,14 @@ def test_serialized_string_attribute
166172
assert_equal(myobj, topic.content)
167173
end
168174

175+
def test_serialized_class_attribute
176+
ActiveRecord.yaml_column_permitted_classes += [Class]
177+
178+
topic = ClassifiedTopic.create(important: Symbol).reload
179+
assert_equal(Symbol, topic.important)
180+
assert_not_empty ClassifiedTopic.where(important: Symbol)
181+
end
182+
169183
def test_nil_serialized_attribute_without_class_constraint
170184
topic = Topic.new
171185
assert_nil topic.content
@@ -551,9 +565,17 @@ def test_serialized_attribute_works_under_concurrent_initial_access
551565

552566
class SerializedAttributeTestWithYamlSafeLoad < SerializedAttributeTest
553567
def setup
568+
@use_yaml_unsafe_load = ActiveRecord.use_yaml_unsafe_load
569+
@yaml_column_permitted_classes_default = ActiveRecord.yaml_column_permitted_classes
554570
ActiveRecord.use_yaml_unsafe_load = false
555571
end
556572

573+
def teardown
574+
Topic.serialize("content")
575+
ActiveRecord.yaml_column_permitted_classes = @yaml_column_permitted_classes_default
576+
ActiveRecord.use_yaml_unsafe_load = @use_yaml_unsafe_load
577+
end
578+
557579
def test_serialized_attribute
558580
Topic.serialize("content", type: String)
559581

activesupport/CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
* `Object#deep_dup` no longer duplicate named classes and modules.
2+
3+
Before:
4+
5+
```ruby
6+
hash = { class: Object, module: Kernel }
7+
hash.deep_dup # => {:class=>#<Class:0x00000001063ffc80>, :module=>#<Module:0x00000001063ffa00>}
8+
```
9+
10+
After:
11+
12+
```ruby
13+
hash = { class: Object, module: Kernel }
14+
hash.deep_dup # => {:class=>Object, :module=>Kernel}
15+
```
16+
17+
*Jean Boussier*
18+
119
* Consistently raise an `ArgumentError` if the `ActiveSupport::Cache` key is blank.
220

321
*Joshua Young*

activesupport/lib/active_support/core_ext/object/deep_dup.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,19 @@ def deep_dup
5353
hash
5454
end
5555
end
56+
57+
class Module
58+
# Returns a copy of module or class if it's anonymous. If it's
59+
# named, returns +self+.
60+
#
61+
# Object.deep_dup == Object # => true
62+
# klass = Class.new
63+
# klass.deep_dup == klass # => false
64+
def deep_dup
65+
if name.nil?
66+
super
67+
else
68+
self
69+
end
70+
end
71+
end

activesupport/test/core_ext/object/deep_dup_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,16 @@ def test_deep_dup_with_mutable_frozen_key
6666

6767
assert_not_equal hash.keys, dup.keys
6868
end
69+
70+
def test_named_modules_arent_duped
71+
hash = { class: Object, module: Kernel }
72+
assert_equal hash, hash.deep_dup
73+
end
74+
75+
def test_anonymous_modules_are_duped
76+
hash = { class: Class.new, module: Module.new }
77+
duped_hash = hash.deep_dup
78+
assert_not_equal hash[:class], duped_hash[:class]
79+
assert_not_equal hash[:module], duped_hash[:module]
80+
end
6981
end

0 commit comments

Comments
 (0)