Skip to content

Commit

Permalink
Forbid sending undefined messages to ServiceActor::Result instances
Browse files Browse the repository at this point in the history
  • Loading branch information
viralpraxis committed Mar 2, 2024
1 parent 231bcfe commit 28f71f3
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Fixes:
- Allow using a Hash as `default:` (#119)
- Refactor `ServiceActor::Result` to get rid of `OpenStruct` inheritance
(#127)
- Deprecate invoking undefined methods on `ServiceActor::Result` (#129)
- Ensure provided `failure_class` and `argument_error_class` values
are subclasses of `Exception` (#132)
- Skip `default` check for actor outputs (#135)
Expand Down
4 changes: 4 additions & 0 deletions lib/service_actor/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ def call(result = nil, **arguments)
instance = new(result)
instance._call

outputs.each_key do |key|
result.send("#{key}=", nil) unless result.respond_to?(key)
end

result
end

Expand Down
26 changes: 21 additions & 5 deletions lib/service_actor/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,34 @@ def display

attr_reader :data

def respond_to_missing?(_method_name, _include_private = false)
true
def respond_to_missing?(method_name, _include_private = false)
return true if method_name.end_with?("=")
return true if method_name.end_with?("?") && \
data.key?(method_name.to_s.chomp("?").to_sym)
return true if data.key?(method_name)

false
end

def method_missing(method_name, *args) # rubocop:disable Metrics/AbcSize
if method_name.end_with?("?")
value = data[method_name.to_s.chomp("?").to_sym]
if method_name.end_with?("?") &&
data.key?(key = method_name.to_s.chomp("?").to_sym)
value = data[key]
value.respond_to?(:empty?) ? !value.empty? : !!value
elsif method_name.end_with?("=")
data[method_name.to_s.chomp("=").to_sym] = args.first
else
elsif data.key?(method_name)
data[method_name]
else
warn_on_undefined_method_invocation(method_name)
end
end

def warn_on_undefined_method_invocation(message)
Kernel.warn(
"DEPRECATED: Invoking undefined methods on `ServiceActor::Result` will " \
"lead to runtime errors in the next major release of Actor. " \
"Invoked method: `#{message}`",
)
end
end
30 changes: 30 additions & 0 deletions spec/actor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -833,5 +833,35 @@
it { expect(actor.name).to eq("Jim") }
it { expect(actor.value).to eq(0) }
end

context "with sending unexpected messages" do
let(:actor) { PlayActors.result(value: 42) }

before { allow(Kernel).to receive(:warn) }

it { expect(actor).to be_a_success }
it { expect(actor).to respond_to(:name) }
it { expect(actor).to respond_to(:name?) }
it { expect(actor.name).to eq("jim") }

it { expect(actor).not_to respond_to(:unknown_method) }
it { expect(actor).not_to respond_to(:unknown_method?) }

it "warns about sending unexpected messages" do
actor.unknown_method

expect(Kernel).to have_received(:warn).with(
include("unknown_method"),
)
end

it "warns about sending unexpected predicate messages" do
actor.unknown_method?

expect(Kernel).to have_received(:warn).with(
include("unknown_method?"),
)
end
end
end
end

0 comments on commit 28f71f3

Please sign in to comment.