Skip to content

Commit

Permalink
add Operation.call_with_public_interface_from_call as an entry poin…
Browse files Browse the repository at this point in the history
…t for

normalizing arguments of `Operation.call` (public style).
  • Loading branch information
apotonick committed Nov 27, 2023
1 parent 5de3a1b commit ac2fa2b
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 8 deletions.
24 changes: 17 additions & 7 deletions lib/trailblazer/operation/public_call.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@ module Operation::PublicCall
def call(options = {}, flow_options = {}, **circuit_options)
return call_with_circuit_interface(options, **circuit_options) if options.is_a?(Array) # This is kind of a hack that could be well hidden if Ruby had method overloading. Goal is to simplify the call thing as we're fading out Operation::public_call anyway.

call_with_public_interface(options, flow_options, **circuit_options)
call_with_public_interface_from_call(options, flow_options, **circuit_options)
end

# @private Please do not override this method as it might get removed.
def call_with_public_interface_from_call(options, flow_options, **circuit_options)
# normalize options.
options = options
.merge(circuit_options) # when using Op.call(params:, ...), {circuit_options} will always be ctx variables.

call_with_public_interface(options, flow_options)
end

# Default {@activity} call interface which doesn't accept {circuit_options}
Expand All @@ -25,23 +34,24 @@ def call(options = {}, flow_options = {}, **circuit_options)
#
# @return [Operation::Railway::Result]
#
# @private

# @semi-public It's OK to override this method.
def call_with_public_interface(options, flow_options, invoke_class: Activity::TaskWrap, **circuit_options)
flow_options = flow_options_for_public_call(flow_options)

# In Ruby < 3, calling Op.(params: {}, "current_user" => user) results in both {circuit_options} and {options} containing variables.
# In Ruby 3.0, **circuit_options is always empty.
options = circuit_options.any? ? circuit_options.merge(options) : options
# options = circuit_options.any? ? circuit_options.merge(options) : options

ctx = options_for_public_call(options, flow_options)

# call the activity.
# This will result in invoking {::call_with_circuit_interface}.
# Call the activity as it if was a step in an endpoint.

# This will result in invoking {self.call_with_circuit_interface}.
signal, (ctx, flow_options) = invoke_class.invoke(
self,
[ctx, flow_options],
container_activity: Activity::TaskWrap.container_activity_for(self, wrap_static: initial_wrap_static) # we cannot make this static because of {self} unless we override {#inherited}.
container_activity: Activity::TaskWrap.container_activity_for(self, wrap_static: initial_wrap_static), # we cannot make this static because of {self} unless we override {#inherited}.
**circuit_options
)

# Result is successful if the activity ended with an End event derived from Railway::End::Success.
Expand Down
10 changes: 9 additions & 1 deletion test/operation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ def self.capture_circuit_options((ctx, flow_options), **circuit_options)
it "doesn't mistake circuit options as ctx variables when using the call interface" do
result = Noop.call(params: {}, model: true, "current_user" => Object) # call with public interface.
#@ {:variable_for_circuit_options} is not supposed to be in {ctx}.
assert_equal result.inspect, %(<Result:true #<Trailblazer::Context::Container wrapped_options={:params=>{}, :model=>true, "current_user"=>Object} mutable_options={:capture_circuit_options=>"[:exec_context, :wrap_runtime, :activity, :runner]"}> >)
assert_equal result.inspect, %(<Result:true #<Trailblazer::Context::Container wrapped_options={:params=>{}, :model=>true, "current_user"=>Object} mutable_options={:capture_circuit_options=>"[:wrap_runtime, :activity, :exec_context, :runner]"}> >)
end

#@ {#call_with_public_interface}
it "doesn't mistake circuit options as ctx variables when using circuit-interface" do
result = Noop.call_with_public_interface({params: {}}, {}, variable_for_circuit_options: true) # call_with_public_interface has two positional args, and kwargs for {circuit_options}.

assert_equal result.inspect, %(<Result:true #<Trailblazer::Context::Container wrapped_options={:params=>{}} mutable_options={:capture_circuit_options=>\"[:variable_for_circuit_options, :wrap_runtime, :activity, :exec_context, :runner]\"}> >)
end
end

Expand Down Expand Up @@ -171,6 +178,7 @@ class Collect < Trailblazer::Operation
ctx.inspect.must_equal %{#<Trailblazer::Context::Container wrapped_options={\"params\"=>{:decide=>true}} mutable_options={\"a\"=>false, \"b\"=>true}>}

# Call by passing aliases as an argument.
# This uses {#call}'s second positional argument.
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0.0")
result = Update.(
options,
Expand Down

0 comments on commit ac2fa2b

Please sign in to comment.