Use when using the dry-monads Result pattern in Hanami 2.x — wrap outcomes in `Success(value)` or `Failure(error_object)`, chain operations with `Do notation` using `include Dry::Monads::Do.for(:call)` and `yield` inside the `call` method for sequential flows, inject the service object via `Deps["key"]` after registering it in a provider, handle results in Actions with pattern matching (`case result; in Success(v); ...; in Failure(e); ...; end`) rather than unsafe `value!` unwrapping, and model expected failures as data not exceptions. Covers bind/fmap chaining, and use in service objects registered in the DI container.
التثبيت
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
Use when using the dry-monads Result pattern in Hanami 2.x — wrap outcomes in `Success(value)` or `Failure(error_object)`, chain operations with `Do notation` using `include Dry::Monads::Do.for(:call)` and `yield` inside the `call` method for sequential flows, inject the service object via `Deps["key"]` after registering it in a provider, handle results in Actions with pattern matching (`case result; in Success(v); ...; in Failure(e); ...; end`) rather than unsafe `value!` unwrapping, and model expected failures as data not exceptions. Covers bind/fmap chaining, and use in service objects registered in the DI container.
Use this skill when using the dry-monads Result pattern in Hanami 2.x.
Core principle: Explicitly model success and failure. Return Success or Failure from operations that can fail, then chain them with bind and fmap.
Quick Reference
Scenario
Approach
Wrap a success
Success(value)
Wrap a failure
Failure(error_message) or Failure(error_object)
Chain on success
result.bind { |value| next_operation(value) }
Transform success value
result.fmap { |value| value.upcase }
Handle failure
result.or { |error| fallback_operation(error) }
Extract value
result.value! (raises on Failure)
Check status
result.success? / result.failure?
Pattern match
case result; in Success(v); ...; in Failure(e); ...; end
Core Rules
Use dry-monads in service objects registered in the DI container:
# app/operations/create_user.rb# frozen_string_literal: truerequire"dry/monads"require"dry/monads/do"moduleMyAppmoduleOperationsclassCreateUserincludeDry::Monads[:result]
includeDry::Monads::Do.for(:call)
includeDeps["repos.user_repo"]
defcall(attrs)
validated = yield validate(attrs)
user = yield create_user(validated)
Success(user)
endprivatedefvalidate(attrs)
returnFailure("Email is required") if attrs[:email].nil? || attrs[:email].empty?
returnFailure("Name is required") if attrs[:first_name].nil? || attrs[:first_name].empty?
Success(attrs)
enddefcreate_user(attrs)
user = user_repo.create(attrs)
Success(user)
rescueStandardError => e
Failure("Database error: #{e.message}")
endendendend
Register the service object in the container:
# config/providers/operations.rbHanami.app.register_provider(:operations) do
start do
register("operations.create_user", MyApp::Operations::CreateUser.new)
endend
Inject and call the service object in an Action:
# app/actions/users/create.rbmoduleMyAppmoduleActionsmoduleUsersclassCreate < MyApp::ActionincludeDeps["operations.create_user"]
defhandle(request, response)
result = create_user.call(request.params[:user])
case result
inDry::Monads::Success(user)
response.status = 201
response.body = user.to_json
inDry::Monads::Failure(error)
response.status = 422
response.body = { error: error }.to_json
endendendendendend