fear 1.1.0 → 1.2.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/.github/workflows/rubocop.yml +39 -0
- data/.github/workflows/spec.yml +42 -0
- data/.rubocop.yml +1 -1
- data/.simplecov +17 -0
- data/CHANGELOG.md +12 -3
- data/Gemfile +0 -2
- data/Gemfile.lock +80 -39
- data/README.md +158 -9
- data/Rakefile +27 -0
- data/examples/pattern_extracting.rb +1 -1
- data/examples/pattern_extracting_ruby2.7.rb +15 -0
- data/examples/pattern_matching_binary_tree_set.rb +3 -0
- data/examples/pattern_matching_number_in_words.rb +2 -0
- data/fear.gemspec +7 -8
- data/lib/dry/types/fear.rb +8 -0
- data/lib/dry/types/fear/option.rb +125 -0
- data/lib/fear.rb +9 -0
- data/lib/fear/awaitable.rb +2 -2
- data/lib/fear/either.rb +5 -0
- data/lib/fear/either_pattern_match.rb +3 -0
- data/lib/fear/extractor.rb +2 -0
- data/lib/fear/extractor/any_matcher.rb +1 -1
- data/lib/fear/extractor/array_splat_matcher.rb +1 -1
- data/lib/fear/extractor/empty_list_matcher.rb +1 -1
- data/lib/fear/extractor/matcher.rb +0 -3
- data/lib/fear/extractor/pattern.rb +1 -0
- data/lib/fear/extractor/value_matcher.rb +1 -1
- data/lib/fear/failure.rb +7 -0
- data/lib/fear/future.rb +12 -6
- data/lib/fear/future_api.rb +2 -2
- data/lib/fear/left.rb +1 -0
- data/lib/fear/none.rb +18 -0
- data/lib/fear/option.rb +22 -0
- data/lib/fear/option_pattern_match.rb +1 -0
- data/lib/fear/partial_function.rb +6 -0
- data/lib/fear/partial_function/empty.rb +2 -0
- data/lib/fear/pattern_matching_api.rb +1 -0
- data/lib/fear/right.rb +2 -0
- data/lib/fear/some.rb +28 -0
- data/lib/fear/struct.rb +13 -0
- data/lib/fear/success.rb +6 -0
- data/lib/fear/try_pattern_match.rb +3 -0
- data/lib/fear/utils.rb +13 -0
- data/lib/fear/version.rb +1 -1
- data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
- data/spec/dry/types/fear/option/core_spec.rb +77 -0
- data/spec/dry/types/fear/option/default_spec.rb +21 -0
- data/spec/dry/types/fear/option/hash_spec.rb +58 -0
- data/spec/dry/types/fear/option/option_spec.rb +97 -0
- data/spec/fear/awaitable_spec.rb +17 -0
- data/spec/fear/either_pattern_matching_spec.rb +28 -0
- data/spec/fear/future_spec.rb +11 -2
- data/spec/fear/none_spec.rb +1 -1
- data/spec/fear/option_pattern_matching_spec.rb +34 -0
- data/spec/fear/option_spec.rb +128 -0
- data/spec/fear/partial_function_spec.rb +50 -0
- data/spec/fear/pattern_matching_api_spec.rb +31 -0
- data/spec/fear/try_pattern_matching_spec.rb +34 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/struct_pattern_matching_spec.rb +36 -0
- data/spec/struct_spec.rb +2 -2
- data/spec/support/dry_types.rb +6 -0
- metadata +110 -12
- data/.travis.yml +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27594ab99bc8a361057d1222bd4e70aa49f5c8535c95f622f338ab17e216cd31
|
4
|
+
data.tar.gz: dfbd5982e2da247cdb74edb7a218023195c4806d56af786098e294165bf345ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c880fdc1a916306cd222bb4d63526aa3b9ab19eadb095df1ea2aef4343e443015b8067628a34a0b436dc5d994f39fd8810b03dbb05adc7d6df975eb1943bee7
|
7
|
+
data.tar.gz: f9e9c441b5d208b65cbd678ae38412d404879834e1ca3ac6636140aa9b53bbb6c1ddf88b613c52d74cb6b09c481a0983c5a3e903c19ee5f98ca94161eb541ba9
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# pulled from repo
|
2
|
+
name: "Rubocop"
|
3
|
+
|
4
|
+
on: push
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
rubocop:
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
strategy:
|
10
|
+
fail-fast: false
|
11
|
+
|
12
|
+
steps:
|
13
|
+
- name: Checkout repository
|
14
|
+
uses: actions/checkout@v2
|
15
|
+
|
16
|
+
# If running on a self-hosted runner, check it meets the requirements
|
17
|
+
# listed at https://github.com/ruby/setup-ruby#using-self-hosted-runners
|
18
|
+
- name: Set up Ruby
|
19
|
+
uses: ruby/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: 2.6
|
22
|
+
|
23
|
+
# This step is not necessary if you add the gem to your Gemfile
|
24
|
+
- name: Install Code Scanning integration
|
25
|
+
run: bundle add code-scanning-rubocop --version 0.4.0 --skip-install
|
26
|
+
|
27
|
+
- name: Install dependencies
|
28
|
+
run: bundle install
|
29
|
+
|
30
|
+
- name: Rubocop run
|
31
|
+
run: |
|
32
|
+
bash -c "
|
33
|
+
bundle exec rubocop --require code_scanning --format CodeScanning::SarifFormatter -o rubocop.sarif
|
34
|
+
[[ $? -ne 2 ]]
|
35
|
+
"
|
36
|
+
- name: Upload Sarif output
|
37
|
+
uses: github/codeql-action/upload-sarif@v1
|
38
|
+
with:
|
39
|
+
sarif_file: rubocop.sarif
|
@@ -0,0 +1,42 @@
|
|
1
|
+
name: Spec
|
2
|
+
|
3
|
+
on: [push]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby: [ '2.5.x', '2.6.x', '2.7.x' ]
|
11
|
+
name: ${{ matrix.ruby }}
|
12
|
+
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v1
|
15
|
+
- name: Set up ruby
|
16
|
+
uses: actions/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: ${{ matrix.ruby }}
|
19
|
+
- name: Install dependencies
|
20
|
+
run: |
|
21
|
+
gem install bundler --force --version=2.0.1
|
22
|
+
bundler --version
|
23
|
+
bundle install --jobs 4 --retry 3
|
24
|
+
- name: Test
|
25
|
+
run: bundle exec rspec
|
26
|
+
- name: Coveralls
|
27
|
+
uses: coverallsapp/github-action@v1.1.2
|
28
|
+
with:
|
29
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
30
|
+
flag-name: ruby-${{ matrix.ruby }}
|
31
|
+
parallel: true
|
32
|
+
|
33
|
+
|
34
|
+
finish:
|
35
|
+
needs: test
|
36
|
+
runs-on: ubuntu-latest
|
37
|
+
steps:
|
38
|
+
- name: Coveralls Finished
|
39
|
+
uses: coverallsapp/github-action@master
|
40
|
+
with:
|
41
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
42
|
+
parallel-finished: true
|
data/.rubocop.yml
CHANGED
data/.simplecov
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "simplecov-lcov"
|
4
|
+
|
5
|
+
SimpleCov::Formatter::LcovFormatter.config do |c|
|
6
|
+
c.report_with_single_file = true
|
7
|
+
c.single_report_path = "coverage/lcov.info"
|
8
|
+
end
|
9
|
+
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new(
|
10
|
+
[
|
11
|
+
SimpleCov::Formatter::HTMLFormatter,
|
12
|
+
SimpleCov::Formatter::LcovFormatter,
|
13
|
+
],
|
14
|
+
)
|
15
|
+
SimpleCov.start do
|
16
|
+
add_filter "spec/"
|
17
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,17 @@
|
|
1
|
+
## 1.2.0
|
2
|
+
|
3
|
+
* Implement `Fear::Option#zip` and `Fear::Future#zip` with block argument ([@bolshakov][])
|
4
|
+
* Drop ruby 2.4.x support, test against ruby 2.7.x ([@bolshakov][])
|
5
|
+
* Implement `Fear::Option#filter_map` ([@bolshakov][])
|
6
|
+
* Add dry-types extentions to wrap nullable values. ([@bolshakov][])
|
7
|
+
* Implement pattern matching for ruby >= 2.7
|
8
|
+
* Deprecate `Fear.xcase`
|
9
|
+
|
1
10
|
## 1.1.0
|
2
11
|
|
3
|
-
* Add `Fear::Await.ready` and `Fear::Await.result`.
|
4
|
-
* Add callback versions with pattern matching `Fear::Future#on_success_match`, `#on_failure_match` and `#on_complete_match`.
|
5
|
-
* Implement immutable `Fear::Struct
|
12
|
+
* Add `Fear::Await.ready` and `Fear::Await.result`. ([@bolshakov][])
|
13
|
+
* Add callback versions with pattern matching `Fear::Future#on_success_match`, `#on_failure_match` and `#on_complete_match`. ([@bolshakov][])
|
14
|
+
* Implement immutable `Fear::Struct`. ([@bolshakov][])
|
6
15
|
|
7
16
|
## 1.0.0
|
8
17
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
GIT
|
2
|
-
remote:
|
2
|
+
remote: https://github.com/baweaver/qo.git
|
3
3
|
revision: 8951ce899559118eb60321014b43cf4211730bd0
|
4
4
|
specs:
|
5
5
|
qo (0.99.0)
|
@@ -8,7 +8,7 @@ GIT
|
|
8
8
|
PATH
|
9
9
|
remote: .
|
10
10
|
specs:
|
11
|
-
fear (1.
|
11
|
+
fear (1.2.0)
|
12
12
|
lru_redux
|
13
13
|
treetop
|
14
14
|
|
@@ -16,56 +16,92 @@ GEM
|
|
16
16
|
remote: https://rubygems.org/
|
17
17
|
specs:
|
18
18
|
any (0.1.0)
|
19
|
-
ast (2.4.
|
20
|
-
benchmark-ips (2.
|
21
|
-
concurrent-ruby (1.1.
|
22
|
-
diff-lcs (1.
|
23
|
-
|
19
|
+
ast (2.4.1)
|
20
|
+
benchmark-ips (2.8.3)
|
21
|
+
concurrent-ruby (1.1.7)
|
22
|
+
diff-lcs (1.4.4)
|
23
|
+
docile (1.3.2)
|
24
|
+
dry-configurable (0.11.6)
|
24
25
|
concurrent-ruby (~> 1.0)
|
25
|
-
|
26
|
-
|
26
|
+
dry-core (~> 0.4, >= 0.4.7)
|
27
|
+
dry-equalizer (~> 0.2)
|
28
|
+
dry-container (0.7.2)
|
29
|
+
concurrent-ruby (~> 1.0)
|
30
|
+
dry-configurable (~> 0.1, >= 0.1.3)
|
31
|
+
dry-core (0.4.9)
|
32
|
+
concurrent-ruby (~> 1.0)
|
33
|
+
dry-equalizer (0.3.0)
|
34
|
+
dry-inflector (0.2.0)
|
35
|
+
dry-logic (1.0.6)
|
36
|
+
concurrent-ruby (~> 1.0)
|
37
|
+
dry-core (~> 0.2)
|
38
|
+
dry-equalizer (~> 0.2)
|
39
|
+
dry-matcher (0.8.0)
|
40
|
+
dry-core (>= 0.4.7)
|
27
41
|
dry-monads (1.2.0)
|
28
42
|
concurrent-ruby (~> 1.0)
|
29
43
|
dry-core (~> 0.4, >= 0.4.4)
|
30
44
|
dry-equalizer
|
31
|
-
|
32
|
-
|
45
|
+
dry-types (1.4.0)
|
46
|
+
concurrent-ruby (~> 1.0)
|
47
|
+
dry-container (~> 0.3)
|
48
|
+
dry-core (~> 0.4, >= 0.4.4)
|
49
|
+
dry-equalizer (~> 0.3)
|
50
|
+
dry-inflector (~> 0.1, >= 0.1.2)
|
51
|
+
dry-logic (~> 1.0, >= 1.0.2)
|
52
|
+
fear-rspec (0.3.0)
|
53
|
+
fear (>= 1.0.0)
|
54
|
+
rspec (~> 3.0)
|
55
|
+
irb (1.1.0)
|
56
|
+
reline (>= 0.0.1)
|
33
57
|
lru_redux (1.1.0)
|
34
|
-
parallel (1.
|
35
|
-
parser (2.
|
36
|
-
ast (~> 2.4.
|
58
|
+
parallel (1.20.0)
|
59
|
+
parser (2.7.2.0)
|
60
|
+
ast (~> 2.4.1)
|
37
61
|
polyglot (0.3.5)
|
38
62
|
rainbow (3.0.0)
|
39
|
-
rake (
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
rspec-
|
46
|
-
|
63
|
+
rake (13.0.1)
|
64
|
+
regexp_parser (1.8.2)
|
65
|
+
reline (0.0.7)
|
66
|
+
rexml (3.2.4)
|
67
|
+
rspec (3.10.0)
|
68
|
+
rspec-core (~> 3.10.0)
|
69
|
+
rspec-expectations (~> 3.10.0)
|
70
|
+
rspec-mocks (~> 3.10.0)
|
71
|
+
rspec-core (3.10.0)
|
72
|
+
rspec-support (~> 3.10.0)
|
73
|
+
rspec-expectations (3.10.0)
|
47
74
|
diff-lcs (>= 1.2.0, < 2.0)
|
48
|
-
rspec-support (~> 3.
|
49
|
-
rspec-mocks (3.
|
75
|
+
rspec-support (~> 3.10.0)
|
76
|
+
rspec-mocks (3.10.0)
|
50
77
|
diff-lcs (>= 1.2.0, < 2.0)
|
51
|
-
rspec-support (~> 3.
|
52
|
-
rspec-support (3.
|
53
|
-
rubocop (0.
|
54
|
-
jaro_winkler (~> 1.5.1)
|
78
|
+
rspec-support (~> 3.10.0)
|
79
|
+
rspec-support (3.10.0)
|
80
|
+
rubocop (1.0.0)
|
55
81
|
parallel (~> 1.10)
|
56
|
-
parser (>= 2.
|
82
|
+
parser (>= 2.7.1.5)
|
57
83
|
rainbow (>= 2.2.2, < 4.0)
|
84
|
+
regexp_parser (>= 1.8)
|
85
|
+
rexml
|
86
|
+
rubocop-ast (>= 0.6.0)
|
58
87
|
ruby-progressbar (~> 1.7)
|
59
|
-
unicode-display_width (>= 1.4.0, <
|
60
|
-
rubocop-
|
88
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
89
|
+
rubocop-ast (1.1.1)
|
90
|
+
parser (>= 2.7.1.5)
|
91
|
+
rubocop-rspec (1.34.0)
|
61
92
|
rubocop (>= 0.60.0)
|
62
93
|
ruby-progressbar (1.10.1)
|
63
|
-
ruby_coding_standard (0.
|
64
|
-
rubocop
|
65
|
-
|
94
|
+
ruby_coding_standard (0.3.0)
|
95
|
+
rubocop (~> 1.0.0)
|
96
|
+
simplecov (0.19.1)
|
97
|
+
docile (~> 1.1)
|
98
|
+
simplecov-html (~> 0.11)
|
99
|
+
simplecov-html (0.12.3)
|
100
|
+
simplecov-lcov (0.8.0)
|
101
|
+
treetop (1.6.11)
|
66
102
|
polyglot (~> 0.3)
|
67
|
-
unicode-display_width (1.
|
68
|
-
yard (0.9.
|
103
|
+
unicode-display_width (1.7.0)
|
104
|
+
yard (0.9.25)
|
69
105
|
|
70
106
|
PLATFORMS
|
71
107
|
ruby
|
@@ -76,14 +112,19 @@ DEPENDENCIES
|
|
76
112
|
concurrent-ruby
|
77
113
|
dry-matcher
|
78
114
|
dry-monads
|
115
|
+
dry-types
|
79
116
|
fear!
|
117
|
+
fear-rspec
|
80
118
|
irb
|
81
119
|
qo!
|
82
|
-
rake (~>
|
120
|
+
rake (~> 13.0)
|
83
121
|
rspec (~> 3.1)
|
84
|
-
rubocop
|
122
|
+
rubocop (= 1.0.0)
|
123
|
+
rubocop-rspec (= 1.34.0)
|
85
124
|
ruby_coding_standard
|
125
|
+
simplecov
|
126
|
+
simplecov-lcov
|
86
127
|
yard
|
87
128
|
|
88
129
|
BUNDLED WITH
|
89
|
-
2.0.
|
130
|
+
2.0.2
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Fear
|
2
|
-
[](https://travis-ci.org/bolshakov/fear)
|
3
2
|
[](https://badge.fury.io/rb/fear)
|
3
|
+

|
4
|
+
[](https://codeclimate.com/github/bolshakov/fear/maintainability)
|
5
|
+
[](https://coveralls.io/github/bolshakov/fear?branch=master)
|
4
6
|
|
5
7
|
This gem provides `Option`, `Either`, and `Try` monads implemented an idiomatic way.
|
6
8
|
It is highly inspired by scala's implementation.
|
@@ -23,11 +25,11 @@ Or install it yourself as:
|
|
23
25
|
|
24
26
|
## Usage
|
25
27
|
|
26
|
-
* [Option](#option-documentation)
|
27
|
-
* [Try](#try-documentation)
|
28
|
-
* [Either](#either-documentation)
|
29
|
-
* [Future](#future-documentation)
|
30
|
-
* [For composition](#for-composition)
|
28
|
+
* [Option](#option-api-documentation)
|
29
|
+
* [Try](#try-api-documentation)
|
30
|
+
* [Either](#either-api-documentation)
|
31
|
+
* [Future](#future-api-documentation)
|
32
|
+
* [For composition](#for-composition-api-documentation)
|
31
33
|
* [Pattern Matching](#pattern-matching-api-documentation)
|
32
34
|
|
33
35
|
### Option ([API Documentation](https://www.rubydoc.info/github/bolshakov/fear/master/Fear/Option))
|
@@ -153,12 +155,24 @@ Fear.none.any? { |v| v > 10 } #=> false
|
|
153
155
|
Returns self if it is nonempty and applying the predicate to this `Option`'s value returns `true`. Otherwise,
|
154
156
|
return `None`.
|
155
157
|
|
156
|
-
```ruby
|
158
|
+
```ruby
|
157
159
|
Fear.some(42).select { |v| v > 40 } #=> Fear.success(21)
|
158
160
|
Fear.some(42).select { |v| v < 40 } #=> None
|
159
161
|
Fear.none.select { |v| v < 40 } #=> None
|
160
162
|
```
|
161
163
|
|
164
|
+
#### Option#filter_map
|
165
|
+
|
166
|
+
Returns a new `Some` of truthy results (everything except `false` or `nil`) of
|
167
|
+
running the block or `None` otherwise.
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
Fear.some(42).filter_map { |v| v/2 if v.even? } #=> Fear.some(21)
|
171
|
+
Fear.some(42).filter_map { |v| v/2 if v.odd? } #=> Fear.none
|
172
|
+
Fear.some(42).filter_map { |v| false } #=> Fear.none
|
173
|
+
Fear.none.filter_map { |v| v/2 } #=> Fear.none
|
174
|
+
```
|
175
|
+
|
162
176
|
#### Option#reject
|
163
177
|
|
164
178
|
Returns `Some` if applying the predicate to this `Option`'s value returns `false`. Otherwise, return `None`.
|
@@ -182,6 +196,19 @@ Fear.some(42).empty? #=> false
|
|
182
196
|
Fear.none.empty? #=> true
|
183
197
|
```
|
184
198
|
|
199
|
+
#### Option#zip
|
200
|
+
|
201
|
+
Returns a `Fear::Some` formed from this Option and another Option by combining the corresponding elements in a pair.
|
202
|
+
If either of the two options is empty, `Fear::None` is returned.
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
Fear.some("foo").zip(Fear.some("bar")) #=> Fear.some(["foo", "bar"])
|
206
|
+
Fear.some("foo").zip(Fear.some("bar")) { |x, y| x + y } #=> Fear.some("foobar")
|
207
|
+
Fear.some("foo").zip(Fear.none) #=> Fear.none
|
208
|
+
Fear.none.zip(Fear.some("bar")) #=> Fear.none
|
209
|
+
|
210
|
+
```
|
211
|
+
|
185
212
|
@see https://github.com/scala/scala/blob/2.11.x/src/library/scala/Option.scala
|
186
213
|
|
187
214
|
|
@@ -625,7 +652,7 @@ Fear.left("flower").join_right #=> Fear.left("flower")
|
|
625
652
|
Fear.left(Fear.right("flower")).join_right #=> Fear.left(Fear.right("flower"))
|
626
653
|
```
|
627
654
|
|
628
|
-
#### Either#
|
655
|
+
#### Either#join_left
|
629
656
|
|
630
657
|
Joins an `Either` through `Left`. This method requires that the left side of this `Either` is itself an
|
631
658
|
`Either` type. This method, and `join_right`, are analogous to `Option#flatten`
|
@@ -1171,7 +1198,7 @@ matcher.(Fear.some(40)) #=> 'Nope'
|
|
1171
1198
|
#### Under the hood
|
1172
1199
|
|
1173
1200
|
Pattern matcher is a combination of partial functions wrapped into nice DSL. Every partial function
|
1174
|
-
defined on domain described with guard.
|
1201
|
+
defined on domain described with a guard.
|
1175
1202
|
|
1176
1203
|
```ruby
|
1177
1204
|
pf = Fear.case(Integer) { |x| x / 2 }
|
@@ -1233,6 +1260,128 @@ handle.(12) #=> 'bigger than ten'
|
|
1233
1260
|
handle.('one') #=> 1
|
1234
1261
|
```
|
1235
1262
|
|
1263
|
+
### Native pattern-matching
|
1264
|
+
|
1265
|
+
Starting from ruby 2.7 you can use native pattern matching capabilities:
|
1266
|
+
|
1267
|
+
```ruby
|
1268
|
+
case Fear.some(42)
|
1269
|
+
in Fear::Some(x)
|
1270
|
+
x * 2
|
1271
|
+
in Fear::None
|
1272
|
+
'none'
|
1273
|
+
end #=> 84
|
1274
|
+
|
1275
|
+
case Fear.some(41)
|
1276
|
+
in Fear::Some(x) if x.even?
|
1277
|
+
x / 2
|
1278
|
+
in Fear::Some(x) if x.odd? && x > 0
|
1279
|
+
x * 2
|
1280
|
+
in Fear::None
|
1281
|
+
'none'
|
1282
|
+
end #=> 82
|
1283
|
+
|
1284
|
+
case Fear.some(42)
|
1285
|
+
in Fear::Some(x) if x.odd?
|
1286
|
+
x * 2
|
1287
|
+
else
|
1288
|
+
'nothing'
|
1289
|
+
end #=> nothing
|
1290
|
+
```
|
1291
|
+
|
1292
|
+
It's possible to pattern match against Fear::Either and Fear::Try as well:
|
1293
|
+
|
1294
|
+
```ruby
|
1295
|
+
case either
|
1296
|
+
in Fear::Right(Integer | String => x)
|
1297
|
+
"integer or string: #{x}"
|
1298
|
+
in Fear::Left(String => error_code) if error_code = :not_found
|
1299
|
+
'not found'
|
1300
|
+
end
|
1301
|
+
```
|
1302
|
+
|
1303
|
+
```ruby
|
1304
|
+
case Fear.try { 10 / x }
|
1305
|
+
in Fear::Failure(ZeroDivisionError)
|
1306
|
+
# ..
|
1307
|
+
in Fear::Success(x)
|
1308
|
+
# ..
|
1309
|
+
end
|
1310
|
+
```
|
1311
|
+
|
1312
|
+
### Dry-Types integration
|
1313
|
+
|
1314
|
+
#### Option
|
1315
|
+
|
1316
|
+
NOTE: Requires the dry-tyes gem to be loaded.
|
1317
|
+
|
1318
|
+
Load the `:fear_option` extension in your application.
|
1319
|
+
|
1320
|
+
```ruby
|
1321
|
+
require 'dry-types'
|
1322
|
+
require 'dry/types/fear'
|
1323
|
+
|
1324
|
+
Dry::Types.load_extensions(:fear_option)
|
1325
|
+
|
1326
|
+
module Types
|
1327
|
+
include Dry.Types()
|
1328
|
+
end
|
1329
|
+
```
|
1330
|
+
|
1331
|
+
Append .option to a Type to return a `Fear::Option` object:
|
1332
|
+
|
1333
|
+
```ruby
|
1334
|
+
Types::Option::Strict::Integer[nil]
|
1335
|
+
#=> Fear.none
|
1336
|
+
Types::Option::Coercible::String[nil]
|
1337
|
+
#=> Fear.none
|
1338
|
+
Types::Option::Strict::Integer[123]
|
1339
|
+
#=> Fear.some(123)
|
1340
|
+
Types::Option::Strict::String[123]
|
1341
|
+
#=> Fear.some(123)
|
1342
|
+
Types::Option::Coercible::Float['12.3']
|
1343
|
+
#=> Fear.some(12.3)
|
1344
|
+
```
|
1345
|
+
|
1346
|
+
'Option' types can also accessed by calling '.option' on a regular type:
|
1347
|
+
|
1348
|
+
```ruby
|
1349
|
+
Types::Strict::Integer.option # equivalent to Types::Option::Strict::Integer
|
1350
|
+
```
|
1351
|
+
|
1352
|
+
|
1353
|
+
You can define your own optional types:
|
1354
|
+
|
1355
|
+
```ruby
|
1356
|
+
option_string = Types::Strict::String.option
|
1357
|
+
option_string[nil]
|
1358
|
+
# => Fear.none
|
1359
|
+
option_string[nil].map(&:upcase)
|
1360
|
+
# => Fear.none
|
1361
|
+
option_string['something']
|
1362
|
+
# => Fear.some('something')
|
1363
|
+
option_string['something'].map(&:upcase)
|
1364
|
+
# => Fear.some('SOMETHING')
|
1365
|
+
option_string['something'].map(&:upcase).get_or_else { 'NOTHING' }
|
1366
|
+
# => "SOMETHING"
|
1367
|
+
```
|
1368
|
+
|
1369
|
+
You can use it with dry-struct as well:
|
1370
|
+
|
1371
|
+
```ruby
|
1372
|
+
class User < Dry::Struct
|
1373
|
+
attribute :name, Types::Coercible::String
|
1374
|
+
attribute :age, Types::Coercible::Integer.option
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
user = User.new(name: 'Bob', age: nil)
|
1378
|
+
user.name #=> "Bob"
|
1379
|
+
user.age #=> Fear.none
|
1380
|
+
|
1381
|
+
user = User.new(name: 'Bob', age: 42)
|
1382
|
+
user.age #=> Fear.some(42)
|
1383
|
+
```
|
1384
|
+
|
1236
1385
|
## Testing
|
1237
1386
|
|
1238
1387
|
To simplify testing, you may use [fear-rspec](https://github.com/bolshakov/fear-rspec) gem. It
|