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

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.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/dry/monads/do.rb', line 117

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)


82
83
84
85
86
87
88
89
90
91
92
# File 'lib/dry/monads/do.rb', line 82

def for(*methods)
  mod = ::Module.new do
    methods.each { |method_name| Do.wrap_method(self, method_name) }
  end

  ::Module.new do
    singleton_class.send(:define_method, :included) do |base|
      base.prepend(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))


133
134
135
# File 'lib/dry/monads/do.rb', line 133

def halt(result)
  raise Halt.new(result), EMPTY_STRING, EMPTY_ARRAY
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.



95
96
97
98
99
100
101
# File 'lib/dry/monads/do.rb', line 95

def included(base)
  super

  # Actually mixes in Do::All
  require 'dry/monads/do/all'
  base.include All
end

.wrap_method(target, method_name) ⇒ 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.



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/dry/monads/do.rb', line 104

def wrap_method(target, method_name)
  target.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
    def #{method_name}(*)
      if block_given?
        super
      else
        Do.() { super { |*ms| Do.bind(ms) } }
      end
    end
  RUBY
end