fear 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://travis-ci.org/bolshakov/fear.svg?branch=master)](https://travis-ci.org/bolshakov/fear)
|
3
2
|
[![Gem Version](https://badge.fury.io/rb/fear.svg)](https://badge.fury.io/rb/fear)
|
3
|
+
![Specs](https://github.com/bolshakov/fear/workflows/Spec/badge.svg)
|
4
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/01030620c59e9f40961b/maintainability)](https://codeclimate.com/github/bolshakov/fear/maintainability)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/github/bolshakov/fear/badge.svg?branch=master)](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
|