ytry 0.0.1 → 1.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 +4 -4
- data/README.md +57 -2
- data/lib/ytry.rb +12 -9
- data/lib/ytry/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 445fb840f8d15382ce1b280cdc6f746b907e2dfb
|
4
|
+
data.tar.gz: 559d814425ba8e70f0e23932890922d99a5393d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4dcc9c8e5518b8ed3ee38e9d2c6fed5c858f6bcb64dcb72adc86e6bc61950b211d4de880cb8ed0bbbb9f79f589ea9709fda6130bfd7499599fb16c5368c4d33
|
7
|
+
data.tar.gz: 3d65b7ee4d84e21b90f42c84ba11a91cc27f8d26bfa3235bb9377823dfa97b7d712ad7ff74a1866b3c945b834f6daaa57307683fc3defc3e75628f20025c32d6
|
data/README.md
CHANGED
@@ -23,9 +23,64 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
## Basic usage
|
25
25
|
|
26
|
-
The Try type represents a computation that may either result in an
|
26
|
+
The Try type represents a computation that may either result in an error, or return a successfully computed value.
|
27
27
|
|
28
|
-
|
28
|
+
If the block passed to Try runs with no errors, then a `Success` wrapping the computed value is returned.
|
29
|
+
|
30
|
+
An instance of `Failure` wrapping the error is returned otherwise.
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
require 'ytry'
|
34
|
+
include Ytry
|
35
|
+
|
36
|
+
Try { 1 + 1 } # Success(2)
|
37
|
+
|
38
|
+
Try { 1 / 0 } # Failure(#<ZeroDivisionError: divided by 0>)
|
39
|
+
```
|
40
|
+
|
41
|
+
`Success` and `Failure` provide a unified API that lets us express a sequence of tranformations in a fluent way, without error handling cluttering the flow:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
def load_and_parse json_file
|
45
|
+
Try { File.read(json_file) }
|
46
|
+
.map {|content| JSON.parse(content)}
|
47
|
+
.select {|table| table.is_a? Array}
|
48
|
+
.recover {|e| puts "Recovering from #{e.message}"; []}
|
49
|
+
end
|
50
|
+
|
51
|
+
load_and_parse(nonexisting_file) # prints "Recovering from No such file..." # Success([])
|
52
|
+
|
53
|
+
load_and_parse(wrong_format_file) # prints "Recovering from Element not found" # Success([])
|
54
|
+
|
55
|
+
load_and_parse(actual_file) # Success([{"id"=>1, "name"=>"Lorenzo", "dob"=>"22/07/1985"}])
|
56
|
+
```
|
57
|
+
|
58
|
+
`Try#map` and `Try#recover` are means to interact with the value wrapped by a Try in a safe way - i.e. with no risk of errors being raised.
|
59
|
+
|
60
|
+
`Try#select` transforms a Success into a Failure when the underlying value does not satisfy the given predicate - i.e. the given block returns false. That can be useful when validating some input.
|
61
|
+
|
62
|
+
`Try#get_or_else` provides a safe way of retrieving the possibly-missing value it contains. It returns the result of the given block when the Try is a Failure. It is equivalent to `Try#get` when the Try is a Success.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
invalid_json = "[\"missing_quote]"
|
66
|
+
|
67
|
+
Try { JSON.parse(invalid_json) }
|
68
|
+
.get_or_else{ [] } # []
|
69
|
+
|
70
|
+
Try { JSON.parse("[]") }
|
71
|
+
.get_or_else { fail "this block is ignored"} # []
|
72
|
+
```
|
73
|
+
|
74
|
+
It is preferable to use `Try#get_or_else` over `Try#get`, as `#get` will raise an error when called on a Failure. It is possible to check for failure via `#empty?`, but that tipically leads to non-idiomatic code
|
75
|
+
|
76
|
+
## Why Try?
|
77
|
+
|
78
|
+
Using Try instead of rescue blocks can make your software both clearer and safer as it
|
79
|
+
|
80
|
+
- leads to less verbose error handling
|
81
|
+
- simplifies the way we deal with operations that might fail for several reasons (such as IO operations)
|
82
|
+
- privileges method chaining thus reducing the need for auxiliary variables to store intermediate results in a computation
|
83
|
+
- encourages programming towards immutability, where the data is transformed rather than mutated in place.
|
29
84
|
|
30
85
|
## Development
|
31
86
|
|
data/lib/ytry.rb
CHANGED
@@ -15,11 +15,17 @@ module Ytry
|
|
15
15
|
raise Try.invalid_argument('Argument must be an array-like object', value) unless value.respond_to? :to_ary
|
16
16
|
return value if value.is_a? Try
|
17
17
|
value.to_ary.empty? ?
|
18
|
-
Failure.new(RuntimeError.new("
|
18
|
+
Failure.new(RuntimeError.new("Element not found").tap{|ex| ex.set_backtrace(caller)}) :
|
19
19
|
Success.new(value.to_ary.first)
|
20
20
|
end
|
21
|
-
def
|
22
|
-
|
21
|
+
def self.zip *try_array
|
22
|
+
first_failure = try_array.find(&:empty?)
|
23
|
+
first_failure.nil? ? Success.new(try_array.map(&:get)) : first_failure
|
24
|
+
end
|
25
|
+
def each
|
26
|
+
return enum_for(__method__) unless block_given?
|
27
|
+
yield self.get unless empty?
|
28
|
+
return self
|
23
29
|
end
|
24
30
|
%i(map select reject collect collect_concat).each do |method|
|
25
31
|
define_method method, ->(&block) {
|
@@ -35,17 +41,14 @@ module Ytry
|
|
35
41
|
Try.ary_to_type(wrapped_result.flatten)
|
36
42
|
end
|
37
43
|
def grep(pattern, &block)
|
38
|
-
Try.ary_to_type
|
44
|
+
self.empty? ? self : Try.ary_to_type(Try{super}.flatten)
|
39
45
|
end
|
40
46
|
def flatten
|
41
47
|
return self if empty?
|
42
48
|
Try.ary_to_type self.get
|
43
49
|
end
|
44
50
|
def zip *others
|
45
|
-
|
46
|
-
return Failure.new(Exception.new) if self.empty? || others.any?(&:empty?)
|
47
|
-
collection = others.reduce(self.to_a, &:concat)
|
48
|
-
Success.new collection
|
51
|
+
Try.zip(self, *others)
|
49
52
|
end
|
50
53
|
def | lambda
|
51
54
|
self.flat_map &lambda # slow but easy to read + supports symbols out of the box
|
@@ -94,7 +97,7 @@ module Ytry
|
|
94
97
|
end
|
95
98
|
def get() raise @error end
|
96
99
|
def empty?() true end
|
97
|
-
def to_s() "Failure(#{@error})" end
|
100
|
+
def to_s() "Failure(#{@error.inspect})" end
|
98
101
|
def to_ary() [] end
|
99
102
|
def == other
|
100
103
|
other.is_a?(Failure) && self.error == other.error
|
data/lib/ytry/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ytry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lorenzo.barasti
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|