diff --git a/CHANGELOG.md b/CHANGELOG.md index 70dcce6..89b3630 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.9.1 + +### Bug fixes + +- Prevent mutable default options from being shared across instances. + ## 0.9.0 ### New features @@ -21,6 +27,7 @@ ## 0.8.1 ## Maintenance + - Loosen the ActiveSupport dependency version to prepare for Rails 7. ## 0.8.0 diff --git a/Gemfile.lock b/Gemfile.lock index 0d3cb90..e119590 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,24 +1,23 @@ PATH remote: . specs: - stimpack (0.8.3) + stimpack (0.9.1) activesupport (>= 6.1) GEM remote: https://rubygems.org/ specs: - activesupport (6.1.4.1) + activesupport (7.0.2.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - zeitwerk (~> 2.3) ast (2.4.2) concurrent-ruby (1.1.9) diff-lcs (1.4.4) - i18n (1.8.10) + i18n (1.10.0) concurrent-ruby (~> 1.0) - minitest (5.14.4) + minitest (5.15.0) parallel (1.20.1) parser (3.0.0.0) ast (~> 2.4.1) @@ -54,7 +53,6 @@ GEM tzinfo (2.0.4) concurrent-ruby (~> 1.0) unicode-display_width (2.0.0) - zeitwerk (2.5.1) PLATFORMS x86_64-darwin-19 diff --git a/lib/stimpack/options_declaration/option.rb b/lib/stimpack/options_declaration/option.rb index 7a07349..8f1410b 100644 --- a/lib/stimpack/options_declaration/option.rb +++ b/lib/stimpack/options_declaration/option.rb @@ -23,7 +23,7 @@ def initialize(name, required:, default:, transform:) def default_value return nil unless default? - default.respond_to?(:call) ? default.() : default + default.respond_to?(:call) ? default.() : default.dup end def transformed_value(value) diff --git a/lib/stimpack/version.rb b/lib/stimpack/version.rb index 3301ca1..efdac0f 100644 --- a/lib/stimpack/version.rb +++ b/lib/stimpack/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Stimpack - VERSION = "0.9.0" + VERSION = "0.9.1" end diff --git a/spec/stimpack/event_source_spec.rb b/spec/stimpack/event_source_spec.rb index 9c48202..c0c6057 100644 --- a/spec/stimpack/event_source_spec.rb +++ b/spec/stimpack/event_source_spec.rb @@ -37,12 +37,12 @@ def self.to_s end describe ".on" do - context "with single event" do + context "with single event" do it { expect { service.on(:foo) {} }.to change { klass.event_listeners["Foo.foo"].size }.by(1) } end context "with multiple events" do - it { expect { service.on(:foo, :bar, :qux) {} }.to change { klass.event_listeners["Foo.foo"].size }.by(1).and change { klass.event_listeners["Foo.bar"].size }.by(1).and change { klass.event_listeners["Foo.qux"].size }.by(1) } + it { expect { service.on(:foo, :bar, :qux) {} }.to change { klass.event_listeners["Foo.foo"].size }.by(1).and change { klass.event_listeners["Foo.bar"].size }.by(1).and change { klass.event_listeners["Foo.qux"].size }.by(1) } # rubocop:disable Layout/LineLength end end diff --git a/spec/stimpack/options_declaration_spec.rb b/spec/stimpack/options_declaration_spec.rb index 4e02269..b99c4c1 100644 --- a/spec/stimpack/options_declaration_spec.rb +++ b/spec/stimpack/options_declaration_spec.rb @@ -19,24 +19,29 @@ option :grault, default: "bar", transform: ->(value) { value.upcase } option :garply, default: "baz", transform: :upcase option :waldo, required: false, transform: :to_sym + option :plugh, default: [] + + def call + plugh << "Hello" + end end end describe ".option" do - it { expect(service.options_configuration.size).to eq(10) } + it { expect(service.options_configuration.size).to eq(11) } it { expect(service.options_configuration.values).to all(be_a(described_class::Option)) } describe "private_reader (option)" do let(:public_instance_methods) { service.public_instance_methods(false) } let(:private_instance_methods) { service.private_instance_methods(false) } - it { expect(public_instance_methods).to contain_exactly(:baz) } - it { expect(private_instance_methods).to contain_exactly(:foo, :bar, :qux, :quux, :quuz, :corge, :grault, :garply, :waldo) } # rubocop:disable Layout/LineLength + it { expect(public_instance_methods).to include(:baz) } + it { expect(private_instance_methods).to include(:foo, :bar, :qux, :quux, :quuz, :corge, :grault, :garply, :waldo, :plugh) } # rubocop:disable Layout/LineLength end end describe ".options" do - it { expect(service.options).to contain_exactly(:foo, :bar, :baz, :qux, :quux, :quuz, :corge, :grault, :garply, :waldo) } # rubocop:disable Layout/LineLength + it { expect(service.options).to contain_exactly(:foo, :bar, :baz, :qux, :quux, :quuz, :corge, :grault, :garply, :waldo, :plugh) } # rubocop:disable Layout/LineLength end describe ".required_options" do @@ -44,11 +49,11 @@ end describe ".optional_options" do - it { expect(service.optional_options).to contain_exactly(:bar, :qux, :quux, :quuz, :grault, :garply, :waldo) } + it { expect(service.optional_options).to contain_exactly(:bar, :qux, :quux, :quuz, :grault, :garply, :waldo, :plugh) } # rubocop:disable Layout/LineLength end describe ".default_options" do - it { expect(service.default_options).to contain_exactly(:qux, :quux, :quuz, :grault, :garply) } + it { expect(service.default_options).to contain_exactly(:qux, :quux, :quuz, :grault, :garply, :plugh) } end describe "#initialize" do @@ -100,6 +105,12 @@ it { expect(instance.send(:quuz)).to eq(nil) } end + context "when default option is a mutable object" do + before { klass.new(foo: "1", baz: "2", corge: "3").() } + + it { expect(instance.send(:plugh)).to eq([]) } + end + context "when transform is applied to user input" do it { expect(instance.send(:corge)).to eq("FOO") } end