fear 0.11.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +0 -1
- data/.rubocop.yml +18 -0
- data/.travis.yml +0 -3
- data/CHANGELOG.md +12 -1
- data/Gemfile +1 -0
- data/{gemfiles/dry_equalizer_0.2.1.gemfile.lock → Gemfile.lock} +21 -12
- data/README.md +594 -241
- data/Rakefile +166 -219
- data/benchmarks/README.md +1 -0
- data/benchmarks/dry_do_vs_fear_for.txt +11 -0
- data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
- data/benchmarks/factorial.txt +16 -0
- data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
- data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
- data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
- data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
- data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
- data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
- data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
- data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
- data/examples/pattern_extracting.rb +15 -0
- data/examples/pattern_matching_binary_tree_set.rb +96 -0
- data/examples/pattern_matching_number_in_words.rb +54 -0
- data/fear.gemspec +4 -2
- data/lib/fear.rb +21 -4
- data/lib/fear/either.rb +77 -59
- data/lib/fear/either_api.rb +21 -0
- data/lib/fear/empty_partial_function.rb +1 -1
- data/lib/fear/extractor.rb +108 -0
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +8 -0
- data/lib/fear/extractor/any_matcher.rb +15 -0
- data/lib/fear/extractor/array_head_matcher.rb +34 -0
- data/lib/fear/extractor/array_matcher.rb +38 -0
- data/lib/fear/extractor/array_splat_matcher.rb +14 -0
- data/lib/fear/extractor/empty_list_matcher.rb +18 -0
- data/lib/fear/extractor/extractor_matcher.rb +42 -0
- data/lib/fear/extractor/grammar.rb +201 -0
- data/lib/fear/extractor/grammar.treetop +129 -0
- data/lib/fear/extractor/identifier_matcher.rb +16 -0
- data/lib/fear/extractor/matcher.rb +54 -0
- data/lib/fear/extractor/matcher/and.rb +36 -0
- data/lib/fear/extractor/named_array_splat_matcher.rb +15 -0
- data/lib/fear/extractor/pattern.rb +55 -0
- data/lib/fear/extractor/typed_identifier_matcher.rb +24 -0
- data/lib/fear/extractor/value_matcher.rb +17 -0
- data/lib/fear/extractor_api.rb +33 -0
- data/lib/fear/failure.rb +32 -10
- data/lib/fear/for.rb +14 -69
- data/lib/fear/for_api.rb +66 -0
- data/lib/fear/future.rb +414 -0
- data/lib/fear/future_api.rb +19 -0
- data/lib/fear/left.rb +8 -0
- data/lib/fear/none.rb +17 -8
- data/lib/fear/option.rb +55 -49
- data/lib/fear/option_api.rb +38 -0
- data/lib/fear/partial_function.rb +9 -12
- data/lib/fear/partial_function/empty.rb +1 -1
- data/lib/fear/partial_function/guard.rb +8 -20
- data/lib/fear/partial_function/lifted.rb +1 -0
- data/lib/fear/partial_function_class.rb +10 -0
- data/lib/fear/pattern_match.rb +10 -0
- data/lib/fear/pattern_matching_api.rb +35 -11
- data/lib/fear/promise.rb +87 -0
- data/lib/fear/right.rb +8 -0
- data/lib/fear/some.rb +22 -3
- data/lib/fear/success.rb +22 -1
- data/lib/fear/try.rb +82 -67
- data/lib/fear/try_api.rb +31 -0
- data/lib/fear/unit.rb +28 -0
- data/lib/fear/version.rb +1 -1
- data/spec/fear/done_spec.rb +3 -3
- data/spec/fear/either/mixin_spec.rb +15 -0
- data/spec/fear/either_pattern_match_spec.rb +10 -12
- data/spec/fear/extractor/array_matcher_spec.rb +228 -0
- data/spec/fear/extractor/extractor_matcher_spec.rb +151 -0
- data/spec/fear/extractor/grammar_array_spec.rb +23 -0
- data/spec/fear/extractor/identified_matcher_spec.rb +47 -0
- data/spec/fear/extractor/identifier_matcher_spec.rb +66 -0
- data/spec/fear/extractor/pattern_spec.rb +32 -0
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +62 -0
- data/spec/fear/extractor/value_matcher_number_spec.rb +77 -0
- data/spec/fear/extractor/value_matcher_string_spec.rb +86 -0
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +69 -0
- data/spec/fear/extractor_api_spec.rb +113 -0
- data/spec/fear/extractor_spec.rb +59 -0
- data/spec/fear/failure_spec.rb +73 -13
- data/spec/fear/for_spec.rb +35 -35
- data/spec/fear/future_spec.rb +466 -0
- data/spec/fear/guard_spec.rb +4 -4
- data/spec/fear/left_spec.rb +40 -14
- data/spec/fear/none_spec.rb +28 -12
- data/spec/fear/option/mixin_spec.rb +37 -0
- data/spec/fear/option_pattern_match_spec.rb +7 -9
- data/spec/fear/partial_function_spec.rb +25 -3
- data/spec/fear/pattern_match_spec.rb +33 -1
- data/spec/fear/promise_spec.rb +94 -0
- data/spec/fear/right_spec.rb +37 -9
- data/spec/fear/some_spec.rb +32 -6
- data/spec/fear/success_spec.rb +32 -4
- data/spec/fear/try/mixin_spec.rb +17 -0
- data/spec/fear/try_pattern_match_spec.rb +8 -10
- data/spec/spec_helper.rb +1 -1
- metadata +115 -20
- data/Appraisals +0 -32
- data/gemfiles/dry_equalizer_0.1.0.gemfile +0 -8
- data/gemfiles/dry_equalizer_0.1.0.gemfile.lock +0 -82
- data/gemfiles/dry_equalizer_0.2.1.gemfile +0 -8
- data/lib/fear/done.rb +0 -22
- data/spec/fear/option_spec.rb +0 -15
@@ -0,0 +1 @@
|
|
1
|
+
See Rakefile
|
@@ -0,0 +1,11 @@
|
|
1
|
+
> bundle exec rake perf:dry:do_vs_fear_for
|
2
|
+
Warming up --------------------------------------
|
3
|
+
Dry 31.375k i/100ms
|
4
|
+
Fear 24.131k i/100ms
|
5
|
+
Calculating -------------------------------------
|
6
|
+
Dry 360.990k (± 2.7%) i/s - 1.820M in 5.045364s
|
7
|
+
Fear 7.212B (±27.2%) i/s - 27.210B in 4.656760s
|
8
|
+
|
9
|
+
Comparison:
|
10
|
+
Fear: 7212177713.5 i/s
|
11
|
+
Dry: 360989.8 i/s - 19978.90x slower
|
@@ -0,0 +1,11 @@
|
|
1
|
+
> bundle exec rake perf:dry:some_fmap_vs_fear_some_map
|
2
|
+
Warming up --------------------------------------
|
3
|
+
Dry 68.154k i/100ms
|
4
|
+
Fear 151.093k i/100ms
|
5
|
+
Calculating -------------------------------------
|
6
|
+
Dry 884.315k (± 4.1%) i/s - 4.430M in 5.018931s
|
7
|
+
Fear 2.481M (± 4.1%) i/s - 12.390M in 5.003728s
|
8
|
+
|
9
|
+
Comparison:
|
10
|
+
Fear: 2480589.0 i/s
|
11
|
+
Dry: 884315.1 i/s - 2.81x slower
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Depends on `n`, for 100!:
|
2
|
+
|
3
|
+
> bundle exec rake perf:pattern_matching:factorial
|
4
|
+
Warming up --------------------------------------
|
5
|
+
Proc 2.395k i/100ms
|
6
|
+
Fear 312.000 i/100ms
|
7
|
+
Qo 122.000 i/100ms
|
8
|
+
Calculating -------------------------------------
|
9
|
+
Proc 26.620k (± 2.9%) i/s - 134.120k in 5.042738s
|
10
|
+
Fear 3.219k (± 4.1%) i/s - 16.224k in 5.049215s
|
11
|
+
Qo 1.250k (± 4.8%) i/s - 6.344k in 5.090745s
|
12
|
+
|
13
|
+
Comparison:
|
14
|
+
Proc: 26620.3 i/s
|
15
|
+
Fear: 3219.4 i/s - 8.27x slower
|
16
|
+
Qo: 1249.6 i/s - 21.30x slower
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# It verifies that optimization for Partial Functions with only one guard actually works.
|
2
|
+
|
3
|
+
> bundle exec rake perf:fear:guard:and1_vs_new
|
4
|
+
Warming up --------------------------------------
|
5
|
+
Guard.new 173.019k i/100ms
|
6
|
+
Guard.and1 268.379k i/100ms
|
7
|
+
Calculating -------------------------------------
|
8
|
+
Guard.new 171.291B (± 8.4%) i/s - 561.437B
|
9
|
+
Guard.and1 266.882B (± 5.9%) i/s - 751.316B
|
10
|
+
|
11
|
+
Comparison:
|
12
|
+
Guard.and1: 266881817299.6 i/s
|
13
|
+
Guard.new: 171291386467.1 i/s - 1.56x slower
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# It verifies that optimization for Partial Functions with two guards actually works.
|
2
|
+
|
3
|
+
> bundle exec rake perf:fear:guard:and2_vs_guard_and_guard
|
4
|
+
Warming up --------------------------------------
|
5
|
+
and2 224.836k i/100ms
|
6
|
+
Guard#and 211.833k i/100ms
|
7
|
+
Calculating -------------------------------------
|
8
|
+
and2 224.457B (± 3.8%) i/s - 651.564B
|
9
|
+
Guard#and 211.486B (± 3.7%) i/s - 667.936B
|
10
|
+
|
11
|
+
Comparison:
|
12
|
+
and2: 224457051906.8 i/s
|
13
|
+
Guard#and: 211485786834.4 i/s - same-ish: difference falls within error
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# It verifies that optimization for Partial Functions with three guards actually works.
|
2
|
+
|
3
|
+
> bundle exec rake perf:fear:guard:and3_vs_and_and
|
4
|
+
Warming up --------------------------------------
|
5
|
+
Guard.and3 236.318k i/100ms
|
6
|
+
Guard#and 170.369k i/100ms
|
7
|
+
Calculating -------------------------------------
|
8
|
+
Guard.and3 235.992B (± 3.4%) i/s - 791.166B
|
9
|
+
Guard#and 169.998B (± 4.0%) i/s - 640.637B
|
10
|
+
|
11
|
+
Comparison:
|
12
|
+
Guard.and3: 235992292688.6 i/s
|
13
|
+
Guard#and: 169997755111.1 i/s - 1.39x slower
|
@@ -0,0 +1,11 @@
|
|
1
|
+
> bundle exec rake perf:fear:pattern_extracting_with_vs_without_cache
|
2
|
+
Warming up --------------------------------------
|
3
|
+
With cache 1.555k i/100ms
|
4
|
+
Without cache 164.000 i/100ms
|
5
|
+
Calculating -------------------------------------
|
6
|
+
With cache 26.159M (±14.7%) i/s - 124.607M in 4.958175s
|
7
|
+
Without cache 278.285k (±10.5%) i/s - 1.368M in 4.993567s
|
8
|
+
|
9
|
+
Comparison:
|
10
|
+
With cache: 26159162.8 i/s
|
11
|
+
Without cache: 278285.4 i/s - 94.00x slower
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# So, it's better to avoid building pattern match in runtime
|
2
|
+
|
3
|
+
> bundle exec rake perf:fear:pattern_matching_construction_vs_execution
|
4
|
+
Warming up --------------------------------------
|
5
|
+
construction 24.425k i/100ms
|
6
|
+
execution 80.516k i/100ms
|
7
|
+
Calculating -------------------------------------
|
8
|
+
construction 267.887k (± 4.9%) i/s - 1.343M in 5.029005s
|
9
|
+
execution 1.085M (± 2.6%) i/s - 5.475M in 5.049775s
|
10
|
+
|
11
|
+
Comparison:
|
12
|
+
execution: 1084968.2 i/s
|
13
|
+
construction: 267886.6 i/s - 4.05x slower
|
@@ -0,0 +1,14 @@
|
|
1
|
+
> bundle exec rake perf:pattern_matching:dry_vs_qo_vs_fear_try
|
2
|
+
Warming up --------------------------------------
|
3
|
+
Qo 2.958k i/100ms
|
4
|
+
Fear 7.127k i/100ms
|
5
|
+
Dr::Matcher 13.079k i/100ms
|
6
|
+
Calculating -------------------------------------
|
7
|
+
Qo 38.872k (± 3.1%) i/s - 195.228k in 5.027249s
|
8
|
+
Fear 88.756k (± 3.7%) i/s - 449.001k in 5.066471s
|
9
|
+
Dr::Matcher 166.700k (± 3.0%) i/s - 837.056k in 5.026408s
|
10
|
+
|
11
|
+
Comparison:
|
12
|
+
Dr::Matcher: 166699.7 i/s
|
13
|
+
Fear: 88755.7 i/s - 1.88x slower
|
14
|
+
Qo: 38871.9 i/s - 4.29x slower
|
@@ -0,0 +1,11 @@
|
|
1
|
+
> bundle exec rake perf:pattern_matching:qo_vs_fear_pattern_extraction
|
2
|
+
Warming up --------------------------------------
|
3
|
+
Qo 12.352k i/100ms
|
4
|
+
Fear 6.841k i/100ms
|
5
|
+
Calculating -------------------------------------
|
6
|
+
Qo 142.416k (± 4.3%) i/s - 716.416k in 5.040430s
|
7
|
+
Fear 88.179k (± 4.8%) i/s - 444.665k in 5.055908s
|
8
|
+
|
9
|
+
Comparison:
|
10
|
+
Qo: 142415.6 i/s
|
11
|
+
Fear: 88179.5 i/s - 1.62x slower
|
@@ -0,0 +1,11 @@
|
|
1
|
+
> bundle exec rake perf:pattern_matching:qo_vs_fear_try_execution
|
2
|
+
Warming up --------------------------------------
|
3
|
+
Qo 10.079k i/100ms
|
4
|
+
Fear 25.868k i/100ms
|
5
|
+
Calculating -------------------------------------
|
6
|
+
Qo 142.209k (± 3.8%) i/s - 715.609k in 5.039975s
|
7
|
+
Fear 395.999k (± 2.5%) i/s - 1.992M in 5.033046s
|
8
|
+
|
9
|
+
Comparison:
|
10
|
+
Fear: 395999.2 i/s
|
11
|
+
Qo: 142209.4 i/s - 2.78x slower
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fear'
|
2
|
+
|
3
|
+
User = Struct.new(:id, :name, :admin)
|
4
|
+
|
5
|
+
matcher = Fear.matcher do |m|
|
6
|
+
m.xcase('User(_, name, true)') do |name:|
|
7
|
+
puts "Hi #{name}, you are welcome"
|
8
|
+
end
|
9
|
+
m.xcase('User(_, _, false)') do
|
10
|
+
puts 'Only admins allowed here'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
matcher.call User.new(1, 'Jane', true)
|
15
|
+
matcher.call User.new(1, 'John', false)
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'fear'
|
2
|
+
|
3
|
+
# @example Usage
|
4
|
+
# set = BinaryTreeSet.new
|
5
|
+
# set.add(4)
|
6
|
+
# set.includes?(4) #=> true
|
7
|
+
# set.includes?(5) #=> false
|
8
|
+
# set.delete(4)
|
9
|
+
# set.includes?(4) #=> false
|
10
|
+
#
|
11
|
+
class BinaryTreeSet
|
12
|
+
Position = Module.new
|
13
|
+
Right = Module.new.include(Position)
|
14
|
+
Left = Module.new.include(Position)
|
15
|
+
|
16
|
+
def initialize(elem = 0, removed: true)
|
17
|
+
@elem = elem
|
18
|
+
@removed = removed
|
19
|
+
@subtrees = {}
|
20
|
+
end
|
21
|
+
attr_reader :elem, :subtrees
|
22
|
+
attr_accessor :removed
|
23
|
+
private :elem
|
24
|
+
private :removed
|
25
|
+
private :subtrees
|
26
|
+
|
27
|
+
# @param value [Integer]
|
28
|
+
# @return [Boolean]
|
29
|
+
def includes?(value)
|
30
|
+
Fear.match(value) do |m|
|
31
|
+
m.case(elem) { !removed }
|
32
|
+
m.case(->(x) { x > elem }) { |v| includes_in_leaf?(Right, v) }
|
33
|
+
m.case(->(x) { x < elem }) { |v| includes_in_leaf?(Left, v) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param position [Position]
|
38
|
+
# @param value [Integer]
|
39
|
+
# @return [Boolean]
|
40
|
+
private def includes_in_leaf?(position, value)
|
41
|
+
leaf(position).match do |m|
|
42
|
+
m.some { |leaf| leaf.includes?(value) }
|
43
|
+
m.none { false }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param value [Integer]
|
48
|
+
# @return [void]
|
49
|
+
def add(value)
|
50
|
+
Fear.match(value) do |m|
|
51
|
+
m.case(elem) { self.removed = false }
|
52
|
+
m.case(->(x) { x > elem }) { |v| add_to_leaf(Right, v) }
|
53
|
+
m.case(->(x) { x < elem }) { |v| add_to_leaf(Left, v) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param position [Position]
|
58
|
+
# @param value [Integer]
|
59
|
+
# @return [void]
|
60
|
+
private def add_to_leaf(position, value)
|
61
|
+
leaf(position).match do |m|
|
62
|
+
m.some { |leaf| leaf.add(value) }
|
63
|
+
m.none { subtrees[position] = BinaryTreeSet.new(value, removed: false) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param value [Integer]
|
68
|
+
# @return [void]
|
69
|
+
def delete(value)
|
70
|
+
Fear.match(value) do |m|
|
71
|
+
m.case(elem) { self.removed = true }
|
72
|
+
m.case(->(x) { x > elem }) { |v| delete_from_leaf(Right, v) }
|
73
|
+
m.case(->(x) { x < elem }) { |v| delete_from_leaf(Left, v) }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# @param position [Position]
|
78
|
+
# @param value [Integer]
|
79
|
+
# @return [void]
|
80
|
+
private def delete_from_leaf(position, value)
|
81
|
+
leaf(position).match do |m|
|
82
|
+
m.some { |leaf| leaf.delete(value) }
|
83
|
+
m.none { subtrees[position] = BinaryTreeSet.new(value, removed: true) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# @param position [Position]
|
88
|
+
# @return [Fear::Option<BinaryTreeSet>]
|
89
|
+
private def leaf(position)
|
90
|
+
if subtrees.key?(position)
|
91
|
+
Fear.some(subtrees[position])
|
92
|
+
else
|
93
|
+
Fear.none
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'fear'
|
2
|
+
|
3
|
+
class ToWords
|
4
|
+
CONVERTER = Fear.matcher do |m|
|
5
|
+
{
|
6
|
+
0 => 'zero',
|
7
|
+
1 => 'one',
|
8
|
+
2 => 'two',
|
9
|
+
3 => 'three',
|
10
|
+
4 => 'four',
|
11
|
+
5 => 'five',
|
12
|
+
6 => 'six',
|
13
|
+
7 => 'seven',
|
14
|
+
8 => 'eight',
|
15
|
+
9 => 'nine',
|
16
|
+
10 => 'ten',
|
17
|
+
11 => 'eleven',
|
18
|
+
12 => 'twelve',
|
19
|
+
13 => 'thirteen',
|
20
|
+
14 => 'fourteen',
|
21
|
+
15 => 'fifteen',
|
22
|
+
16 => 'sixteen',
|
23
|
+
17 => 'seventeen',
|
24
|
+
18 => 'eighteen',
|
25
|
+
19 => 'nineteen',
|
26
|
+
20 => 'twenty',
|
27
|
+
30 => 'thirty',
|
28
|
+
40 => 'forty',
|
29
|
+
50 => 'fifty',
|
30
|
+
60 => 'sixty',
|
31
|
+
70 => 'seventy',
|
32
|
+
80 => 'eighty',
|
33
|
+
90 => 'ninety',
|
34
|
+
}.each_pair do |number, in_words|
|
35
|
+
m.case(number) { in_words }
|
36
|
+
end
|
37
|
+
m.case(->(n) { n < 0 }) { |n| "minus #{CONVERTER.call(-n)}" }
|
38
|
+
m.case(->(n) { n < 100 }) { |n| "#{CONVERTER.call((n / 10) * 10)}-#{CONVERTER.call(n % 10)}" }
|
39
|
+
m.case(->(n) { n < 200 }) { |n| "one hundred #{CONVERTER.call(n % 100)}" }
|
40
|
+
m.case(->(n) { n < 1_000 }) { |n| "#{CONVERTER.call(n / 100)} hundreds #{CONVERTER.call(n % 100)}" }
|
41
|
+
m.case(->(n) { n < 2_000 }) { |n| "one thousand #{CONVERTER.call(n % 1000)}" }
|
42
|
+
m.case(->(n) { n < 1_000_000 }) { |n| "#{CONVERTER.call(n / 1_000)} thousands #{CONVERTER.call(n % 1_000)}" }
|
43
|
+
m.else { |n| raise "#{n} too big " }
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.call(number)
|
47
|
+
Fear.case(Integer, &:itself).and_then(CONVERTER).call(number)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
ToWords.call(99) #=> 'ninety-nine'
|
52
|
+
ToWords.call(133) #=> 'one hundred thirty-three
|
53
|
+
ToWords.call(777) #=> 'seven hundreds seventy-seven'
|
54
|
+
ToWords.call(254_555) #=> 'two hundreds fifty-four thousands five hundreds fifty-five'
|
data/fear.gemspec
CHANGED
@@ -24,12 +24,14 @@ Gem::Specification.new do |spec|
|
|
24
24
|
Successfully installed fear-#{Fear::VERSION}
|
25
25
|
MSG
|
26
26
|
|
27
|
-
spec.add_runtime_dependency '
|
27
|
+
spec.add_runtime_dependency 'lru_redux'
|
28
|
+
spec.add_runtime_dependency 'treetop'
|
28
29
|
|
29
|
-
spec.add_development_dependency 'appraisal'
|
30
30
|
spec.add_development_dependency 'benchmark-ips'
|
31
31
|
spec.add_development_dependency 'bundler'
|
32
|
+
spec.add_development_dependency 'concurrent-ruby'
|
32
33
|
spec.add_development_dependency 'dry-matcher'
|
34
|
+
spec.add_development_dependency 'dry-monads'
|
33
35
|
spec.add_development_dependency 'qo'
|
34
36
|
spec.add_development_dependency 'rake', '~> 10.0'
|
35
37
|
spec.add_development_dependency 'rspec', '~> 3.1'
|
data/lib/fear.rb
CHANGED
@@ -1,19 +1,34 @@
|
|
1
|
-
require '
|
2
|
-
require 'fear/
|
1
|
+
require 'fear/either_api'
|
2
|
+
require 'fear/extractor_api'
|
3
|
+
require 'fear/for_api'
|
4
|
+
require 'fear/future_api'
|
5
|
+
require 'fear/option_api'
|
3
6
|
require 'fear/pattern_matching_api'
|
7
|
+
require 'fear/try_api'
|
8
|
+
require 'fear/version'
|
4
9
|
|
5
10
|
module Fear
|
6
11
|
Error = Class.new(StandardError)
|
7
|
-
|
12
|
+
IllegalStateException = Class.new(Error)
|
8
13
|
MatchError = Class.new(Error)
|
14
|
+
NoSuchElementError = Class.new(Error)
|
15
|
+
PatternSyntaxError = Class.new(Error)
|
16
|
+
|
17
|
+
extend EitherApi
|
18
|
+
extend ExtractorApi
|
19
|
+
extend ForApi
|
20
|
+
extend FutureApi
|
21
|
+
extend OptionApi
|
9
22
|
extend PatternMatchingApi
|
23
|
+
extend TryApi
|
10
24
|
|
11
25
|
autoload :EmptyPartialFunction, 'fear/empty_partial_function'
|
12
26
|
autoload :PartialFunction, 'fear/partial_function'
|
13
27
|
autoload :PartialFunctionClass, 'fear/partial_function_class'
|
14
28
|
autoload :PatternMatch, 'fear/pattern_match'
|
29
|
+
autoload :Extractor, 'fear/extractor'
|
15
30
|
|
16
|
-
autoload :
|
31
|
+
autoload :Unit, 'fear/unit'
|
17
32
|
autoload :For, 'fear/for'
|
18
33
|
autoload :RightBiased, 'fear/right_biased'
|
19
34
|
autoload :Utils, 'fear/utils'
|
@@ -40,6 +55,8 @@ module Fear
|
|
40
55
|
autoload :Right, 'fear/right'
|
41
56
|
autoload :RightPatternMatch, 'fear/right_pattern_match'
|
42
57
|
|
58
|
+
autoload :Future, 'fear/future'
|
59
|
+
|
43
60
|
module Mixin
|
44
61
|
include Either::Mixin
|
45
62
|
include For::Mixin
|
data/lib/fear/either.rb
CHANGED
@@ -14,9 +14,9 @@ module Fear
|
|
14
14
|
# @example
|
15
15
|
# in = Readline.readline('Type Either a string or an Int: ', true)
|
16
16
|
# result = begin
|
17
|
-
#
|
17
|
+
# Fear.right(Integer(in))
|
18
18
|
# rescue ArgumentError
|
19
|
-
#
|
19
|
+
# Fear.left(in)
|
20
20
|
# end
|
21
21
|
#
|
22
22
|
# result.match do |m|
|
@@ -40,21 +40,21 @@ module Fear
|
|
40
40
|
# @yieldreturn [any]
|
41
41
|
# @return [any]
|
42
42
|
# @example
|
43
|
-
#
|
44
|
-
#
|
43
|
+
# Fear.right(42).get_or_else { 24/2 } #=> 42
|
44
|
+
# Fear.left('undefined').get_or_else { 24/2 } #=> 12
|
45
45
|
# @overload get_or_else(default)
|
46
46
|
# @return [any]
|
47
47
|
# @example
|
48
|
-
#
|
49
|
-
#
|
48
|
+
# Fear.right(42).get_or_else(12) #=> 42
|
49
|
+
# Fear.left('undefined').get_or_else(12) #=> 12
|
50
50
|
#
|
51
51
|
# @!method or_else(&alternative)
|
52
52
|
# Returns this +Right+ or the given alternative if this is a +Left+.
|
53
53
|
# @return [Either]
|
54
54
|
# @example
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
55
|
+
# Fear.right(42).or_else { Fear.right(21) } #=> Fear.right(42)
|
56
|
+
# Fear.left('unknown').or_else { Fear.right(21) } #=> Fear.right(21)
|
57
|
+
# Fear.left('unknown').or_else { Fear.left('empty') } #=> Fear.left('empty')
|
58
58
|
#
|
59
59
|
# @!method include?(other_value)
|
60
60
|
# Returns +true+ if +Right+ has an element that is equal
|
@@ -62,9 +62,9 @@ module Fear
|
|
62
62
|
# @param [any]
|
63
63
|
# @return [Boolean]
|
64
64
|
# @example
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
65
|
+
# Fear.right(17).include?(17) #=> true
|
66
|
+
# Fear.right(17).include?(7) #=> false
|
67
|
+
# Fear.left('undefined').include?(17) #=> false
|
68
68
|
#
|
69
69
|
# @!method each(&block)
|
70
70
|
# Performs the given block if this is a +Right+.
|
@@ -72,11 +72,11 @@ module Fear
|
|
72
72
|
# @yieldreturn [void]
|
73
73
|
# @return [Option] itself
|
74
74
|
# @example
|
75
|
-
#
|
75
|
+
# Fear.right(17).each do |value|
|
76
76
|
# puts value
|
77
77
|
# end #=> prints 17
|
78
78
|
#
|
79
|
-
#
|
79
|
+
# Fear.left('undefined').each do |value|
|
80
80
|
# puts value
|
81
81
|
# end #=> does nothing
|
82
82
|
#
|
@@ -86,8 +86,8 @@ module Fear
|
|
86
86
|
# @yieldparam [any] value
|
87
87
|
# @yieldreturn [any]
|
88
88
|
# @example
|
89
|
-
#
|
90
|
-
#
|
89
|
+
# Fear.right(42).map { |v| v/2 } #=> Fear.right(21)
|
90
|
+
# Fear.left('undefined').map { |v| v/2 } #=> Fear.left('undefined')
|
91
91
|
#
|
92
92
|
# @!method flat_map(&block)
|
93
93
|
# Returns the given block applied to the value from this +Right+
|
@@ -96,16 +96,16 @@ module Fear
|
|
96
96
|
# @yieldreturn [Option]
|
97
97
|
# @return [Option]
|
98
98
|
# @example
|
99
|
-
#
|
100
|
-
#
|
99
|
+
# Fear.right(42).flat_map { |v| Fear.right(v/2) } #=> Fear.right(21)
|
100
|
+
# Fear.left('undefined').flat_map { |v| Fear.right(v/2) } #=> Fear.left('undefined')
|
101
101
|
#
|
102
102
|
# @!method to_option
|
103
103
|
# Returns an +Some+ containing the +Right+ value or a +None+ if
|
104
104
|
# this is a +Left+.
|
105
105
|
# @return [Option]
|
106
106
|
# @example
|
107
|
-
#
|
108
|
-
#
|
107
|
+
# Fear.right(42).to_option #=> Fear.some(21)
|
108
|
+
# Fear.left('undefined').to_option #=> Fear.none()
|
109
109
|
#
|
110
110
|
# @!method any?(&predicate)
|
111
111
|
# Returns +false+ if +Left+ or returns the result of the
|
@@ -114,9 +114,9 @@ module Fear
|
|
114
114
|
# @yieldreturn [Boolean]
|
115
115
|
# @return [Boolean]
|
116
116
|
# @example
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
117
|
+
# Fear.right(12).any?( |v| v > 10) #=> true
|
118
|
+
# Fear.right(7).any?( |v| v > 10) #=> false
|
119
|
+
# Fear.left('undefined').any?( |v| v > 10) #=> false
|
120
120
|
#
|
121
121
|
# -----
|
122
122
|
#
|
@@ -125,16 +125,16 @@ module Fear
|
|
125
125
|
# @note this method is also aliased as +#success?+
|
126
126
|
# @return [Boolean]
|
127
127
|
# @example
|
128
|
-
#
|
129
|
-
#
|
128
|
+
# Fear.right(42).right? #=> true
|
129
|
+
# Fear.left('err').right? #=> false
|
130
130
|
#
|
131
131
|
# @!method left?
|
132
132
|
# Returns +true+ if this is a +Left+, +false+ otherwise.
|
133
133
|
# @note this method is also aliased as +#failure?+
|
134
134
|
# @return [Boolean]
|
135
135
|
# @example
|
136
|
-
#
|
137
|
-
#
|
136
|
+
# Fear.right(42).left? #=> false
|
137
|
+
# Fear.left('err').left? #=> true
|
138
138
|
#
|
139
139
|
# @!method select_or_else(default, &predicate)
|
140
140
|
# Returns +Left+ of the default if the given predicate
|
@@ -144,10 +144,10 @@ module Fear
|
|
144
144
|
# @yieldreturn [Boolean]
|
145
145
|
# @return [Either]
|
146
146
|
# @example
|
147
|
-
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
#
|
147
|
+
# Fear.right(12).select_or_else(-1, &:even?) #=> Fear.right(12)
|
148
|
+
# Fear.right(7).select_or_else(-1, &:even?) #=> Fear.left(-1)
|
149
|
+
# Fear.left(12).select_or_else(-1, &:even?) #=> Fear.left(12)
|
150
|
+
# Fear.left(12).select_or_else(-> { -1 }, &:even?) #=> Fear.left(12)
|
151
151
|
#
|
152
152
|
# @!method select(&predicate)
|
153
153
|
# Returns +Left+ of value if the given predicate
|
@@ -156,10 +156,10 @@ module Fear
|
|
156
156
|
# @yieldreturn [Boolean]
|
157
157
|
# @return [Either]
|
158
158
|
# @example
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
159
|
+
# Fear.right(12).select(&:even?) #=> Fear.right(12)
|
160
|
+
# Fear.right(7).select(&:even?) #=> Fear.left(7)
|
161
|
+
# Fear.left(12).select(&:even?) #=> Fear.left(12)
|
162
|
+
# Fear.left(7).select(&:even?) #=> Fear.left(7)
|
163
163
|
#
|
164
164
|
# @!method reject(&predicate)
|
165
165
|
# Returns +Left+ of value if the given predicate holds for the
|
@@ -168,17 +168,17 @@ module Fear
|
|
168
168
|
# @yieldreturn [Boolean]
|
169
169
|
# @return [Either]
|
170
170
|
# @example
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
#
|
171
|
+
# Fear.right(12).reject(&:even?) #=> Fear.left(12)
|
172
|
+
# Fear.right(7).reject(&:even?) #=> Fear.right(7)
|
173
|
+
# Fear.left(12).reject(&:even?) #=> Fear.left(12)
|
174
|
+
# Fear.left(7).reject(&:even?) #=> Fear.left(7)
|
175
175
|
#
|
176
176
|
# @!method swap
|
177
177
|
# If this is a +Left+, then return the left value in +Right+ or vice versa.
|
178
178
|
# @return [Either]
|
179
179
|
# @example
|
180
|
-
#
|
181
|
-
#
|
180
|
+
# Fear.left('left').swap #=> Fear.right('left')
|
181
|
+
# Fear.right('right').swap #=> Fear.left('left')
|
182
182
|
#
|
183
183
|
# @!method reduce(reduce_left, reduce_right)
|
184
184
|
# Applies +reduce_left+ if this is a +Left+ or +reduce_right+ if
|
@@ -204,10 +204,10 @@ module Fear
|
|
204
204
|
# @return [Either]
|
205
205
|
# @raise [TypeError] if it does not contain +Either+.
|
206
206
|
# @example
|
207
|
-
#
|
208
|
-
#
|
209
|
-
#
|
210
|
-
#
|
207
|
+
# Fear.right(Fear.right(12)).join_right #=> Fear.right(12)
|
208
|
+
# Fear.right(Fear.left("flower")).join_right #=> Fear.left("flower")
|
209
|
+
# Fear.left("flower").join_right #=> Fear.left("flower")
|
210
|
+
# Fear.left(Fear.right("flower")).join_right #=> Fear.left(Fear.right("flower"))
|
211
211
|
#
|
212
212
|
# @!method join_right
|
213
213
|
# Joins an +Either+ through +Left+. This method requires
|
@@ -217,16 +217,16 @@ module Fear
|
|
217
217
|
# @return [Either]
|
218
218
|
# @raise [TypeError] if it does not contain +Either+.
|
219
219
|
# @example
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
223
|
-
#
|
220
|
+
# Fear.left(Fear.right("flower")).join_left #=> Fear.right("flower")
|
221
|
+
# Fear.left(Fear.left(12)).join_left #=> Fear.left(12)
|
222
|
+
# Fear.right("daisy").join_left #=> Fear.right("daisy")
|
223
|
+
# Fear.right(Fear.left("daisy")).join_left #=> Fear.right(Fear.left("daisy"))
|
224
224
|
#
|
225
225
|
# @!method match(&matcher)
|
226
226
|
# Pattern match against this +Either+
|
227
227
|
# @yield matcher [Fear::EitherPatternMatch]
|
228
228
|
# @example
|
229
|
-
#
|
229
|
+
# either.match do |m|
|
230
230
|
# m.right(Integer) do |x|
|
231
231
|
# x * 2
|
232
232
|
# end
|
@@ -242,8 +242,6 @@ module Fear
|
|
242
242
|
# @see https://github.com/scala/scala/blob/2.12.x/src/library/scala/util/Either.scala
|
243
243
|
#
|
244
244
|
module Either
|
245
|
-
include Dry::Equalizer(:value)
|
246
|
-
|
247
245
|
# @private
|
248
246
|
def left_class
|
249
247
|
Left
|
@@ -261,6 +259,20 @@ module Fear
|
|
261
259
|
attr_reader :value
|
262
260
|
protected :value
|
263
261
|
|
262
|
+
# @param other [Any]
|
263
|
+
# @return [Boolean]
|
264
|
+
def ==(other)
|
265
|
+
other.is_a?(self.class) && value == other.value
|
266
|
+
end
|
267
|
+
|
268
|
+
# @return [String]
|
269
|
+
def inspect
|
270
|
+
"#<#{self.class} value=#{value.inspect}>"
|
271
|
+
end
|
272
|
+
|
273
|
+
# @return [String]
|
274
|
+
alias to_s inspect
|
275
|
+
|
264
276
|
class << self
|
265
277
|
# Build pattern matcher to be used later, despite off
|
266
278
|
# +Either#match+ method, id doesn't apply matcher immanently,
|
@@ -275,7 +287,7 @@ module Fear
|
|
275
287
|
# m.left(String) { :err }
|
276
288
|
# m.else { 'error '}
|
277
289
|
# end
|
278
|
-
# matcher.call(
|
290
|
+
# matcher.call(Fear.right(42))
|
279
291
|
#
|
280
292
|
# @yieldparam [Fear::EitherPatternMatch]
|
281
293
|
# @return [Fear::PartialFunction]
|
@@ -292,16 +304,22 @@ module Fear
|
|
292
304
|
# Left('beaf') #=> #<Fear::Legt value='beaf'>
|
293
305
|
#
|
294
306
|
module Mixin
|
295
|
-
# @param [any]
|
296
|
-
# @return [Left]
|
307
|
+
# @param value [any]
|
308
|
+
# @return [Fear::Left]
|
309
|
+
# @example
|
310
|
+
# Left(42) #=> #<Fear::Left value=42>
|
311
|
+
#
|
297
312
|
def Left(value)
|
298
|
-
|
313
|
+
Fear.left(value)
|
299
314
|
end
|
300
315
|
|
301
|
-
# @param [any]
|
302
|
-
# @return [Right]
|
316
|
+
# @param value [any]
|
317
|
+
# @return [Fear::Right]
|
318
|
+
# @example
|
319
|
+
# Right(42) #=> #<Fear::Right value=42>
|
320
|
+
#
|
303
321
|
def Right(value)
|
304
|
-
|
322
|
+
Fear.right(value)
|
305
323
|
end
|
306
324
|
end
|
307
325
|
end
|