From 08095927ea03c60a00eb3b0d0323458b482827b0 Mon Sep 17 00:00:00 2001 From: Marian13 Date: Thu, 2 Feb 2023 00:04:07 +0200 Subject: [PATCH] fix(copyable): do not mutate input params --- lib/convenient_service/support/copyable.rb | 8 ++++-- .../support/copyable_spec.rb | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/convenient_service/support/copyable.rb b/lib/convenient_service/support/copyable.rb index de5eca1f9ea..c08f6103b4b 100644 --- a/lib/convenient_service/support/copyable.rb +++ b/lib/convenient_service/support/copyable.rb @@ -20,8 +20,12 @@ module Copyable # NOTE: This method is NOT likely to be ever changed, that is why inline logic is preferred over command classes in this particular case. # def copy(overrides: {}) - overrides[:args] ||= {} - overrides[:kwargs] ||= {} + defaults = {args: {}, kwargs: {}} + + ## + # IMPORTANT: Do not mutate `overrides`. + # + overrides = defaults.merge(overrides) ## # TODO: Refactor runtime `respond_to?`. Investigate before refactoring. diff --git a/spec/lib/convenient_service/support/copyable_spec.rb b/spec/lib/convenient_service/support/copyable_spec.rb index 5ae3de96645..e5b5e184b84 100644 --- a/spec/lib/convenient_service/support/copyable_spec.rb +++ b/spec/lib/convenient_service/support/copyable_spec.rb @@ -83,6 +83,14 @@ def to_block expect(instance).to have_received(:to_block) end + context "when `overrides[:args]` is NOT passed" do + let(:overrides) { {} } + + it "defaults to empty hash`" do + expect(instance.copy(overrides: overrides).args).to eq(constructor_params[:args]) + end + end + context "when `overrides[:args]` is passed" do context "when `overrides[:args]` is array" do let(:overrides) { {args: [:baz, :qux]} } @@ -109,6 +117,14 @@ def to_block end end + context "when `overrides[:kwargs]` is NOT passed" do + let(:overrides) { {} } + + it "defaults to empty hash`" do + expect(instance.copy(overrides: overrides).kwargs).to eq(constructor_params[:kwargs]) + end + end + context "when `overrides[:kwargs]` is passed" do let(:overrides) { {kwargs: {foo: 3, bar: 4}} } @@ -125,6 +141,16 @@ def to_block end end + context "when `overrides` is passed" do + let(:overrides) { {block: proc { :bar }} } + + it "does NOT mutate `overrides`" do + overrides.freeze + + expect { instance.copy(overrides: overrides) }.not_to raise_error(FrozenError) + end + end + context "when `to_args` is NOT implemented" do let(:klass) do Class.new(base_class) do