safe_operation 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1e94fff35d4584131e4618984db17237d7e0eb20
4
- data.tar.gz: 5990172463731f5ea965977ab30ebca21a7c5fe5
2
+ SHA256:
3
+ metadata.gz: b91d97c00cb10cf98d6811a622637447ebb610da081a40e82a470b4a14d14a56
4
+ data.tar.gz: 715f3660b7f47295f32c3c221b48f2bbbb9bb5787a62190f8430e9e8c9d85b31
5
5
  SHA512:
6
- metadata.gz: b386772b2152fd9699f92fd7050b6da0086e503abc8082d309739302fd611eb0f9312169920cf4bae598a1c9f26385a1ff94f3439fe151ebc8aae5821ee2aaee
7
- data.tar.gz: aa6ddc9cb1ed18e8621476d42c2806d87775621bd46fe91e3ca9564e92e10e7a2634fd82b8b1678e6779643459545db3c17bbf6ac072b8375fdb2e98a2fd9c1e
6
+ metadata.gz: 3c1304db8d9cbf0a022199fdc6dfb2d52984b01c0a76dd5cceefd5307fb8ea6ef28a6cc084058ef45c9dce706c4faf611ba6f7f7e76ca159bec744c6899b98b5
7
+ data.tar.gz: b31daab86df7e66d43283eb8c36523ec8b990413f7e2c135b4d8fcac93bfcb2ef3cffb251621506b894ea7fbd2c1bc2270597b9be68feaa8ab5efc244f0d9969
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --format documentation
data/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.0.0
6
+
7
+ - Drop support for v1.0.0
8
+ - v2.0.0 redesigned the API of SafeOperation:
9
+
10
+ SafeOperation.run
11
+
12
+ SafeOperation#value_or
13
+ SafeOperation#value_or_else
14
+ SafeOperation#and_then
15
+ SafeOperation#or_else
16
+
5
17
  ## 1.0.0
6
18
 
7
19
  First implementation ([#1][pr1]) - 2017.07.09
data/README.md CHANGED
@@ -1,20 +1,9 @@
1
1
  # SafeOperation
2
2
 
3
- Write safer code with SafeOperation.
4
-
5
- ```ruby
6
- any_operation_may_fail = ->{ User.find(1) }
3
+ [![Gem Version](https://badge.fury.io/rb/safe_operation.svg)](https://rubygems.org/gems/safe_operation)
4
+ [![Build Status](https://travis-ci.org/JuanitoFatas/safe_operation.svg?branch=master)](https://travis-ci.org/JuanitoFatas/safe_operation)
7
5
 
8
- operation = SafeOperation.either(any_operation_may_fail) do
9
- # MUST handle the failure here
10
- end
11
-
12
- # know if operation succeeded
13
- operation.success?
14
-
15
- # get the result of the performed operation
16
- operation.result
17
- ```
6
+ Write safer code with SafeOperation.
18
7
 
19
8
  ## Installation
20
9
 
@@ -34,46 +23,68 @@ Or install it yourself as:
34
23
 
35
24
  ## Usage
36
25
 
26
+ No monkey patch.
27
+
37
28
  ```ruby
38
- class User
39
- ActiveRecordRecordNotFound = Class.new(StandardError)
29
+ class RecordNotFound < StandardError; end
30
+ class User def self.find(id); new; end; end;
31
+ class Guest; end
32
+ class Admin; def initialize(user); end; end
33
+ class SuperAdmin; def initialize(admin); end; end
34
+
35
+ operation = SafeOperation.run do
36
+ User.find(1)
37
+ end
40
38
 
41
- def self.find(id)
42
- (id == 1) ? new : raise(ActiveRecordRecordNotFound)
43
- end
39
+ # Know if operation succeeded
40
+ operation.success?
44
41
 
45
- def self.find_by(*); end
46
- end
42
+ # Get the value of the performed operation
43
+ operation.value
47
44
 
48
- class Guest
45
+ # Common patterns, reloaded
46
+ SafeOperation.run { User.find(1) }.value_or(Guest.new)
47
+
48
+ # Handling exceptions
49
+ SafeOperation.run { raise(RecordNotFound) }.value_or_else do |exception|
50
+ if exception.is_a?(RecordNotFound)
51
+ Guest.new
52
+ else
53
+ # logging, re-raise, etc.
54
+ end
49
55
  end
50
56
 
51
- SafeOperation.either(->{ User.find(1) })
52
- # => raises an SafeOperation::NoFailureHandler error
57
+ # Apply on first operation
58
+ operation = SafeOperation.
59
+ run { User.find(1) }.
60
+ and_then { |user| Admin.new(user) }
53
61
 
54
- SafeOperation.either(->{ User.find(1) }) do
55
- Guest.new
56
- end
57
- # => returns a SafeOperation::Success object with User
58
- # => #<SafeOperation::Success:0x007fbc8d8c5ae0 @success=#<User:0x007fbc8d8c5b08>>
62
+ operation.value # #<Admin ...>
59
63
 
60
- SafeOperation.either(->{ User.find(2) }) do
61
- Guest.new
62
- end
63
- # => rescue ActiveRecordRecordNotFound, returns a SafeOperation::Failure object with Guest
64
- # #<SafeOperation::Failure:0x007fbc8dbb71e0 @failure=#<Guest:0x007fbc8dbb7208>>
64
+ # Chainable
65
+ operation = SafeOperation.
66
+ run { User.find(1) }.
67
+ and_then { |user| Admin.new(user) }.
68
+ and_then { |admin| SuperAdmin.new(admin) }
65
69
 
66
- SafeOperation.either(->{ User.find_by(id: 42) }) do
67
- Guest.new
68
- end
69
- # => returns a SafeOperation::Failure object with Guest
70
- # #<SafeOperation::Failure:0x007fbc8dbb71e0 @failure=#<Guest:0x007fbc8dbb7208>>
70
+ operation.value # #<SuperAdmin ...>
71
+
72
+ # Add or_else to handle failed operation
73
+ operation = SafeOperation.
74
+ run { raise(RecordNotFound) }.
75
+ and_then { |user| Admin.new(user) }.
76
+ or_else { Guest.new }
77
+
78
+ operation.success? # => false
79
+ operation.value # => #<Guest ...>
71
80
  ```
72
81
 
82
+ See test suite for more examples.
83
+
73
84
  ## Contributing
74
85
 
75
86
  This project follows the [Moya Contributors Guidelines][moya].
76
- TLDR: means we give out push access easily and often.
87
+ TLDR: means we give out commit access easily and often.
77
88
 
78
89
  [moya]: https://github.com/Moya/contributors
79
90
 
@@ -1,18 +1,15 @@
1
- module SafeOperation
1
+ class SafeOperation
2
2
  class Failure
3
3
  def initialize(failure)
4
4
  @failure = failure
5
5
  end
6
6
 
7
- def result
8
- failure
7
+ def value
8
+ @failure
9
9
  end
10
10
 
11
11
  def success?
12
12
  false
13
13
  end
14
-
15
- private
16
- attr_reader :failure
17
14
  end
18
15
  end
@@ -1,18 +1,15 @@
1
- module SafeOperation
1
+ class SafeOperation
2
2
  class Success
3
3
  def initialize(success)
4
4
  @success = success
5
5
  end
6
6
 
7
- def result
8
- success
7
+ def value
8
+ @success
9
9
  end
10
10
 
11
11
  def success?
12
12
  true
13
13
  end
14
-
15
- private
16
- attr_reader :success
17
14
  end
18
15
  end
@@ -1,3 +1,3 @@
1
- module SafeOperation
2
- VERSION = "1.0.0"
1
+ class SafeOperation
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,24 +1,66 @@
1
1
  # frozen_string_literal: true
2
+ require "forwardable"
2
3
 
3
4
  require_relative "safe_operation/version"
4
5
  require_relative "safe_operation/success"
5
6
  require_relative "safe_operation/failure"
6
7
 
7
- module SafeOperation
8
- NoFailureHandler = Class.new NotImplementedError
8
+ class SafeOperation
9
+ extend Forwardable
9
10
 
10
- def self.either(maybe_block)
11
- raise NoFailureHandler if !block_given?
11
+ class << self
12
+ protected(:new)
12
13
 
13
- if maybe = maybe_block.call
14
- Success.new maybe
14
+ def run
15
+ success(yield)
16
+ rescue StandardError => exception
17
+ failure(exception)
18
+ end
19
+
20
+ def success(value)
21
+ new(success: value)
22
+ end
23
+
24
+ def failure(value)
25
+ new(failure: value)
26
+ end
27
+ end
28
+
29
+ def_delegators :@result, :success?, :value
30
+
31
+ def initialize(success: nil, failure: nil)
32
+ @result = success ? Success.new(success) : Failure.new(failure)
33
+ end
34
+
35
+ def value_or(fallback_value)
36
+ if success?
37
+ value
15
38
  else
16
- Failure.new yield
39
+ fallback_value
17
40
  end
18
- rescue StandardError
19
- Failure.new yield
20
41
  end
21
42
 
22
- NO_FAILURE_HANDLER_MESSAGE = "Please pass in a block to handle the failure 😅"
23
- private_constant :NO_FAILURE_HANDLER_MESSAGE
43
+ def value_or_else(&fallback_block)
44
+ if success?
45
+ value
46
+ else
47
+ fallback_block.call(value)
48
+ end
49
+ end
50
+
51
+ def and_then(&block)
52
+ if success?
53
+ self.class.success(block.call(value))
54
+ else
55
+ self
56
+ end
57
+ end
58
+
59
+ def or_else(&block)
60
+ if success?
61
+ self
62
+ else
63
+ self.class.failure(block.call(value))
64
+ end
65
+ end
24
66
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safe_operation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juanito Fatas
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-07-09 00:00:00.000000000 Z
11
+ date: 2019-04-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Write safer code with SafeOperation.
14
14
  email:
@@ -52,8 +52,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0'
54
54
  requirements: []
55
- rubyforge_project:
56
- rubygems_version: 2.6.12
55
+ rubygems_version: 3.0.1
57
56
  signing_key:
58
57
  specification_version: 4
59
58
  summary: Write safer code with SafeOperation.