Skip to content
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

Drop ostruct usage #127

Merged
merged 3 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Fixes:
- Add default message to missing `message` key on advanced `input` or `output`
checks (#117)
- Allow using a Hash as `default:` (#119)
- Refactor `ServiceActor::Result` to get rid of `OpenStruct` inheritance
(#127)

## v3.7.0

Expand Down
15 changes: 3 additions & 12 deletions lib/service_actor/playable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,8 @@ def inherited(child)

private

def define_alias_input(actor, new, original)
actor[new] = actor[original]
actor.instance_exec do
[original, new].each do |method|
singleton_class.send(:undef_method, "#{method}=")
define_singleton_method("#{method}=") do |v|
actor[original] = v
actor[new] = v
end
end
end
def define_alias_input(actor, new_input, original_input)
actor[new_input] = actor.delete(original_input)
end
end

Expand Down Expand Up @@ -113,7 +104,7 @@ def play_interactor(actor)
return unless actor.is_a?(Class)
return unless actor.ancestors.map(&:name).include?("Interactor")

result.merge!(actor.call(result).to_h)
result.merge!(actor.call(result.to_h).to_h)
end
end
end
58 changes: 34 additions & 24 deletions lib/service_actor/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@

# Represents the context of an actor, holding the data from both its inputs
# and outputs.
class ServiceActor::Result < OpenStruct
class ServiceActor::Result
def self.to_result(data)
return data if data.is_a?(self)

new(data.to_h)
end

def initialize(data = {})
@data = data.to_h
end

def to_h
data
end

def inspect
"<#{self.class.name} #{to_h}>"
end
Expand All @@ -21,8 +29,8 @@ def fail!(failure_class = nil, result = {})
failure_class = ServiceActor::Failure
end

merge!(result)
merge!(failure?: true)
data.merge!(result)
data[:failure] = true

raise failure_class, self
end
Expand All @@ -32,13 +40,11 @@ def success?
end

def failure?
self[:failure?] || false
data[:failure] || false
end

def merge!(result)
result.each_pair do |key, value|
self[key] = value
end
data.merge!(result)

self
end
Expand All @@ -48,7 +54,15 @@ def key?(name)
end

def [](name)
to_h[name]
data[name]
end

def []=(key, value)
data[key] = value
end

def delete(key)
data.delete(key)
end

# Defined here to override the method on `Object`.
Expand All @@ -58,24 +72,20 @@ def display

private

def respond_to_missing?(method_name, include_private = false)
method_name.to_s.end_with?("?") || super
end

def method_missing(symbol, *args)
attribute = symbol.to_s.chomp("?")
attr_reader :data

if symbol.to_s.end_with?("?") && respond_to?(attribute)
define_singleton_method symbol do
value = send(attribute.to_sym)

# Same as ActiveSupport’s #present?
value.respond_to?(:empty?) ? !value.empty? : !!value
end
def respond_to_missing?(_method_name, _include_private = false)
true
end

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

super symbol, *args
end
end