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 +5 -5
- data/.rspec +1 -0
- data/CHANGELOG.md +12 -0
- data/README.md +51 -40
- data/lib/safe_operation/failure.rb +3 -6
- data/lib/safe_operation/success.rb +3 -6
- data/lib/safe_operation/version.rb +2 -2
- data/lib/safe_operation.rb +53 -11
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b91d97c00cb10cf98d6811a622637447ebb610da081a40e82a470b4a14d14a56
|
4
|
+
data.tar.gz: 715f3660b7f47295f32c3c221b48f2bbbb9bb5787a62190f8430e9e8c9d85b31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c1304db8d9cbf0a022199fdc6dfb2d52984b01c0a76dd5cceefd5307fb8ea6ef28a6cc084058ef45c9dce706c4faf611ba6f7f7e76ca159bec744c6899b98b5
|
7
|
+
data.tar.gz: b31daab86df7e66d43283eb8c36523ec8b990413f7e2c135b4d8fcac93bfcb2ef3cffb251621506b894ea7fbd2c1bc2270597b9be68feaa8ab5efc244f0d9969
|
data/.rspec
CHANGED
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
|
-
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
any_operation_may_fail = ->{ User.find(1) }
|
3
|
+
[](https://rubygems.org/gems/safe_operation)
|
4
|
+
[](https://travis-ci.org/JuanitoFatas/safe_operation)
|
7
5
|
|
8
|
-
|
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
|
39
|
-
|
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
|
-
|
42
|
-
|
43
|
-
end
|
39
|
+
# Know if operation succeeded
|
40
|
+
operation.success?
|
44
41
|
|
45
|
-
|
46
|
-
|
42
|
+
# Get the value of the performed operation
|
43
|
+
operation.value
|
47
44
|
|
48
|
-
|
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
|
-
|
52
|
-
|
57
|
+
# Apply on first operation
|
58
|
+
operation = SafeOperation.
|
59
|
+
run { User.find(1) }.
|
60
|
+
and_then { |user| Admin.new(user) }
|
53
61
|
|
54
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
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
|
-
|
1
|
+
class SafeOperation
|
2
2
|
class Failure
|
3
3
|
def initialize(failure)
|
4
4
|
@failure = failure
|
5
5
|
end
|
6
6
|
|
7
|
-
def
|
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
|
-
|
1
|
+
class SafeOperation
|
2
2
|
class Success
|
3
3
|
def initialize(success)
|
4
4
|
@success = success
|
5
5
|
end
|
6
6
|
|
7
|
-
def
|
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
|
-
|
2
|
-
VERSION = "
|
1
|
+
class SafeOperation
|
2
|
+
VERSION = "2.0.0"
|
3
3
|
end
|
data/lib/safe_operation.rb
CHANGED
@@ -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
|
-
|
8
|
-
|
8
|
+
class SafeOperation
|
9
|
+
extend Forwardable
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
class << self
|
12
|
+
protected(:new)
|
12
13
|
|
13
|
-
|
14
|
-
|
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
|
-
|
39
|
+
fallback_value
|
17
40
|
end
|
18
|
-
rescue StandardError
|
19
|
-
Failure.new yield
|
20
41
|
end
|
21
42
|
|
22
|
-
|
23
|
-
|
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:
|
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:
|
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
|
-
|
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.
|