kit-organizer edge

Organize module
Kit::Organizer::Services::Organize
View Source

Organizer passes the result of a callable to another callable (as long as the result is successfull). It is mostly useful when you need to execute a series of operations resembling a pipeline. You might alredy be familiar with some solutions that deal with this (Promises, Railway Programming, Pipe operators). Kit::Organizer is a flavor of functional interactor.

Introduction

Describing a list of operations often leads to code that is difficult to follow or nested requires a lot of nesting. For instance:

fire_user_created_event(persist_user(validate_password(validate_email({ email: email, password: password }))))

# or

valid_email?    = validate_email(email)
valid_password? = validate_password(password)
if valid_email? && valid_password?
  user = persist_user(email: email, password: password)
  if user
    fire_user_created_event(user: user)
  end
end

With Organizer, this is expressed as:

Kit::Organize::Services::Organize.call(
  list: [
    [:alias, :validate_email],
    [:alias, :validate_password],
    [:alias, :persist_user],
    [:alias, :fire_user_created_event],
  ],
  ctx: {
    email: '',
    password: '',
  },
)

Context

An organizer uses a context. The context contains everything the set of operations need to work. When an operation is called, it can affect the context.

Callable

A callable is expected to return a result tupple of the following format:

[:ok] || [:ok, context_update] || [:error] || [:error, context_update]

Link to this section Summary ⚠️ Private APIs are currently hidden.

Used instance mixins: Contract::Mixin

Link to this section Class methods 3 ⚠️ Private APIs are currently hidden.

Link to this method

._log(txt, color = nil)

View Source APIPrivate
⚠️ This method is part of a private API. You should avoid using it as it may be removed or be changed in the future.

Display debug information when ENV['LOG_ORGANIZER'] is set

Link to this method

.call(list:, ctx: {}, filter: nil)

View Source

Run a list of operations (callable) in order. Each results update the initial ctx which is then sent to the next operation. An operation needs to be a callable, but it can be resolved from other format (see #to_callable) Note: Every operation is expected to return a tupple of the format [:ok] or [:error] with an optional context update ([:ok, { new_ctx_key: 'value' }], [:errors, { errors: [{ detail: 'Error explaination' }], }]). If an :error tupple is returned, the next operations are canceled and call will return. contract Ct::Hash[list: Ct::Operations, ctx: Ct::Optional[Ct::Hash], filter: Ct::Optional[Ct::Or[Ct::Hash[ok: Ct::Array], Ct::Hash[error: Ct::Array]]]] => Ct::ResultTupple

Parameters:

  • list

    An array of operations (callables) that will be called in order

  • ctx (defaults to: {})

    A hash containing values to send to the operations (callables). It will be updated after every operation.

  • filter (defaults to: nil)

    Allows to slice specific keys on the context

Returns:

  • The updated context.

Link to this method

.sanitize_errors(result:)

View Source APIPrivate
⚠️ This method is part of a private API. You should avoid using it as it may be removed or be changed in the future. 🗒 Notes:
  • Enable simpler error return format from an organized callable.

Sanitizes returned errors, if any. contract Ct::Hash[result: Ct::ResultTupple] => Ct::ResultTupple

Examples:

Returning an error as a string

sanitize_result([:error, 'Error details']) => [:error, { errors: [{ detail: 'Error details' }] }]

Returning an error as hash with detail

sanitize_result([:error, { detail: 'Error details' }]) => [:error, { errors: [{ detail: 'Error details' }] }]

Returning an array of errors in the two former formats

sanitize_result([:error, ['Error1 detail', { detail: 'Error2 details' }]) => [:error, { errors: [{ detail: 'Error1 details' }, { detail: 'Error2 details' }] }]