Module: Dry::Monads::Do

Extended by:
Mixin
Defined in:
lib/dry/monads/do.rb,
lib/dry/monads/do/all.rb,
lib/dry/monads/do/mixin.rb

Overview

An implementation of do-notation.

See Also:

Defined Under Namespace

Modules: All, Mixin Classes: Halt, MethodTracker

Constant Summary collapse

VISIBILITY_WORD =
{
  public: "",
  private: "private ",
  protected: "protected "
}.freeze

Class Method Summary collapse

Methods included from Mixin

bind, call

Class Method Details

.coerce_to_monad(monads) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
# 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) ⇒ Module

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

Examples:

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

Parameters:

  • methods (Array<Symbol>)

Returns:

  • (Module)


105
106
107
108
109
110
111
112
113
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (Halt.new(result))


165
166
167
# File 'lib/dry/monads/do.rb', line 165

def halt(result)
  raise Halt.new(result), "", []
end

.included(base) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



116
117
118
119
120
121
122
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



138
139
140
141
142
143
144
145
146
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



125
126
127
128
129
130
131
132
133
134
135
# 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