Hi there,
Dry-rb libraries beginner here, I was trying to do this:
class Create
include Dry::Transaction::Operation
include Dry::Monads::Do.for(:call)
def call(params)
result = yield some_other_call(params)
# some logic with result
end
end
But I got no block given (yield)
error when running the tests.
This discussion LocalJumpError: no block given (yield) in github actions was a hint that it might not work to have do notation for the same :call method, because Dry::Transaction::Operation defines a Matcher for the same :call method with include Dry::Matcher.for(:call, with: Dry::Matcher::ResultMatcher)
.
I could not find an explanation for this. Why is not possible to use both?
Gems:
- dry-monads 1.3.5
- dry-transaction 0.13.2
Thanks!
Welcome! My first question is: why are you combining dry-monads and dry-transaction?
dry-transaction’s future is uncertain. It was deprecated, then un-deprecated, and hasn’t really seen any activity since.
Part of the reason for this is that dry-monads + dry-auto_inject basically provide all the things you get with dry-transaction with far greater flexibility.
If there are legacy reasons why you need dry-transaction, it will probably receive at least maintenance releases for the time being, but if you are starting fresh I would recommend just using do-notation.
That said, here’s the most basic approach to a do-notation Operation:
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'dry-monads'
end
require 'dry/monads'
M = Dry::Monads
class Create
include Dry::Monads[:result]
include Dry::Monads::Do.for(:call)
def call(params)
result = yield some_other_call(params)
Success(result)
end
private
def some_other_call(params) = Success(params)
end
create = Create.new
case create.({ foo: "Bar" })
in M::Success(attributes)
puts attributes.inspect
in M::Failure(err)
raise err
end
Hi, thanks for your time!
I consider the Create class an operation since I am including Dry::Transaction::Operation, which is later used in a transaction as a step.
The application we have, I would not necessarily say it is legacy. We have top-level business logic in dry-transactions, which are constructed from other transactions and operations.
I was surprised that I could not use the do notation in the same :call method and couldn’t find an explanation anywhere. I really like how transactions look and read, it’s way more natural than having do notation.
I ended up having something like this:
module Api
class Operation
def self.inherited(subclass)
super
subclass.include Dry::Transaction::Operation
end
end
end
class Create < Api::Operation
include Dry::Monads::Do.for(:create)
def call(params)
create(params)
end
private
def create(params)
result = yield some_other_call(params)
# some logic with result that returns Success/Failure
end
end
Moved do notation for the private :create method.