lib/hanami/interactor.rb in hanami-utils-1.0.4 vs lib/hanami/interactor.rb in hanami-utils-1.1.0.beta1
- old
+ new
@@ -143,19 +143,18 @@
# @api private
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.
# Developers can override it.
#
@@ -260,23 +259,135 @@
#
# Signup.new.call # => NoMethodError
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 1.1.0
+ 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 1.1.0
+ def _call(*args, **kwargs)
+ catch :fail do
+ validate!(*args, **kwargs)
+ yield
+ end
+
+ _prepare!
+ end
+
+ # @since 1.1.0
+ def validate!(*args, **kwargs)
+ fail! unless valid?(*args, **kwargs)
+ end
+ end
+
private
# Check if proceed with <tt>#call</tt> invokation.
# By default it returns <tt>true</tt>.
#
# Developers can override it.
#
# @return [TrueClass,FalseClass] the result of the check
#
# @since 0.3.5
- def valid?
+ def valid?(*)
true
end
# Fail and interrupt the current flow.
#
@@ -426,36 +537,20 @@
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!
@__result.prepare!(_exposures)
end
# @since 0.5.0
# @api private
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
end
@@ -468,9 +563,20 @@
interactor.class_eval do
include Utils::ClassAttribute
class_attribute :exposures
self.exposures = {}
+ 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>
#