Skip to content

Commit

Permalink
Merge pull request #64 from jonolsson/master
Browse files Browse the repository at this point in the history
Check if an operation is registered in the container before getting it (Issue #61)
  • Loading branch information
timriley authored Jul 10, 2017
2 parents c29930e + cddb524 commit 9d62b10
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 25 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ group :test do
gem "simplecov"
gem "codeclimate-test-reporter"
gem "byebug", platform: :mri
gem "dry-container"
end

group :tools do
Expand Down
4 changes: 3 additions & 1 deletion lib/dry/transaction/operation_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ def initialize(container)
module_exec(container) do |ops_container|
define_method :initialize do |**kwargs|
operation_kwargs = self.class.steps.select(&:operation_name).map { |step|
operation = kwargs.fetch(step.step_name) { ops_container and ops_container[step.operation_name] }
operation = kwargs.fetch(step.step_name) {
ops_container and ops_container.key?(step.operation_name) and ops_container[step.operation_name]
}

[step.step_name, operation]
}.to_h
Expand Down
108 changes: 84 additions & 24 deletions spec/integration/transaction_spec.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
RSpec.describe "Transactions" do
let(:transaction) {
Class.new do
include Dry::Transaction(container: Test::Container)
map :process
step :verify
try :validate, catch: Test::NotValidError
tee :persist
end.new(**dependencies)
}

let(:dependencies) { {} }

before do
Test::NotValidError = Class.new(StandardError)
Test::DB = []
Test::Container = {
process: -> input { {name: input["name"], email: input["email"]} },
verify: -> input { Right(input) },
validate: -> input { input[:email].nil? ? raise(Test::NotValidError, "email required") : input },
persist: -> input { Test::DB << input and true },
}
class Test::Container
extend Dry::Container::Mixin
register :process, -> input { {name: input["name"], email: input["email"]} }
register :verify, -> input { Dry::Monads::Right(input) }
register :validate, -> input { input[:email].nil? ? raise(Test::NotValidError, "email required") : input }
register :persist, -> input { Test::DB << input and true }
end
end

context "successful" do
let(:transaction) {
Class.new do
include Dry::Transaction(container: Test::Container)
map :process
step :verify
try :validate, catch: Test::NotValidError
tee :persist
end.new(**dependencies)
}
let(:input) { {"name" => "Jane", "email" => "[email protected]"} }

it "calls the operations" do
Expand Down Expand Up @@ -63,12 +63,11 @@

context "different step names" do
before do
module Test
ContainerNames = {
process_step: -> input { {name: input["name"], email: input["email"]} },
verify_step: -> input { Dry::Monads.Right(input) },
persist_step: -> input { Test::DB << input and true },
}
class Test::ContainerNames
extend Dry::Container::Mixin
register :process_step, -> input { {name: input["name"], email: input["email"]} }
register :verify_step, -> input { Dry::Monads::Right(input) }
register :persist_step, -> input { Test::DB << input and true }
end
end

Expand Down Expand Up @@ -156,6 +155,29 @@ def verify(input)
end
end

context "local step definition not in container" do
let(:transaction) do
Class.new do
include Dry::Transaction(container: Test::Container)

map :process, with: :process
step :verify_only_local
tee :persist, with: :persist

def verify_only_local(input)
Right(input.keys)
end
end.new
end

it "execute step only defined as local method" do
transaction.call("name" => "Jane", "email" => "[email protected]")

expect(Test::DB).to include([:name, :email])
end
end


context "all steps are local methods" do
let(:transaction) do
Class.new do
Expand Down Expand Up @@ -186,6 +208,15 @@ def persist(input)
end

context "failed in a try step" do
let(:transaction) {
Class.new do
include Dry::Transaction(container: Test::Container)
map :process
step :verify
try :validate, catch: Test::NotValidError
tee :persist
end.new(**dependencies)
}
let(:input) { {"name" => "Jane"} }

it "does not run subsequent operations" do
Expand Down Expand Up @@ -252,9 +283,24 @@ def persist(input)
let(:input) { {"name" => "Jane", "email" => "[email protected]"} }

before do
Test::Container[:verify] = -> input { Left("raw failure") }
class Test::ContainerRaw
extend Dry::Container::Mixin
register :process_step, -> input { {name: input["name"], email: input["email"]} }
register :verify_step, -> input { Dry::Monads::Left("raw failure") }
register :persist_step, -> input { Test::DB << input and true }
end
end

let(:transaction) {
Class.new do
include Dry::Transaction(container: Test::ContainerRaw)

map :process, with: :process_step
step :verify, with: :verify_step
tee :persist, with: :persist_step
end.new(**dependencies)
}

it "does not run subsequent operations" do
transaction.call(input)
expect(Test::DB).to be_empty
Expand Down Expand Up @@ -284,8 +330,22 @@ def persist(input)
context "non-confirming raw step result" do
let(:input) { {"name" => "Jane", "email" => "[email protected]"} }

let(:transaction) {
Class.new do
include Dry::Transaction(container: Test::ContainerRaw)
map :process
step :verify
tee :persist
end.new(**dependencies)
}

before do
Test::Container[:verify] = -> input { "failure" }
class Test::ContainerRaw
extend Dry::Container::Mixin
register :process, -> input { {name: input["name"], email: input["email"]} }
register :verify, -> input { "failure" }
register :persist, -> input { Test::DB << input and true }
end
end

it "raises an exception" do
Expand Down

0 comments on commit 9d62b10

Please sign in to comment.