summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorUfuk Kayserilioglu <ufuk@paralaus.com>2022-12-22 02:27:38 +0200
committerGitHub <noreply@github.com>2022-12-21 16:27:38 -0800
commit99cee85775bc5656b942bf4e1b0568a8f40addcd (patch)
tree2411e0b27cfc55a559a50ac28eb1e0acec202e6f /test
parent398aaed2f0e56a81c5c15cc1126b6bbba79ffec0 (diff)
Add copy with changes functionality for Data objects (#6766)
Implements [Feature #19000] This commit adds copy with changes functionality for `Data` objects using a new method `Data#with`. Since Data objects are immutable, the only way to change them is by creating a copy. This PR adds a `with` method for `Data` class instances that optionally takes keyword arguments. If the `with` method is called with no arguments, the behaviour is the same as the `Kernel#dup` method, i.e. a new shallow copy is created with no field values changed. However, if keyword arguments are supplied to the `with` method, then the copy is created with the specified field values changed. For example: ```ruby Point = Data.define(:x, :y) point = Point.new(x: 1, y: 2) point.with(x: 3) # => #<data Point x: 3, y: 2> ``` Passing positional arguments to `with` or passing keyword arguments to it that do not correspond to any of the members of the Data class will raise an `ArgumentError`. Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Notes
Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
Diffstat (limited to 'test')
-rw-r--r--test/ruby/test_data.rb59
1 files changed, 59 insertions, 0 deletions
diff --git a/test/ruby/test_data.rb b/test/ruby/test_data.rb
index 4d28da6061..3cafb365ed 100644
--- a/test/ruby/test_data.rb
+++ b/test/ruby/test_data.rb
@@ -158,6 +158,65 @@ class TestData < Test::Unit::TestCase
assert_not_operator(o1, :eql?, o3)
end
+ def test_with
+ klass = Data.define(:foo, :bar)
+ source = klass.new(foo: 1, bar: 2)
+
+ # Simple
+ test = source.with
+ assert_equal(source.object_id, test.object_id)
+
+ # Changes
+ test = source.with(foo: 10)
+
+ assert_equal(1, source.foo)
+ assert_equal(2, source.bar)
+ assert_equal(source, klass.new(foo: 1, bar: 2))
+
+ assert_equal(10, test.foo)
+ assert_equal(2, test.bar)
+ assert_equal(test, klass.new(foo: 10, bar: 2))
+
+ test = source.with(foo: 10, bar: 20)
+
+ assert_equal(1, source.foo)
+ assert_equal(2, source.bar)
+ assert_equal(source, klass.new(foo: 1, bar: 2))
+
+ assert_equal(10, test.foo)
+ assert_equal(20, test.bar)
+ assert_equal(test, klass.new(foo: 10, bar: 20))
+
+ # Keyword splat
+ changes = { foo: 10, bar: 20 }
+ test = source.with(**changes)
+
+ assert_equal(1, source.foo)
+ assert_equal(2, source.bar)
+ assert_equal(source, klass.new(foo: 1, bar: 2))
+
+ assert_equal(10, test.foo)
+ assert_equal(20, test.bar)
+ assert_equal(test, klass.new(foo: 10, bar: 20))
+
+ # Wrong protocol
+ assert_raise_with_message(ArgumentError, "wrong number of arguments (given 1, expected 0)") do
+ source.with(10)
+ end
+ assert_raise_with_message(ArgumentError, "unknown keywords: :baz, :quux") do
+ source.with(foo: 1, bar: 2, baz: 3, quux: 4)
+ end
+ assert_raise_with_message(ArgumentError, "wrong number of arguments (given 1, expected 0)") do
+ source.with(1, bar: 2)
+ end
+ assert_raise_with_message(ArgumentError, "wrong number of arguments (given 2, expected 0)") do
+ source.with(1, 2)
+ end
+ assert_raise_with_message(ArgumentError, "wrong number of arguments (given 1, expected 0)") do
+ source.with({ bar: 2 })
+ end
+ end
+
def test_memberless
klass = Data.define