From 2a366165f06f3065a54f114c28c484dda04b795f Mon Sep 17 00:00:00 2001 From: Ted Johansson Date: Tue, 6 Jul 2021 14:09:20 +0800 Subject: [PATCH 1/3] Add unsafe #unwrap! method to Result --- lib/stimpack/result_monad/result.rb | 9 +++++++++ spec/stimpack/result_monad/result_spec.rb | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/stimpack/result_monad/result.rb b/lib/stimpack/result_monad/result.rb index 23297e7..7b3c085 100644 --- a/lib/stimpack/result_monad/result.rb +++ b/lib/stimpack/result_monad/result.rb @@ -3,6 +3,8 @@ module Stimpack module ResultMonad class Result < Struct + class UnwrapError < StandardError; end + def successful? errors.nil? end @@ -11,6 +13,13 @@ def failed? !successful? end + def unwrap! + raise UnwrapError, "Can not unwrap a failed result." if failed? + return if klass.blank_result? + + public_send(result_key) + end + def inspect if successful? "<#{klass}:successful #{result_key} : #{self[result_key].inspect}>" diff --git a/spec/stimpack/result_monad/result_spec.rb b/spec/stimpack/result_monad/result_spec.rb index 4d3f652..8ec402f 100644 --- a/spec/stimpack/result_monad/result_spec.rb +++ b/spec/stimpack/result_monad/result_spec.rb @@ -36,4 +36,14 @@ def self.to_s it { expect(instance.error_result(errors: "Oops!").inspect).to eq("") } end end + + describe "#unwrap!" do + context "when result is successful" do + it { expect(instance.success_result(foo: "bar").unwrap!).to eq("bar") } + end + + context "when result is failed" do + it { expect { instance.error_result(errors: "Oops!").unwrap! }.to raise_error(described_class::UnwrapError) } + end + end end From eed058eb1b8fcbd46caa3996f804ad32c89c4deb Mon Sep 17 00:00:00 2001 From: Ted Johansson Date: Tue, 6 Jul 2021 14:15:41 +0800 Subject: [PATCH 2/3] Unwrap and return success value from #guard when passed --- lib/stimpack/result_monad/guard_clause.rb | 2 +- spec/stimpack/result_monad/guard_clause_spec.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/stimpack/result_monad/guard_clause.rb b/lib/stimpack/result_monad/guard_clause.rb index b91bd66..3deab62 100644 --- a/lib/stimpack/result_monad/guard_clause.rb +++ b/lib/stimpack/result_monad/guard_clause.rb @@ -58,7 +58,7 @@ def guard(label = nil, &block) raise GuardFailed, result if result.failed? - result + result.unwrap! end def self.included(klass) diff --git a/spec/stimpack/result_monad/guard_clause_spec.rb b/spec/stimpack/result_monad/guard_clause_spec.rb index 8dbfd62..4142c5f 100644 --- a/spec/stimpack/result_monad/guard_clause_spec.rb +++ b/spec/stimpack/result_monad/guard_clause_spec.rb @@ -27,9 +27,9 @@ def self.to_s def call guard :foo - guard { bar } + intermediate = guard { bar } - success(foo: "bar") + success(foo: intermediate) end private @@ -56,6 +56,7 @@ def bar double( Stimpack::ResultMonad::Result, failed?: false, + unwrap!: "Foo", errors: [] ) end @@ -86,6 +87,7 @@ def bar end it { expect(instance.()).to be_successful } + it { expect(instance.().foo).to eq("Foo") } end context "when a guard fails" do From 3af906f59e5c4fd8dc3c5d8d619fd1369675d440 Mon Sep 17 00:00:00 2001 From: Ted Johansson Date: Wed, 7 Jul 2021 13:46:01 +0800 Subject: [PATCH 3/3] Add ResultMonad::GuardClause#pass method which can be used to pass guards --- CHANGELOG.md | 6 ++++++ README.md | 6 +++--- lib/stimpack/result_monad/guard_clause.rb | 8 ++++++++ lib/stimpack/version.rb | 2 +- spec/stimpack/result_monad/guard_clause_spec.rb | 13 +++++++++---- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a9cc1d..8c92f5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.7.1 + +### New features + +- Add `ResultMonad::GuardClause#pass` method which can be used to pass guards. + ## 0.7.0 ### New features diff --git a/README.md b/README.md index 0e08223..97db3fc 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ class Foo def call guard :bar_guard - guard { baz_guard } + qux = guard { baz_guard } end private @@ -329,9 +329,9 @@ class Foo def baz_guard if qux? - error(errors: ["Qux failed."]) + pass("Qux") else - success + error(errors: ["Qux failed."]) end end end diff --git a/lib/stimpack/result_monad/guard_clause.rb b/lib/stimpack/result_monad/guard_clause.rb index 3deab62..5461523 100644 --- a/lib/stimpack/result_monad/guard_clause.rb +++ b/lib/stimpack/result_monad/guard_clause.rb @@ -2,6 +2,8 @@ module Stimpack module ResultMonad + PassResult = Result.new(:klass, :errors, :_value, keyword_init: true) + # This module adds a `#guard` method, which can be used inside a `#call` # to declare a step which, if it fails, breaks the flow of the method and # propagates the error result. @@ -61,6 +63,12 @@ def guard(label = nil, &block) result.unwrap! end + # A standardized result object which can be used to pass guards. + # + def pass(value = nil) + PassResult.new(klass: self.class, errors: nil, _value: value) + end + def self.included(klass) klass.prepend(GuardCatcher) end diff --git a/lib/stimpack/version.rb b/lib/stimpack/version.rb index ed8911f..1072409 100644 --- a/lib/stimpack/version.rb +++ b/lib/stimpack/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Stimpack - VERSION = "0.7.0" + VERSION = "0.7.1" end diff --git a/spec/stimpack/result_monad/guard_clause_spec.rb b/spec/stimpack/result_monad/guard_clause_spec.rb index 4142c5f..ce198f5 100644 --- a/spec/stimpack/result_monad/guard_clause_spec.rb +++ b/spec/stimpack/result_monad/guard_clause_spec.rb @@ -27,9 +27,10 @@ def self.to_s def call guard :foo - intermediate = guard { bar } + bar_result = guard { bar } + baz_result = guard { baz } - success(foo: intermediate) + success(foo: bar_result + baz_result) end private @@ -41,6 +42,10 @@ def foo def bar # Stubbed in test cases. end + + def baz + pass("Baz") + end end end @@ -57,7 +62,7 @@ def bar Stimpack::ResultMonad::Result, failed?: false, unwrap!: "Foo", - errors: [] + errors: nil ) end @@ -87,7 +92,7 @@ def bar end it { expect(instance.()).to be_successful } - it { expect(instance.().foo).to eq("Foo") } + it { expect(instance.().foo).to eq("FooBaz") } end context "when a guard fails" do