fear 0.9.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 +5 -5
- data/.github/workflows/rubocop.yml +39 -0
- data/.github/workflows/spec.yml +42 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +4 -12
- data/.simplecov +17 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +1 -1
- data/README.md +1293 -97
- data/Rakefile +369 -1
- 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 +17 -0
- data/examples/pattern_extracting_ruby2.7.rb +15 -0
- data/examples/pattern_matching_binary_tree_set.rb +101 -0
- data/examples/pattern_matching_number_in_words.rb +60 -0
- data/fear.gemspec +34 -23
- data/lib/dry/types/fear.rb +8 -0
- data/lib/dry/types/fear/option.rb +125 -0
- data/lib/fear.rb +65 -15
- data/lib/fear/await.rb +33 -0
- data/lib/fear/awaitable.rb +28 -0
- data/lib/fear/either.rb +131 -71
- data/lib/fear/either_api.rb +23 -0
- data/lib/fear/either_pattern_match.rb +53 -0
- data/lib/fear/empty_partial_function.rb +38 -0
- data/lib/fear/extractor.rb +112 -0
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +10 -0
- data/lib/fear/extractor/any_matcher.rb +17 -0
- data/lib/fear/extractor/array_head_matcher.rb +36 -0
- data/lib/fear/extractor/array_matcher.rb +40 -0
- data/lib/fear/extractor/array_splat_matcher.rb +16 -0
- data/lib/fear/extractor/empty_list_matcher.rb +20 -0
- data/lib/fear/extractor/extractor_matcher.rb +44 -0
- data/lib/fear/extractor/grammar.rb +203 -0
- data/lib/fear/extractor/grammar.treetop +129 -0
- data/lib/fear/extractor/identifier_matcher.rb +18 -0
- data/lib/fear/extractor/matcher.rb +53 -0
- data/lib/fear/extractor/matcher/and.rb +38 -0
- data/lib/fear/extractor/named_array_splat_matcher.rb +17 -0
- data/lib/fear/extractor/pattern.rb +58 -0
- data/lib/fear/extractor/typed_identifier_matcher.rb +26 -0
- data/lib/fear/extractor/value_matcher.rb +19 -0
- data/lib/fear/extractor_api.rb +35 -0
- data/lib/fear/failure.rb +46 -14
- data/lib/fear/failure_pattern_match.rb +10 -0
- data/lib/fear/for.rb +37 -95
- data/lib/fear/for_api.rb +68 -0
- data/lib/fear/future.rb +497 -0
- data/lib/fear/future_api.rb +21 -0
- data/lib/fear/left.rb +19 -2
- data/lib/fear/left_pattern_match.rb +11 -0
- data/lib/fear/none.rb +67 -3
- data/lib/fear/none_pattern_match.rb +14 -0
- data/lib/fear/option.rb +120 -56
- data/lib/fear/option_api.rb +40 -0
- data/lib/fear/option_pattern_match.rb +48 -0
- data/lib/fear/partial_function.rb +176 -0
- data/lib/fear/partial_function/and_then.rb +50 -0
- data/lib/fear/partial_function/any.rb +28 -0
- data/lib/fear/partial_function/combined.rb +53 -0
- data/lib/fear/partial_function/empty.rb +10 -0
- data/lib/fear/partial_function/guard.rb +80 -0
- data/lib/fear/partial_function/guard/and.rb +38 -0
- data/lib/fear/partial_function/guard/and3.rb +41 -0
- data/lib/fear/partial_function/guard/or.rb +38 -0
- data/lib/fear/partial_function/lifted.rb +23 -0
- data/lib/fear/partial_function/or_else.rb +64 -0
- data/lib/fear/partial_function_class.rb +38 -0
- data/lib/fear/pattern_match.rb +114 -0
- data/lib/fear/pattern_matching_api.rb +137 -0
- data/lib/fear/promise.rb +95 -0
- data/lib/fear/right.rb +20 -2
- data/lib/fear/right_biased.rb +6 -14
- data/lib/fear/right_pattern_match.rb +11 -0
- data/lib/fear/some.rb +55 -3
- data/lib/fear/some_pattern_match.rb +13 -0
- data/lib/fear/struct.rb +248 -0
- data/lib/fear/success.rb +35 -5
- data/lib/fear/success_pattern_match.rb +12 -0
- data/lib/fear/try.rb +136 -79
- data/lib/fear/try_api.rb +33 -0
- data/lib/fear/try_pattern_match.rb +33 -0
- data/lib/fear/unit.rb +32 -0
- data/lib/fear/utils.rb +39 -14
- data/lib/fear/version.rb +4 -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/done_spec.rb +8 -6
- data/spec/fear/either/mixin_spec.rb +17 -0
- data/spec/fear/either_pattern_match_spec.rb +37 -0
- data/spec/fear/either_pattern_matching_spec.rb +28 -0
- data/spec/fear/extractor/array_matcher_spec.rb +230 -0
- data/spec/fear/extractor/extractor_matcher_spec.rb +153 -0
- data/spec/fear/extractor/grammar_array_spec.rb +25 -0
- data/spec/fear/extractor/identified_matcher_spec.rb +49 -0
- data/spec/fear/extractor/identifier_matcher_spec.rb +68 -0
- data/spec/fear/extractor/pattern_spec.rb +34 -0
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +64 -0
- data/spec/fear/extractor/value_matcher_number_spec.rb +79 -0
- data/spec/fear/extractor/value_matcher_string_spec.rb +88 -0
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +71 -0
- data/spec/fear/extractor_api_spec.rb +115 -0
- data/spec/fear/extractor_spec.rb +61 -0
- data/spec/fear/failure_spec.rb +145 -45
- data/spec/fear/for_spec.rb +57 -67
- data/spec/fear/future_spec.rb +691 -0
- data/spec/fear/guard_spec.rb +103 -0
- data/spec/fear/left_spec.rb +112 -46
- data/spec/fear/none_spec.rb +114 -16
- data/spec/fear/option/mixin_spec.rb +39 -0
- data/spec/fear/option_pattern_match_spec.rb +35 -0
- data/spec/fear/option_pattern_matching_spec.rb +34 -0
- data/spec/fear/option_spec.rb +121 -8
- data/spec/fear/partial_function/empty_spec.rb +38 -0
- data/spec/fear/partial_function_and_then_spec.rb +147 -0
- data/spec/fear/partial_function_composition_spec.rb +82 -0
- data/spec/fear/partial_function_or_else_spec.rb +276 -0
- data/spec/fear/partial_function_spec.rb +239 -0
- data/spec/fear/pattern_match_spec.rb +93 -0
- data/spec/fear/pattern_matching_api_spec.rb +31 -0
- data/spec/fear/promise_spec.rb +96 -0
- data/spec/fear/right_biased/left.rb +29 -32
- data/spec/fear/right_biased/right.rb +51 -54
- data/spec/fear/right_spec.rb +109 -41
- data/spec/fear/some_spec.rb +80 -15
- data/spec/fear/success_spec.rb +99 -32
- data/spec/fear/try/mixin_spec.rb +19 -0
- data/spec/fear/try_pattern_match_spec.rb +37 -0
- data/spec/fear/try_pattern_matching_spec.rb +34 -0
- data/spec/fear/utils_spec.rb +16 -14
- data/spec/spec_helper.rb +13 -7
- data/spec/struct_pattern_matching_spec.rb +36 -0
- data/spec/struct_spec.rb +226 -0
- data/spec/support/dry_types.rb +6 -0
- metadata +320 -29
- data/.travis.yml +0 -9
- data/lib/fear/done.rb +0 -22
- data/lib/fear/for/evaluation_context.rb +0 -91
@@ -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,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear"
|
4
|
+
|
5
|
+
User = Struct.new(:id, :name, :admin)
|
6
|
+
|
7
|
+
matcher = Fear.matcher do |m|
|
8
|
+
m.xcase("User(_, name, true)") do |name:|
|
9
|
+
puts "Hi #{name}, you are welcome"
|
10
|
+
end
|
11
|
+
m.xcase("User(_, _, false)") do
|
12
|
+
puts "Only admins are allowed here"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
matcher.(User.new(1, "Jane", true))
|
17
|
+
matcher.(User.new(1, "John", false))
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear"
|
4
|
+
|
5
|
+
matcher = proc do |value|
|
6
|
+
case value
|
7
|
+
in User(admin: true, name:)
|
8
|
+
puts "Hi #{name}, you are welcome"
|
9
|
+
in User(admin: false)
|
10
|
+
puts "Only admins are allowed here"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
matcher.(User.new(1, "Jane", true))
|
15
|
+
matcher.(User.new(1, "John", false))
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear"
|
4
|
+
|
5
|
+
# @example Usage
|
6
|
+
# set = BinaryTreeSet.new
|
7
|
+
# set.add(4)
|
8
|
+
# set.includes?(4) #=> true
|
9
|
+
# set.includes?(5) #=> false
|
10
|
+
# set.delete(4)
|
11
|
+
# set.includes?(4) #=> false
|
12
|
+
#
|
13
|
+
class BinaryTreeSet
|
14
|
+
Position = Module.new
|
15
|
+
private_constant(:Position)
|
16
|
+
Right = Module.new.include(Position)
|
17
|
+
private_constant(:Right)
|
18
|
+
Left = Module.new.include(Position)
|
19
|
+
private_constant(:Left)
|
20
|
+
|
21
|
+
def initialize(elem = 0, removed: true)
|
22
|
+
@elem = elem
|
23
|
+
@removed = removed
|
24
|
+
@subtrees = {}
|
25
|
+
end
|
26
|
+
attr_reader :elem, :subtrees
|
27
|
+
attr_accessor :removed
|
28
|
+
private :elem
|
29
|
+
private :removed
|
30
|
+
private :subtrees
|
31
|
+
|
32
|
+
# @param value [Integer]
|
33
|
+
# @return [Boolean]
|
34
|
+
def includes?(value)
|
35
|
+
Fear.match(value) do |m|
|
36
|
+
m.case(elem) { !removed }
|
37
|
+
m.case(->(x) { x > elem }) { |v| includes_in_leaf?(Right, v) }
|
38
|
+
m.case(->(x) { x < elem }) { |v| includes_in_leaf?(Left, v) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param position [Position]
|
43
|
+
# @param value [Integer]
|
44
|
+
# @return [Boolean]
|
45
|
+
private def includes_in_leaf?(position, value)
|
46
|
+
leaf(position).match do |m|
|
47
|
+
m.some { |leaf| leaf.includes?(value) }
|
48
|
+
m.none { false }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param value [Integer]
|
53
|
+
# @return [void]
|
54
|
+
def add(value)
|
55
|
+
Fear.match(value) do |m|
|
56
|
+
m.case(elem) { self.removed = false }
|
57
|
+
m.case(->(x) { x > elem }) { |v| add_to_leaf(Right, v) }
|
58
|
+
m.case(->(x) { x < elem }) { |v| add_to_leaf(Left, v) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param position [Position]
|
63
|
+
# @param value [Integer]
|
64
|
+
# @return [void]
|
65
|
+
private def add_to_leaf(position, value)
|
66
|
+
leaf(position).match do |m|
|
67
|
+
m.some { |leaf| leaf.add(value) }
|
68
|
+
m.none { subtrees[position] = BinaryTreeSet.new(value, removed: false) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# @param value [Integer]
|
73
|
+
# @return [void]
|
74
|
+
def delete(value)
|
75
|
+
Fear.match(value) do |m|
|
76
|
+
m.case(elem) { self.removed = true }
|
77
|
+
m.case(->(x) { x > elem }) { |v| delete_from_leaf(Right, v) }
|
78
|
+
m.case(->(x) { x < elem }) { |v| delete_from_leaf(Left, v) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param position [Position]
|
83
|
+
# @param value [Integer]
|
84
|
+
# @return [void]
|
85
|
+
private def delete_from_leaf(position, value)
|
86
|
+
leaf(position).match do |m|
|
87
|
+
m.some { |leaf| leaf.delete(value) }
|
88
|
+
m.none { subtrees[position] = BinaryTreeSet.new(value, removed: true) }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# @param position [Position]
|
93
|
+
# @return [Fear::Option<BinaryTreeSet>]
|
94
|
+
private def leaf(position)
|
95
|
+
if subtrees.has_key?(position)
|
96
|
+
Fear.some(subtrees[position])
|
97
|
+
else
|
98
|
+
Fear.none
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear"
|
4
|
+
|
5
|
+
class ToWords
|
6
|
+
NUMBERS = {
|
7
|
+
0 => "zero",
|
8
|
+
1 => "one",
|
9
|
+
2 => "two",
|
10
|
+
3 => "three",
|
11
|
+
4 => "four",
|
12
|
+
5 => "five",
|
13
|
+
6 => "six",
|
14
|
+
7 => "seven",
|
15
|
+
8 => "eight",
|
16
|
+
9 => "nine",
|
17
|
+
10 => "ten",
|
18
|
+
11 => "eleven",
|
19
|
+
12 => "twelve",
|
20
|
+
13 => "thirteen",
|
21
|
+
14 => "fourteen",
|
22
|
+
15 => "fifteen",
|
23
|
+
16 => "sixteen",
|
24
|
+
17 => "seventeen",
|
25
|
+
18 => "eighteen",
|
26
|
+
19 => "nineteen",
|
27
|
+
20 => "twenty",
|
28
|
+
30 => "thirty",
|
29
|
+
40 => "forty",
|
30
|
+
50 => "fifty",
|
31
|
+
60 => "sixty",
|
32
|
+
70 => "seventy",
|
33
|
+
80 => "eighty",
|
34
|
+
90 => "ninety",
|
35
|
+
}.freeze
|
36
|
+
private_constant :NUMBERS
|
37
|
+
|
38
|
+
CONVERTER = Fear.matcher do |m|
|
39
|
+
NUMBERS.each_pair do |number, in_words|
|
40
|
+
m.case(number) { in_words }
|
41
|
+
end
|
42
|
+
m.case(->(n) { n < 0 }) { |n| "minus #{CONVERTER.(-n)}" }
|
43
|
+
m.case(->(n) { n < 100 }) { |n| "#{CONVERTER.((n / 10) * 10)}-#{CONVERTER.(n % 10)}" }
|
44
|
+
m.case(->(n) { n < 200 }) { |n| "one hundred #{CONVERTER.(n % 100)}" }
|
45
|
+
m.case(->(n) { n < 1_000 }) { |n| "#{CONVERTER.(n / 100)} hundreds #{CONVERTER.(n % 100)}" }
|
46
|
+
m.case(->(n) { n < 2_000 }) { |n| "one thousand #{CONVERTER.(n % 1000)}" }
|
47
|
+
m.case(->(n) { n < 1_000_000 }) { |n| "#{CONVERTER.(n / 1_000)} thousands #{CONVERTER.(n % 1_000)}" }
|
48
|
+
m.else { |n| raise "#{n} too big " }
|
49
|
+
end
|
50
|
+
private_constant :CONVERTER
|
51
|
+
|
52
|
+
def self.call(number)
|
53
|
+
Fear.case(Integer, &:itself).and_then(CONVERTER).(number)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
ToWords.(99) #=> 'ninety-nine'
|
58
|
+
ToWords.(133) #=> 'one hundred thirty-three
|
59
|
+
ToWords.(777) #=> 'seven hundreds seventy-seven'
|
60
|
+
ToWords.(254_555) #=> 'two hundreds fifty-four thousands five hundreds fifty-five'
|
data/fear.gemspec
CHANGED
@@ -1,31 +1,42 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
3
4
|
|
4
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
6
|
|
6
|
-
require
|
7
|
+
require "fear/version"
|
7
8
|
Gem::Specification.new do |spec|
|
8
|
-
spec.name
|
9
|
-
spec.version
|
10
|
-
spec.authors
|
11
|
-
spec.email
|
12
|
-
spec.summary
|
13
|
-
spec.description
|
14
|
-
spec.homepage
|
15
|
-
spec.license
|
9
|
+
spec.name = "fear"
|
10
|
+
spec.version = Fear::VERSION
|
11
|
+
spec.authors = ["Tema Bolshakov"]
|
12
|
+
spec.email = ["abolshakov@spbtv.com"]
|
13
|
+
spec.summary = "%q{Ruby port of some Scala's monads.}"
|
14
|
+
spec.description = "Ruby port of some Scala's monads."
|
15
|
+
spec.homepage = "https://github.com/bolshakov/fear"
|
16
|
+
spec.license = "MIT"
|
16
17
|
|
17
|
-
spec.files
|
18
|
-
spec.executables
|
19
|
-
spec.test_files
|
20
|
-
spec.require_paths = [
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin\/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^spec\/})
|
21
|
+
spec.require_paths = ["lib"]
|
21
22
|
|
22
|
-
spec.add_runtime_dependency
|
23
|
+
spec.add_runtime_dependency "lru_redux"
|
24
|
+
spec.add_runtime_dependency "treetop"
|
23
25
|
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
29
|
-
spec.add_development_dependency
|
30
|
-
spec.add_development_dependency
|
26
|
+
spec.add_development_dependency "benchmark-ips"
|
27
|
+
spec.add_development_dependency "bundler"
|
28
|
+
spec.add_development_dependency "concurrent-ruby"
|
29
|
+
spec.add_development_dependency "dry-matcher"
|
30
|
+
spec.add_development_dependency "dry-monads"
|
31
|
+
spec.add_development_dependency "qo"
|
32
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
34
|
+
spec.add_development_dependency "rubocop-rspec", "1.34.0"
|
35
|
+
spec.add_development_dependency "rubocop", "1.0.0"
|
36
|
+
spec.add_development_dependency "ruby_coding_standard"
|
37
|
+
spec.add_development_dependency "yard"
|
38
|
+
spec.add_development_dependency "dry-types"
|
39
|
+
spec.add_development_dependency "fear-rspec"
|
40
|
+
spec.add_development_dependency "simplecov"
|
41
|
+
spec.add_development_dependency "simplecov-lcov"
|
31
42
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module Types
|
5
|
+
class Option
|
6
|
+
include Type
|
7
|
+
include ::Dry::Equalizer(:type, :options, inspect: false, immutable: true)
|
8
|
+
include Decorator
|
9
|
+
include Builder
|
10
|
+
include Printable
|
11
|
+
|
12
|
+
# @param [Fear::Option, Object] input
|
13
|
+
#
|
14
|
+
# @return [Fear::Option]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def call_unsafe(input = Undefined)
|
18
|
+
case input
|
19
|
+
when ::Fear::Option
|
20
|
+
input
|
21
|
+
when Undefined
|
22
|
+
Fear.none
|
23
|
+
else
|
24
|
+
Fear.option(type.call_unsafe(input))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [Fear::Option, Object] input
|
29
|
+
#
|
30
|
+
# @return [Fear::Option]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def call_safe(input = Undefined)
|
34
|
+
case input
|
35
|
+
when ::Fear::Option
|
36
|
+
input
|
37
|
+
when Undefined
|
38
|
+
Fear.none
|
39
|
+
else
|
40
|
+
Fear.option(type.call_safe(input) { |output = input| return yield(output) })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [Object] input
|
45
|
+
#
|
46
|
+
# @return [Result::Success]
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def try(input = Undefined)
|
50
|
+
result = type.try(input)
|
51
|
+
|
52
|
+
if result.success?
|
53
|
+
Result::Success.new(Fear.option(result.input))
|
54
|
+
else
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [true]
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
def default?
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [Object] value
|
67
|
+
#
|
68
|
+
# @see Dry::Types::Builder#default
|
69
|
+
#
|
70
|
+
# @raise [ArgumentError] if nil provided as default value
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def default(value)
|
74
|
+
if value.nil?
|
75
|
+
raise ArgumentError, "nil cannot be used as a default of a maybe type"
|
76
|
+
else
|
77
|
+
super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module Builder
|
83
|
+
# Turn a type into a maybe type
|
84
|
+
#
|
85
|
+
# @return [Option]
|
86
|
+
#
|
87
|
+
# @api public
|
88
|
+
def option
|
89
|
+
Option.new(Types["nil"] | self)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @api private
|
94
|
+
class Schema
|
95
|
+
class Key
|
96
|
+
# @api private
|
97
|
+
def option
|
98
|
+
__new__(type.option)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# @api private
|
104
|
+
class Printer
|
105
|
+
MAPPING[Option] = :visit_option
|
106
|
+
|
107
|
+
# @api private
|
108
|
+
def visit_option(maybe)
|
109
|
+
visit(maybe.type) do |type|
|
110
|
+
yield "Fear::Option<#{type}>"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Register non-coercible maybe types
|
116
|
+
NON_NIL.each_key do |name|
|
117
|
+
register("option.strict.#{name}", self[name.to_s].option)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Register coercible maybe types
|
121
|
+
COERCIBLE.each_key do |name|
|
122
|
+
register("option.coercible.#{name}", self["coercible.#{name}"].option)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|