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

Constant Summary collapse

DELEGATE =
::RUBY_VERSION < '2.7' ? '*' : '...'

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.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/dry/monads/do.rb', line 121

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)


86
87
88
89
90
91
92
93
94
95
96
# File 'lib/dry/monads/do.rb', line 86

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))


137
138
139
# File 'lib/dry/monads/do.rb', line 137

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



99
100
101
102
103
104
105
# File 'lib/dry/monads/do.rb', line 99

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.



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/dry/monads/do.rb', line 108

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