to-result 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0bf957670d51788e15be5797daeb430d409cc38967e9f3ba93027ce66eefe93c
4
- data.tar.gz: 5500df2709d9dd14780e53858cf6a2a10fe029d90d3c097e11280104983fdf44
3
+ metadata.gz: 842070fb5be7a4388055318b3956091d4869885c76d745c0dd01ba87cde415e5
4
+ data.tar.gz: 0a7c4e93685409f3f96479df8482255e501a88db53523c55d2f5f171255f58a3
5
5
  SHA512:
6
- metadata.gz: 80580831a173303c62330c741bccaa6bb6edad1155ef9639e33c4e1076132cff165b0a7a9d6d91d2a9d472a69841c3f6fd7af9ab177edcbc6488e8d34d958c14
7
- data.tar.gz: 92eda88e706fbe5b330a5417190904d158487e469c726e64d07380e334efb07b9f30def99a2e6f19fa3e354d184cd9892287d18f02dbffe2130cadf5f351abf4
6
+ metadata.gz: c16327c7a1420c8c1b711d98ffd59de246a3221c98dd6a3bae2cf3650c731c558ccbb02effccdd25d6f9f99e0097d030d751cf8c1dac40569b97dd95b4845817
7
+ data.tar.gz: 23d78aac99bc431eb9b47aafe9aca8dde5b95615766a60305ce016638a3c26e74ac632f5c19bf9c913a5ce70a2ba14d187dc3aea99f8c5876155db4ad9cbed34
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in pulsarcli.gemspec
6
+ gemspec
7
+
8
+ gem 'dry-monads', '~> 1.4'
9
+
10
+ gem 'byebug', '~> 11.1'
11
+
12
+ gem 'minitest', '~> 5.16'
13
+
14
+ gem 'mocha', '~> 1.15'
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ to-result (0.0.3)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ byebug (11.1.3)
10
+ concurrent-ruby (1.1.10)
11
+ dry-core (0.8.1)
12
+ concurrent-ruby (~> 1.0)
13
+ dry-monads (1.4.0)
14
+ concurrent-ruby (~> 1.0)
15
+ dry-core (~> 0.7)
16
+ minitest (5.16.3)
17
+ mocha (1.15.0)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ byebug (~> 11.1)
24
+ dry-monads (~> 1.4)
25
+ minitest (~> 5.16)
26
+ mocha (~> 1.15)
27
+ to-result!
28
+
29
+ BUNDLED WITH
30
+ 2.3.15
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Christian
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,134 @@
1
+
2
+ # ToResult
3
+
4
+ ToResult is a wrapper built over `dry-monads` to make the `Do Notation`, `Result` and `Try` concepts more handy and consistent to use, in particular to implement the **Railway Pattern**.
5
+
6
+ ## Why I created ToResult
7
+
8
+ `dry-monads` is full of edge cases that require to write boilerplate code everytime I want a method to return a `Success` or `Failure`, for example:
9
+
10
+ ```ruby
11
+ def my_method
12
+ Success(another_method.call)
13
+ rescue StandardError => e
14
+ Failure(e)
15
+ end
16
+ ```
17
+
18
+ so I started using `Try`, that makes the code easier to read and faster to write:
19
+ ```ruby
20
+ def my_method
21
+ Try do
22
+ another_method.call
23
+ end.to_result
24
+ end
25
+ ```
26
+
27
+ but I feel like `to_result` is not really visible at the end of the code and if you forget to write it (as always happens to me) your application blows up.
28
+
29
+ But this is not the bigget problem, bear with me.
30
+
31
+ One of the biggest problem is that we cannot use the `Do Notation` inside a `Try` block:
32
+ ```ruby
33
+ # this will return a Failure(Dry::Monads::Do::Halt)
34
+ def my_method
35
+ Try do
36
+ yield Failure('error code')
37
+ end.to_result
38
+ end
39
+ ```
40
+
41
+ and you cannot even use `yield` and `rescue` in the same method:
42
+
43
+ ```ruby
44
+ # this will return a Failure(Dry::Monads::Do::Halt)
45
+ def my_method
46
+ yield Failure('error code')
47
+ rescue StandardError => e
48
+ # e is an instance of Dry::Monads::Do::Halt
49
+ Failure(e)
50
+ end
51
+ ```
52
+
53
+ because they will raise a `Dry::Monads::Do::Halt` exception and the original exception will be forever lost if we do not "unbox" the exception with `e.result`.
54
+
55
+ ## Installation
56
+
57
+ To install with bundler:
58
+ ```bash
59
+ bundle add to-result
60
+ ```
61
+ or with `gem`:
62
+ ```bash
63
+ gem install to-result
64
+ ```
65
+
66
+ ## Usage
67
+
68
+ To use it with instances of a class, just include it
69
+ ```ruby
70
+ require 'to_result'
71
+
72
+ class MyClass
73
+ include ToResultMixin
74
+
75
+ def my_method
76
+ ToResult do
77
+ whatever_method.call
78
+ end
79
+ end
80
+ end
81
+ ```
82
+
83
+ or if you want to use it with Singleton Classes:
84
+ ```ruby
85
+ require 'to_result'
86
+
87
+ class MyClass
88
+ extend ToResultMixin
89
+
90
+ class << self
91
+ def my_method
92
+ ToResult do
93
+ whatever_method.call
94
+ end
95
+ end
96
+ end
97
+ end
98
+ ```
99
+
100
+ now you can always use `ToResult` all the time you wanted to use `Success`, `Failure` or `Try` but with a more convenient interface and consistent behaviour.
101
+
102
+ Look at this:
103
+
104
+ ```ruby
105
+ ToResult { raise StandardError.new('error code') }
106
+ # returns Failure(StandardError('error code'))
107
+
108
+ ToResult { yield Success('hello!') }
109
+ # returns Success('hello!')
110
+
111
+ ToResult { yield Failure('error code') }
112
+ # returns Failure('error code')
113
+
114
+ ToResult { yield Failure(StandardError.new('error code')) }
115
+ # returns Failure(StandardError('error code'))
116
+
117
+ ToResult([YourCustomError]) { yield Failure(YourCustomError.new('error code')) }
118
+ # returns Failure(YourCustomError('error code'))
119
+
120
+ ToResult([ArgumentError]) { yield Failure(YourCustomError.new('error code')) }
121
+ # raises YourCustomError('error code')
122
+ ```
123
+
124
+ ## Roadmap
125
+ I'm already planning to implement some useful features:
126
+ - [x] write more examples/documentation/tests
127
+ - [ ] configurable error logging when an exception is catched inside `DoResult`
128
+ e.g. sending the log to Airbrake or whathever service you are using
129
+ - [ ] transform/process the catched error
130
+ - [ ] any other suggestion would be appreciated 😁
131
+
132
+ ## Authors
133
+
134
+ - [@a-chris](https://www.github.com/a-chris)
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'to-result'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -3,6 +3,17 @@ require 'dry/monads'
3
3
  module ToResultMixin
4
4
  include Dry::Monads[:do, :result, :try]
5
5
 
6
+ Configuration = Struct.new(:on_error)
7
+
8
+ @@configuration = Configuration.new(on_error: nil)
9
+
10
+ #
11
+ # Allow to override the @@configuration fields
12
+ #
13
+ def self.configure
14
+ yield @@configuration
15
+ end
16
+
6
17
  #
7
18
  # ToResult executes a block of code and returns Success or Failure.
8
19
  # All exceptions inherited from StandardError are catched and
@@ -20,8 +31,11 @@ module ToResultMixin
20
31
  Proc.new do
21
32
  f.call
22
33
  rescue Dry::Monads::Do::Halt => e
23
- return e.result
34
+ error = e.result
35
+ @@configuration.on_error.call(error) if @@configuration.on_error.respond_to?(:call)
36
+ return error
24
37
  rescue *exceptions => e
38
+ @@configuration.on_error.call(e) if @@configuration.on_error.respond_to?(:call)
25
39
  raise e
26
40
  end
27
41
  ).to_result
@@ -0,0 +1,5 @@
1
+ class FakeLogger
2
+ def self.log_error
3
+ true
4
+ end
5
+ end
@@ -0,0 +1,68 @@
1
+ require 'minitest/autorun'
2
+ require 'mocha/minitest'
3
+ require 'byebug'
4
+
5
+ require './lib/to-result'
6
+ require './tests/support/fake_logger'
7
+
8
+ class ToResultTest < Minitest::Test
9
+ include ToResultMixin
10
+
11
+ def setup
12
+ super
13
+ @value = 'hello world!'
14
+ end
15
+
16
+ def teardown
17
+ super
18
+
19
+ # reset the configuration after each test
20
+ ToResultMixin.configure { |c| c = {} }
21
+ end
22
+
23
+ def test_string
24
+ assert ToResult { @value } == Success(@value)
25
+ end
26
+
27
+ def test_success
28
+ expected = Success(@value)
29
+ assert ToResult { expected } == Success(expected)
30
+ end
31
+
32
+ def test_exception
33
+ expected = StandardError.new(@value)
34
+ assert ToResult { raise expected } == Failure(expected)
35
+ end
36
+
37
+ def test_exception_included_in_exceptions_list
38
+ expected = ArgumentError.new(@value)
39
+ assert ToResult([ArgumentError]) { raise expected } == Failure(expected)
40
+ end
41
+
42
+ def test_exception_not_included_in_exceptions_list
43
+ expected = NameError.new(@value)
44
+ assert_raises(NameError) { ToResult([ArgumentError]) { raise expected } }
45
+ end
46
+
47
+ def test_yield_failure
48
+ expected = Failure(@value)
49
+ # this will raise a Dry::Monads::Do::Halt exception
50
+ assert ToResult { yield expected } == expected
51
+ end
52
+
53
+ def test_yield_failure_exception
54
+ expected = Failure(StandardError.new(@value))
55
+ # this will raise a Dry::Monads::Do::Halt exception
56
+ assert ToResult { yield expected } == expected
57
+ end
58
+
59
+ def test_on_error
60
+ FakeLogger.expects(:log_error).once
61
+
62
+ ToResultMixin.configure do |c|
63
+ c.on_error = Proc.new { FakeLogger.log_error }
64
+ end
65
+
66
+ ToResult { raise StandardError.new(@value) }
67
+ end
68
+ end
data/to-result.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'to-result'
8
+ s.version = '0.0.3'
9
+ s.summary = 'A wrapper over dry-monads to offer a handy and consistent way to implement the Railway pattern.'
10
+ s.description = 'A wrapper over dry-monads to offer a handy and consistent way to implement the Railway pattern.'
11
+ s.authors = ['Christian Toscano']
12
+ s.homepage = 'https://github.com/a-chris/to-result'
13
+ s.license = 'MIT'
14
+
15
+ s.require_paths = ['lib']
16
+ s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).reject { |f| (f == '.gitignore') || f =~ /^examples/ }
17
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: to-result
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Toscano
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-18 00:00:00.000000000 Z
11
+ date: 2022-10-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A wrapper over dry-monads to offer a handy and consistent way to implement
14
14
  the Railway pattern.
@@ -17,7 +17,15 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - lib/to_result.rb
20
+ - Gemfile
21
+ - Gemfile.lock
22
+ - LICENSE
23
+ - README.md
24
+ - bin/console
25
+ - lib/to-result.rb
26
+ - tests/support/fake_logger.rb
27
+ - tests/to_result_test.rb
28
+ - to-result.gemspec
21
29
  homepage: https://github.com/a-chris/to-result
22
30
  licenses:
23
31
  - MIT