Skip to content

Hands-on workshop for the dry-rb ecosystem: types, structs, validation, monads, containers, and transactions

Notifications You must be signed in to change notification settings

jwalsh/dry-rb-workshop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

dry-rb Ecosystem Workshop

Ruby dry-rb License: MIT PRs Welcome

A hands-on workshop exploring the dry-rb ecosystem - a collection of next-generation Ruby libraries that embrace functional programming concepts while remaining pragmatic and Ruby-like.

Key Principles

  • Immutability by default - Data structures that don't change unexpectedly
  • Explicit over implicit - Clear contracts and expectations
  • Composition over inheritance - Build complex behavior from simple parts
  • Type safety without ceremony - Catch errors early without boilerplate

Workshop Contents

Part Topic Duration Description
1 dry-types 20 min Type system for coercion, constraints, and composition
2 dry-struct 15 min Immutable, typed value objects
3 dry-validation 25 min Schemas and contracts for business rule validation
4 dry-monads 25 min Result, Maybe, and Try monads for error handling
5 dry-container 15 min IoC container and dependency injection
6 dry-transaction 10 min Business transaction DSL with failure handling

Quick Start

# Clone the repository
git clone https://github.com/jwalsh/dry-rb-workshop.git
cd dry-rb-workshop

# Install dependencies
bundle install

# Run individual examples
ruby lib/examples/01_types_primitives.rb
ruby lib/examples/12_monads_result.rb
ruby lib/examples/19_transaction.rb

# Run the complete application demo
ruby lib/application.rb

Dependencies

gem "dry-types", "~> 1.7"
gem "dry-struct", "~> 1.6"
gem "dry-validation", "~> 1.10"
gem "dry-monads", "~> 1.6"
gem "dry-container", "~> 0.11"
gem "dry-auto_inject", "~> 1.0"
gem "dry-transaction", "~> 0.15"

Examples Overview

dry-types - Type System Foundation

# Strict types raise on invalid input
strict_string = Types::Strict::String
strict_string.("hello")  # => "hello"

# Coercible types attempt conversion
coercible_int = Types::Coercible::Integer
coercible_int.("42")     # => 42

# Constrained types with validation
PositiveInt = Types::Strict::Integer.constrained(gt: 0)
Email = Types::Strict::String.constrained(format: /\A[\w+\-.]+@[a-z\d\-]+\.[a-z]+\z/i)

dry-struct - Immutable Value Objects

class Person < Dry::Struct
  attribute :name, Types::Strict::String
  attribute :age, Types::Coercible::Integer
  attribute :email, Types::Strict::String.optional
end

alice = Person.new(name: "Alice", age: "30", email: "alice@example.com")
older_alice = alice.new(age: 31)  # Returns new instance

dry-monads - Functional Error Handling

class UserService
  include Dry::Monads[:result, :do]

  def create(params)
    validated = yield validate(params)
    user = yield persist(validated)
    Success(user)
  end
end

# Pattern matching on results
case service.create(params)
in Success(user) then puts "Created: #{user.name}"
in Failure(:validation, errors) then puts "Invalid: #{errors}"
in Failure(:database, error) then puts "DB Error: #{error}"
end

dry-transaction - Business Transaction DSL

class CreateOrder
  include Dry::Transaction

  step :validate
  step :check_inventory
  step :charge_payment
  step :create_record
  step :send_confirmation
end

Quick Reference

Type Coercion Families

Type Family Behavior Example
Types::Strict:: No coercion, raises on mismatch Strict::String.("hi")
Types::Coercible:: Ruby-style coercion Coercible::Integer.("42")
Types::Params:: HTTP param coercion Params::Bool.("true")
Types::JSON:: JSON-style coercion JSON::Date.("2025-01-01")

Common Constraints

.constrained(gt: 0)           # greater than
.constrained(gteq: 0)         # greater than or equal
.constrained(min_size: 1)     # minimum length
.constrained(format: /regex/) # regex match
.constrained(included_in: []) # enum values

Monad Operations

Operation Description
Success(val) Wrap success value
Failure(err) Wrap failure value
.value! Unwrap (raises on Failure)
.value_or(x) Unwrap with default
.bind { } Chain (must return Result)
.fmap { } Transform success value
yield result Do-notation unwrap

Resources

License

MIT

About

Hands-on workshop for the dry-rb ecosystem: types, structs, validation, monads, containers, and transactions

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages