Skip to content

Commit

Permalink
Merge pull request #211 from hanami/improve-interactors-format
Browse files Browse the repository at this point in the history
Introduce new interactor format
  • Loading branch information
TiteiKo committed Jul 5, 2017
2 parents 03a57b8 + a603acc commit 5cf3f54
Show file tree
Hide file tree
Showing 2 changed files with 502 additions and 104 deletions.
150 changes: 128 additions & 22 deletions lib/hanami/interactor.rb
Expand Up @@ -145,15 +145,14 @@ def self.included(base)
super

base.class_eval do
prepend Interface
extend ClassMethods
extend ClassMethods
end
end

# Interactor interface
# Interactor legacy interface
#
# @since 0.3.5
module Interface
module LegacyInterface
# Initialize an interactor
#
# It accepts arbitrary number of arguments.
Expand Down Expand Up @@ -262,6 +261,118 @@ def initialize(*args)
def call
_call { super }
end

private

# @since 0.3.5
# @api private
def _call
catch :fail do
validate!
yield
end

_prepare!
end

# @since 0.3.5
def validate!
fail! unless valid?
end
end

# Interactor interface
# @since x.x.x
module Interface
# Triggers the operation and return a result.
#
# All the exposed instance variables will be available in the result.
#
# ATTENTION: This must be implemented by the including class.
#
# @return [Hanami::Interactor::Result] the result of the operation
#
# @raise [NoMethodError] if this isn't implemented by the including class.
#
# @example Expose instance variables in result payload
# require 'hanami/interactor'
#
# class Signup
# include Hanami::Interactor
# expose :user, :params
#
# def call(params)
# @params = params
# @foo = 'bar'
# @user = UserRepository.new.persist(User.new(params))
# end
# end
#
# result = Signup.new(name: 'Luca').call
# result.failure? # => false
# result.successful? # => true
#
# result.user # => #<User:0x007fa311105778 @id=1 @name="Luca">
# result.params # => { :name=>"Luca" }
# result.foo # => raises NoMethodError
#
# @example Failed precondition
# require 'hanami/interactor'
#
# class Signup
# include Hanami::Interactor
# expose :user
#
# # THIS WON'T BE INVOKED BECAUSE #valid? WILL RETURN false
# def call(params)
# @user = User.new(params)
# @user = UserRepository.new.persist(@user)
# end
#
# private
# def valid?(params)
# params.valid?
# end
# end
#
# result = Signup.new.call(name: nil)
# result.successful? # => false
# result.failure? # => true
#
# result.user # => nil
#
# @example Bad usage
# require 'hanami/interactor'
#
# class Signup
# include Hanami::Interactor
#
# # Method #call is not defined
# end
#
# Signup.new.call # => NoMethodError
def call(*args, **kwargs)
@__result = ::Hanami::Interactor::Result.new
_call(*args, **kwargs) { super }
end

private

# @api private
# @since x.x.x
def _call(*args, **kwargs)
catch :fail do
validate!(*args, **kwargs)
yield
end

_prepare!
end

# @since x.x.x
def validate!(*args, **kwargs)
fail! unless valid?(*args, **kwargs)
end
end

private
Expand All @@ -274,7 +385,7 @@ def call
# @return [TrueClass,FalseClass] the result of the check
#
# @since 0.3.5
def valid?
def valid?(*)
true
end

Expand Down Expand Up @@ -426,22 +537,6 @@ def error!(message)
fail!
end

# @since 0.3.5
# @api private
def _call
catch :fail do
validate!
yield
end

_prepare!
end

# @since 0.3.5
def validate!
fail! unless valid?
end

# @since 0.3.5
# @api private
def _prepare!
Expand All @@ -453,7 +548,7 @@ def _prepare!
def _exposures
Hash[].tap do |result|
self.class.exposures.each do |name, ivar|
result[name] = instance_variable_get(ivar)
result[name] = instance_variable_defined?(ivar) ? instance_variable_get(ivar) : nil
end
end
end
Expand All @@ -473,6 +568,17 @@ def self.extended(interactor)
end
end

def method_added(method_name)
super
return unless method_name == :call

if instance_method(:call).arity.zero?
prepend Hanami::Interactor::LegacyInterface
else
prepend Hanami::Interactor::Interface
end
end

# Expose local instance variables into the returning value of <tt>#call</tt>
#
# @param instance_variable_names [Symbol,Array<Symbol>] one or more instance
Expand Down

0 comments on commit 5cf3f54

Please sign in to comment.