From 1e6e9f2ee0e1881f908b6b5bc5ae49c439616c99 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Mon, 11 Oct 2021 10:50:13 +0300 Subject: [PATCH] Fix arity check for defaults --- .../dispatchers/prepare_default.rb | 4 +- spec/invalid_default_spec.rb | 78 ++++++++++++++++++- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/lib/dry/initializer/dispatchers/prepare_default.rb b/lib/dry/initializer/dispatchers/prepare_default.rb index c89b30e..35db84e 100644 --- a/lib/dry/initializer/dispatchers/prepare_default.rb +++ b/lib/dry/initializer/dispatchers/prepare_default.rb @@ -26,8 +26,8 @@ def callable!(default) def check_arity!(default) return unless default - arity = default.method(:call).arity.to_i - return unless arity.positive? + arity = default.is_a?(Proc) ? default.arity : default.method(:call).arity + return if arity.equal?(0) || arity.equal?(-1) invalid!(default) end diff --git a/spec/invalid_default_spec.rb b/spec/invalid_default_spec.rb index b15d5b0..fee0069 100644 --- a/spec/invalid_default_spec.rb +++ b/spec/invalid_default_spec.rb @@ -1,4 +1,12 @@ +# frozen_string_literal: true + describe "invalid default value assignment" do + shared_examples "it has a TypeError" do + it "raises TypeError" do + expect { subject }.to raise_error TypeError + end + end + subject do class Test::Foo extend Dry::Initializer @@ -7,7 +15,73 @@ class Test::Foo end end - it "raises TypeError" do - expect { subject }.to raise_error TypeError + it_behaves_like "it has a TypeError" + + context "when default is a lambda one attribute with splat operator" do + subject do + class Test::Foo + extend Dry::Initializer + + param :foo, default: ->(a) { a.to_i } + end + end + + it_behaves_like "it has a TypeError" + end + + context "when default is a proc with attributes" do + subject do + class Test::Foo + extend Dry::Initializer + + param :foo, default: proc { |a| a.to_i } + end + end + + it_behaves_like "it has a TypeError" + end + + context "when default is a callable with attributes" do + subject do + class Test::Callbale + def self.call(a) + a.to_i + end + end + + class Test::Foo + extend Dry::Initializer + + param :foo, default: Test::Callbale + end + end + + it_behaves_like "it has a TypeError" + end + + context "when default is a proc with multiple attributes" do + subject do + class Test::Foo + extend Dry::Initializer + + param :foo, default: proc { |a, *b| a.to_i } + end + end + + it_behaves_like "it has a TypeError" + end + + context "when default is a lambda one attribute with splat operator" do + subject do + class Test::Foo + extend Dry::Initializer + + param :foo, default: ->(*a) { a.size } + end + end + + it "does not raise TypeError" do + expect { subject }.not_to raise_error + end end end