module Dry::Monads
Common, idiomatic monads for Ruby
@api public
Common, idiomatic monads for Ruby
@api private
Constants
- Traverse
-
List
of default traverse functions for types. It is implicitly used by List#traverse for making common cases easier to handle. - Unit
-
Unit
is a special object you can use whenever your computations don’t return any payload. Previously, if your function ran a side-effect and returned no meaningful value, you had to return things like Success(nil), Success([]), Success({}), Maybe(“”), Success(true) and so forth.You should use
Unit
if you wish to return an empty monad.@example with
Result
Success(Unit) Failure(Unit)
@example with
Maybe
Maybe(Unit) => Some(Unit)
- VERSION
-
Gem version
Attributes
Public Class Methods
Source
# File lib/dry/monads.rb, line 71 def self.[](*monads) monads.sort! @mixins.fetch_or_store(monads.hash) do monads.each { load_monad(_1) } mixins = monads.map { registry.fetch(_1) } ::Module.new { include(*mixins) }.freeze end end
Build a module with cherry-picked monads. It saves a bit of typing when you add multiple monads to one class. Not loaded monads get loaded automatically.
@example
require 'dry/monads' class CreateUser include Dry::Monads[:result, :do] def initialize(repo, send_email) @repo = repo @send_email = send_email end def call(name) if @repo.user_exist?(name) Failure(:user_exists) else user = yield @repo.add_user(name) yield @send_email.(user) Success(user) end end end
@param [Array<Symbol>] monads @return [Module] @api public
Source
# File lib/dry/monads.rb, line 34 def self.included(base) if all_loaded? base.include(*constructors) else raise "Load all monads first with require 'dry/monads/all'" end end
@private
Source
# File lib/dry/monads.rb, line 17 def self.loader @loader ||= ::Zeitwerk::Loader.new.tap do |loader| root = ::File.expand_path("..", __dir__) loader.tag = "dry-monads" loader.inflector = ::Zeitwerk::GemInflector.new("#{root}/dry-monads.rb") loader.push_dir(root) loader.ignore( "#{root}/dry-monads.rb", "#{root}/dry/monads/{all,constants,errors,registry,version}.rb", "#{root}/json/**/*.rb", "#{root}/dry/monads/extensions.rb", "#{root}/dry/monads/extensions/**/*.rb" ) end end
@api private
Protected Class Methods
Source
# File lib/dry/monads/registry.rb, line 30 def registry=(registry) @constructors = nil @registry = registry.dup.freeze end
Private Class Methods
Source
# File lib/dry/monads/registry.rb, line 66 def all_loaded? = registry.size.eql?(@constants.size) end
@private
Source
# File lib/dry/monads/registry.rb, line 59 def constructors @constructors ||= registry.values.filter_map do |m| m::Constructors if m.const_defined?(:Constructors) end end
@private
Source
# File lib/dry/monads/registry.rb, line 46 def known_monads = @constants.keys # @private def load_monad(name) constants = @constants.fetch(name) { raise ::ArgumentError, "#{name.inspect} is not a known monad" } Array(constants).each do |const_name| const_name.split("::").reduce(Monads) { |mod, const| mod.const_get(const) } end end # @private def constructors @constructors ||= registry.values.filter_map do |m| m::Constructors if m.const_defined?(:Constructors) end end # @private def all_loaded? = registry.size.eql?(@constants.size) end end
@private
Source
# File lib/dry/monads/registry.rb, line 49 def load_monad(name) constants = @constants.fetch(name) { raise ::ArgumentError, "#{name.inspect} is not a known monad" } Array(constants).each do |const_name| const_name.split("::").reduce(Monads) { |mod, const| mod.const_get(const) } end end
@private
Source
# File lib/dry/monads/registry.rb, line 37 def register_mixin(name, mod) if registry.key?(name) raise ArgumentError, "#{name.inspect} is already registered" end self.registry = registry.merge(name => mod) end
@private
Public Instance Methods
Source
# File lib/dry/monads/do/all.rb, line 159 def warn(message, category: nil, **) if message.include?("lib/dry/monads/do.rb") && message.include?("warning: the block passed to") nil else super end end