Module: Teckel::Operation

Defined in:
lib/teckel/operation.rb,
lib/teckel/operation/results.rb

Overview

The main operation Mixin

Each operation is expected to declare input. output and error classes.

There are two ways of declaring those classes. The first way is to define the constants Input, Output and Error, the second way is to use the input. output and error methods to point them to anonymous classes.

If you like “traditional” result objects to ask successful? or failure? on, see Teckel::Operation::Results

By default, input. output and error classes are build using :[] (eg: Input[some: :param]). Use input_constructor, output_constructor and error_constructor to change them.

Examples:

class definitions via constants

class CreateUserViaConstants
  include Teckel::Operation

  class Input
    def initialize(name:, age:)
      @name, @age = name, age
    end
    attr_reader :name, :age
  end

  Output = ::User

  class Error
    def initialize(message, errors)
      @message, @errors = message, errors
    end
    attr_reader :message, :errors
  end

  input_constructor :new
  error_constructor :new

  # @param [CreateUser::Input]
  # @return [User,CreateUser::Error]
  def call(input)
    user = ::User.new(name: input.name, age: input.age)
    if user.save
      user
    else
      fail!(message: "Could not save User", errors: user.errors)
    end
  end
end

CreateUserViaConstants.call(name: "Bob", age: 23).is_a?(User) #=> true

class definitions via methods

class CreateUserViaMethods
  include Teckel::Operation

  input  Types::Hash.schema(name: Types::String, age: Types::Coercible::Integer)
  output Types.Instance(User)
  error  Types::Hash.schema(message: Types::String, errors: Types::Array.of(Types::Hash))

  # @param [Hash<name: String, age: Integer>]
  # @return [User,Hash<message: String, errors: [Hash]>]
  def call(input)
    user = User.new(name: input[:name], age: input[:age])
    if user.save
      success!(user) # exits early with success, prevents any further execution
    else
      fail!(message: "Could not save User", errors: user.errors)
    end
  end
end

# A success call:
CreateUserViaMethods.call(name: "Bob", age: 23).is_a?(User) #=> true

# A failure call:
CreateUserViaMethods.call(name: "Bob", age: 10).eql?(message: "Could not save User", errors: [{age: "underage"}]) #=> true

# Build your Input, Output and Error classes in a way that let you know:
begin; CreateUserViaMethods.call(unwanted: "input"); rescue => e; e end.is_a?(::Dry::Types::MissingKeyError) #=> true

# Feed an instance of the input class directly to call:
CreateUserViaMethods.call(CreateUserViaMethods.input[name: "Bob", age: 23]).is_a?(User) #=> true

Defined Under Namespace

Modules: ClassMethods, InstanceMethods, Results Classes: Runner

Class Method Summary collapse

Class Method Details

.included(receiver) ⇒ Object



400
401
402
403
404
405
406
407
408
409
410
411
# File 'lib/teckel/operation.rb', line 400

def self.included(receiver)
  receiver.extend         ClassMethods
  receiver.send :include, InstanceMethods

  receiver.class_eval do
    @config = Config.new

    @runner = Runner

    protected :success!, :fail!
  end
end