safe_operation 1.0.0 → 2.0.0

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
- 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.