diff --git a/lib/interactor.rb b/lib/interactor.rb index 8cf246f..0109494 100644 --- a/lib/interactor.rb +++ b/lib/interactor.rb @@ -166,24 +166,22 @@ def rollback private - # Internal: Determine what arguments (if any) should be passed to the "call" - # instance method when invoking an Interactor. The "call" instance method may - # accept any combination of positional and keyword arguments. This method - # will extract values from the context in order to populate those arguments - # based on their names. + # Internal: Determine what keyword arguments (if any) should be passed to the + # "call" instance method when invoking an Interactor. The "call" instance + # method may accept any number of keyword arguments. This method will extract + # values from the context in order to populate those arguments based on their + # names. # # Returns an Array of arguments to be applied as an argument list. - def arguments_for_call # rubocop:disable Metrics/MethodLength + def arguments_for_call positional_arguments = [] keyword_arguments = {} method(:call).parameters.each do |(type, name)| + next unless type == :keyreq || type == :key next unless context.include?(name) - case type - when :req, :opt then positional_arguments << context[name] - when :keyreq, :key then keyword_arguments[name] = context[name] - end + keyword_arguments[name] = context[name] end positional_arguments << keyword_arguments if keyword_arguments.any? diff --git a/spec/interactor_spec.rb b/spec/interactor_spec.rb index 2153bfc..d85b8db 100644 --- a/spec/interactor_spec.rb +++ b/spec/interactor_spec.rb @@ -4,54 +4,6 @@ describe "#call" do let(:interactor) { Class.new.send(:include, described_class) } - context "positional arguments" do - it "accepts required positional arguments" do - interactor.class_eval do - def call(foo) - context.output = foo - end - end - - result = interactor.call(foo: "baz", hello: "world") - - expect(result.output).to eq("baz") - end - - it "accepts optional positional arguments" do - interactor.class_eval do - def call(foo = "bar") - context.output = foo - end - end - - result = interactor.call(foo: "baz", hello: "world") - - expect(result.output).to eq("baz") - end - - it "assigns absent positional arguments" do - interactor.class_eval do - def call(foo = "bar") - context.output = foo - end - end - - result = interactor.call(hello: "world") - - expect(result.output).to eq("bar") - end - - it "raises an error for missing positional arguments" do - interactor.class_eval do - def call(foo) - context.output = foo - end - end - - expect { interactor.call(hello: "world") }.to raise_error(ArgumentError) - end - end - context "keyword arguments" do it "accepts required keyword arguments" do interactor.class_eval do @@ -60,9 +12,9 @@ def call(foo:) end end - result = interactor.call(foo: "baz", hello: "world") + result = interactor.call(foo: "bar", hello: "world") - expect(result.output).to eq("baz") + expect(result.output).to eq("bar") end it "accepts optional keyword arguments" do @@ -98,115 +50,15 @@ def call(foo:) expect { interactor.call(hello: "world") }.to raise_error(ArgumentError) end - end - - context "combination arguments" do - it "accepts required positional with required keyword arguments" do - interactor.class_eval do - def call(foo, hello:) - context.output = [foo, hello] - end - end - - result = interactor.call(foo: "baz", hello: "world") - - expect(result.output).to eq(["baz", "world"]) - end - - it "accepts required positional with optional keyword arguments" do - interactor.class_eval do - def call(foo, hello: "there") - context.output = [foo, hello] - end - end - - result = interactor.call(foo: "baz", hello: "world") - - expect(result.output).to eq(["baz", "world"]) - end - - it "accepts required positional and assigns absent keyword arguments" do - interactor.class_eval do - def call(foo, hello: "there") - context.output = [foo, hello] - end - end - - result = interactor.call(foo: "baz") - - expect(result.output).to eq(["baz", "there"]) - end - - it "accepts optional positional with required keyword arguments" do - interactor.class_eval do - def call(foo = "bar", hello:) - context.output = [foo, hello] - end - end - - result = interactor.call(foo: "baz", hello: "world") - - expect(result.output).to eq(["baz", "world"]) - end - it "accepts optional positional with optional keyword arguments" do + it "raises an error for call definitions with non-keyword arguments" do interactor.class_eval do - def call(foo = "bar", hello: "there") - context.output = [foo, hello] - end - end - - result = interactor.call(foo: "baz", hello: "world") - - expect(result.output).to eq(["baz", "world"]) - end - - it "accepts optional positional and assigns absent keyword arguments" do - interactor.class_eval do - def call(foo = "bar", hello: "there") - context.output = [foo, hello] - end - end - - result = interactor.call(foo: "baz") - - expect(result.output).to eq(["baz", "there"]) - end - - it "assigns absent positional and accepts required keyword arguments" do - interactor.class_eval do - def call(foo = "bar", hello:) - context.output = [foo, hello] - end - end - - result = interactor.call(hello: "world") - - expect(result.output).to eq(["bar", "world"]) - end - - it "assigns absent positional and accepts optional keyword arguments" do - interactor.class_eval do - def call(foo = "bar", hello: "there") - context.output = [foo, hello] - end - end - - result = interactor.call(hello: "world") - - expect(result.output).to eq(["bar", "world"]) - end - - it "assigns absent positional and absent keyword arguments" do - interactor.class_eval do - def call(foo = "bar", hello: "there") - context.output = [foo, hello] + def call(foo) + context.output = foo end end - result = interactor.call - - expect(result.output).to eq(["bar", "there"]) + expect { interactor.call(foo: "bar") }.to raise_error(ArgumentError) end end end