module Dry::Monads::Do

An implementation of do-notation.

@see Do.for

Constants

VISIBILITY_WORD

Public Class Methods

coerce_to_monad(monads) click to toggle source

@api private

# File lib/dry/monads/do.rb, line 149
def coerce_to_monad(monads)
  return monads if monads.size != 1

  first = monads[0]

  case first
  when ::Array
    [List.coerce(first).traverse]
  when List
    [first.traverse]
  else
    monads
  end
end
for(*methods) click to toggle source

Generates a module that passes a block to methods that either unwraps a single-valued monadic value or halts the execution.

@example A complete example

class CreateUser
  include Dry::Monads::Result::Mixin
  include Dry::Monads::Try::Mixin
  include Dry::Monads::Do.for(:call)

  attr_reader :user_repo

  def initialize(:user_repo)
    @user_repo = user_repo
  end

  def call(params)
    json = yield parse_json(params)
    hash = yield validate(json)

    user_repo.transaction do
      user = yield create_user(hash[:user])
      yield create_profile(user, hash[:profile])
    end

    Success(user)
  end

  private

  def parse_json(params)
    Try(JSON::ParserError) {
      JSON.parse(params)
    }.to_result
  end

  def validate(json)
    UserSchema.(json).to_monad
  end

  def create_user(user_data)
    Try(Sequel::Error) {
      user_repo.create(user_data)
    }.to_result
  end

  def create_profile(user, profile_data)
    Try(Sequel::Error) {
      user_repo.create_profile(user, profile_data)
    }.to_result
  end
end

@param [Array<Symbol>] methods @return [Module]

# File lib/dry/monads/do.rb, line 105
def for(*methods)
  ::Module.new do
    singleton_class.define_method(:included) do |base|
      mod = ::Module.new
      base.prepend(mod)
      base.extend(MethodTracker.new(methods, base, mod))
    end
  end
end
halt(result) click to toggle source

@api private

# File lib/dry/monads/do.rb, line 165
def halt(result)
  raise Halt.new(result), "", []
end
included(base) click to toggle source

@api private

Calls superclass method Dry::Monads::Do::All::included
# File lib/dry/monads/do.rb, line 116
def included(base)
  super

  # Actually mixes in Do::All
  require "dry/monads/do/all"
  base.include All
end
method_visibility(mod, method) click to toggle source

@api private

# File lib/dry/monads/do.rb, line 138
def method_visibility(mod, method)
  if mod.public_method_defined?(method)
    :public
  elsif mod.private_method_defined?(method)
    :private
  else
    :protected
  end
end
wrap_method(target, method, visibility) click to toggle source

@api private

# File lib/dry/monads/do.rb, line 125
        def wrap_method(target, method, visibility)
          target.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
            #{VISIBILITY_WORD[visibility]} def #{method}(...) # private def create_acccount(...)
              if block_given?                                 #   if block_given?
                super                                         #     super
              else                                            #   else
                Do.() { super { |*ms| Do.bind(ms) } }         #     Do.() { super { |*ms| Do.bind(ms) } }
              end                                             #   end
            end                                               # end
          RUBY
        end