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> #