-
-
Save rinaldifonseca/8fcc84863d971b83dec7044cfdf9cdbf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'logger' | |
require 'byebug' | |
require 'dry/monads' | |
require 'dry/monads/do' | |
require 'dry/matcher/result_matcher' | |
module Dry | |
module Transaction | |
module Steps | |
class Abstract | |
include Dry::Monads[:result] | |
attr_reader :name | |
attr_reader :object | |
def initialize(name, object = nil) | |
@name = name | |
@object = object | |
end | |
def call(input) | |
object.public_send(name, input) | |
end | |
def bind(object) | |
self.class.new(name, object) | |
end | |
end | |
class Step < Abstract | |
end | |
class Map < Abstract | |
end | |
class Tee < Abstract | |
def call(input) | |
super | |
Success(input) | |
end | |
end | |
end | |
module DSL | |
def step(name) | |
__steps__ << Steps::Step.new(name) | |
end | |
def map(name) | |
__steps__ << Steps::Map.new(name) | |
end | |
def tee(name) | |
__steps__ << Steps::Tee.new(name) | |
end | |
def __steps__ | |
@__steps__ ||= [] | |
end | |
end | |
def self.included(klass) | |
super | |
klass.class_eval do | |
extend DSL | |
include Dry::Monads[:result, :try] | |
include Dry::Monads::Do.for(:call) | |
include Dry::Matcher.for(:call, with: Dry::Matcher::ResultMatcher) | |
end | |
end | |
attr_reader :steps | |
def initialize(*) | |
@steps = self.class.__steps__.map { |step| step.bind(self) } | |
end | |
def call(input) | |
steps.reduce(input) do |value, curr_step| | |
case curr_step | |
when Steps::Tee | |
curr_step.(value) | |
else | |
yield(curr_step.(value)) | |
end | |
end | |
end | |
end | |
end | |
RSpec.describe Dry::Transaction do | |
subject(:transaction) do | |
Class.new do | |
include Dry::Transaction | |
step :validate | |
map :transform | |
tee :log | |
attr_reader :logs | |
def initialize | |
super | |
@logs = [] | |
end | |
def validate(params) | |
if params.key?('email') | |
Success(params) | |
else | |
Failure('no email') | |
end | |
end | |
def transform(params) | |
Success(email: params.fetch('email')) | |
end | |
def log(values) | |
logs << values | |
end | |
def call(input) | |
res = yield super | |
res = yield extract(res) | |
Success(res) | |
end | |
private | |
def extract(params) | |
Success(params[:email]) | |
end | |
end.new | |
end | |
it 'works with a success matcher' do | |
result = nil | |
transaction.('email' => '[email protected]') do |m| | |
m.success do |value| | |
result = value | |
end | |
m.failure do |_| | |
end | |
end | |
expect(transaction.logs).to eql('email' => '[email protected]') | |
expect(result).to eql('[email protected]') | |
end | |
it 'works with a failure matcher' do | |
result = nil | |
transaction.('foo': '[email protected]') do |m| | |
m.success do |value| | |
result = value | |
end | |
m.failure do |error| | |
result = error | |
end | |
end | |
expect(transaction.logs).to eql('email' => '[email protected]') | |
expect(result).to eql('no email') | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment