-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow developers to define #call with arguments for convenience #135
Changes from all commits
0d6ab9f
822c2a4
cf6b273
a0b9688
27af274
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,7 +140,7 @@ def run | |
# Raises Interactor::Failure if the context is failed. | ||
def run! | ||
with_hooks do | ||
call | ||
call(*arguments_for_call) | ||
context.called!(self) | ||
end | ||
rescue | ||
|
@@ -163,4 +163,28 @@ def call | |
# Returns nothing. | ||
def rollback | ||
end | ||
|
||
private | ||
|
||
# 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 | ||
positional_arguments = [] | ||
keyword_arguments = {} | ||
|
||
method(:call).parameters.each do |(type, name)| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think should be here: |
||
next unless type == :keyreq || type == :key | ||
next unless context.include?(name) | ||
|
||
keyword_arguments[name] = context[name] | ||
end | ||
|
||
positional_arguments << keyword_arguments if keyword_arguments.any? | ||
positional_arguments | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,7 +121,7 @@ def failure? | |
# | ||
# Raises Interactor::Failure initialized with the Interactor::Context. | ||
def fail!(context = {}) | ||
context.each { |key, value| modifiable[key.to_sym] = value } | ||
context.each { |key, value| self[key] = value } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
@failure = true | ||
raise Failure, self | ||
end | ||
|
@@ -158,6 +158,15 @@ def rollback! | |
@rolled_back = true | ||
end | ||
|
||
# Public: Check for the presence of a given key in the context. This does | ||
# not check whether the value is truthy, just whether the key is set to any | ||
# value at all. | ||
# | ||
# Returns true if the key is found or false otherwise. | ||
def include?(key) | ||
table.include?(key.to_sym) | ||
end | ||
|
||
# Internal: An Array of successfully called Interactor instances invoked | ||
# against this Interactor::Context instance. | ||
# | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,65 @@ | ||
describe Interactor do | ||
include_examples :lint | ||
|
||
describe "#call" do | ||
let(:interactor) { Class.new.send(:include, described_class) } | ||
|
||
context "keyword arguments" do | ||
it "accepts required keyword arguments" do | ||
interactor.class_eval do | ||
def call(foo:) | ||
context.output = foo | ||
end | ||
end | ||
|
||
result = interactor.call(foo: "bar", hello: "world") | ||
|
||
expect(result.output).to eq("bar") | ||
end | ||
|
||
it "accepts optional keyword 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 keyword 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 keyword arguments" do | ||
interactor.class_eval do | ||
def call(foo:) | ||
context.output = foo | ||
end | ||
end | ||
|
||
expect { interactor.call(hello: "world") }.to raise_error(ArgumentError) | ||
end | ||
|
||
it "raises an error for call definitions with non-keyword arguments" do | ||
interactor.class_eval do | ||
def call(foo) | ||
context.output = foo | ||
end | ||
end | ||
|
||
expect { interactor.call(foo: "bar") }.to raise_error(ArgumentError) | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A big thank-you for maintaining this value.