qo 0.5.0 → 0.99.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/.travis.yml +3 -3
- data/README.md +106 -9
- data/Rakefile +3 -3
- data/lib/qo.rb +17 -15
- data/lib/qo/branches/branch.rb +191 -0
- data/lib/qo/branches/branches.rb +37 -0
- data/lib/qo/branches/else_branch.rb +20 -0
- data/lib/qo/branches/error_branch.rb +26 -0
- data/lib/qo/branches/failure_branch.rb +26 -0
- data/lib/qo/branches/monadic_else_branch.rb +26 -0
- data/lib/qo/branches/monadic_when_branch.rb +26 -0
- data/lib/qo/branches/success_branch.rb +26 -0
- data/lib/qo/branches/when_branch.rb +21 -0
- data/lib/qo/destructurers/destructurer.rb +85 -0
- data/lib/qo/destructurers/destructurers.rb +15 -0
- data/lib/qo/exceptions.rb +3 -32
- data/lib/qo/matchers/matcher.rb +298 -0
- data/lib/qo/pattern_matchers/branching.rb +52 -0
- data/lib/qo/pattern_matchers/pattern_match.rb +170 -0
- data/lib/qo/pattern_matchers/pattern_matchers.rb +13 -0
- data/lib/qo/pattern_matchers/result_pattern_match.rb +45 -0
- data/lib/qo/public_api.rb +130 -8
- data/lib/qo/version.rb +1 -1
- data/qo.gemspec +11 -0
- metadata +28 -11
- data/lib/qo/helpers.rb +0 -44
- data/lib/qo/matchers/array_matcher.rb +0 -99
- data/lib/qo/matchers/base_matcher.rb +0 -110
- data/lib/qo/matchers/guard_block_matcher.rb +0 -91
- data/lib/qo/matchers/hash_matcher.rb +0 -144
- data/lib/qo/matchers/pattern_match.rb +0 -126
@@ -1,126 +0,0 @@
|
|
1
|
-
require 'qo/exceptions'
|
2
|
-
|
3
|
-
module Qo
|
4
|
-
module Matchers
|
5
|
-
# Creates a PatternMatch in a succinct block format:
|
6
|
-
#
|
7
|
-
# ```ruby
|
8
|
-
# Qo.match(target) { |m|
|
9
|
-
# m.when(/^F/, 42) { |(name, age)| "#{name} is #{age}" }
|
10
|
-
# m.else { "We need a default, right?" }
|
11
|
-
# }
|
12
|
-
# ```
|
13
|
-
#
|
14
|
-
# The Public API obscures the fact that the matcher is only called when it
|
15
|
-
# is explicitly given an argument to match against. If it is not, it will
|
16
|
-
# just return a class waiting for a target, as such:
|
17
|
-
#
|
18
|
-
# ```ruby
|
19
|
-
# def get_url(url)
|
20
|
-
# Net::HTTP.get_response(URI(url)).yield_self(&Qo.match { |m|
|
21
|
-
# m.when(Net::HTTPSuccess) { |response| response.body.size }
|
22
|
-
# m.else { |response| raise response.message }
|
23
|
-
# })
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# get_url('https://github.com/baweaver/qo')
|
27
|
-
# # => 142387
|
28
|
-
# get_url('https://github.com/baweaver/qo/does_not_exist')
|
29
|
-
# # => RuntimeError: Not Found
|
30
|
-
# ```
|
31
|
-
#
|
32
|
-
# This is intended for flexibility between singular calls and calls as a
|
33
|
-
# paramater to higher order functions like `map` and `yield_self`.
|
34
|
-
#
|
35
|
-
# This variant was inspired by ideas from Scala, Haskell, and various Ruby
|
36
|
-
# libraries dealing with Async and self-yielding blocks. Especially notable
|
37
|
-
# were websocket handlers and dry-ruby implementations.
|
38
|
-
#
|
39
|
-
# @author baweaver
|
40
|
-
# @since 0.3.0
|
41
|
-
#
|
42
|
-
class PatternMatch
|
43
|
-
def initialize
|
44
|
-
@matchers = []
|
45
|
-
|
46
|
-
yield(self)
|
47
|
-
end
|
48
|
-
|
49
|
-
# Creates a match case. This is the exact same as any other `and` style
|
50
|
-
# match reflected in the public API, except that it's a Guard Block
|
51
|
-
# match being performed. That means if the left side matches, the right
|
52
|
-
# side function is invoked and that value is returned.
|
53
|
-
#
|
54
|
-
# @param *array_matchers [Array[Any]]
|
55
|
-
# Array style matchers
|
56
|
-
#
|
57
|
-
# @param **keyword_matchers [Hash[Any, Any]]
|
58
|
-
# Hash style matchers
|
59
|
-
#
|
60
|
-
# @param &fn [Proc]
|
61
|
-
# If matched, this function will be called. If no function is provided
|
62
|
-
# Qo will default to identity
|
63
|
-
#
|
64
|
-
# @return [Array[GuardBlockMatcher]]
|
65
|
-
# The return of this method should not be directly depended on, but will
|
66
|
-
# provide all matchers currently present. This will likely be left for
|
67
|
-
# ease of debugging later.
|
68
|
-
def when(*array_matchers, **keyword_matchers, &fn)
|
69
|
-
@matchers << Qo::Matchers::GuardBlockMatcher.new(
|
70
|
-
array_matchers,
|
71
|
-
keyword_matchers,
|
72
|
-
&(fn || Qo::IDENTITY)
|
73
|
-
)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Else is the last statement that will be evaluated if all other parts
|
77
|
-
# fail. It should be noted that it won't magically appear, you have to
|
78
|
-
# explicitly put an `else` case in for it to catch on no match unless
|
79
|
-
# you want a `nil` return
|
80
|
-
#
|
81
|
-
# @param &fn [Proc]
|
82
|
-
# Function to call when all other matches have failed. If no value is
|
83
|
-
# provided, it assumes `Qo::IDENTITY` which will return the value given.
|
84
|
-
#
|
85
|
-
# @return [Proc]
|
86
|
-
def else(&fn)
|
87
|
-
raise Qo::Exceptions::MultipleElseClauses if @else
|
88
|
-
|
89
|
-
@else = fn || Qo::IDENTITY
|
90
|
-
end
|
91
|
-
|
92
|
-
# Proc version of a PatternMatch
|
93
|
-
#
|
94
|
-
# @return [Proc]
|
95
|
-
# Any -> Any | nil
|
96
|
-
def to_proc
|
97
|
-
Proc.new { |target| self.call(target) }
|
98
|
-
end
|
99
|
-
|
100
|
-
# Immediately invokes a PatternMatch
|
101
|
-
#
|
102
|
-
# @param target [Any]
|
103
|
-
# Target to run against and pipe to the associated block if it
|
104
|
-
# "matches" any of the GuardBlocks
|
105
|
-
#
|
106
|
-
# @return [Any]
|
107
|
-
# Result of the piped block
|
108
|
-
#
|
109
|
-
# @return [nil]
|
110
|
-
# No matches were found, so nothing is returned
|
111
|
-
def call(target)
|
112
|
-
@matchers.each { |guard_block_matcher|
|
113
|
-
next unless guard_block_matcher.match?(target)
|
114
|
-
return guard_block_matcher.match(target)
|
115
|
-
}
|
116
|
-
|
117
|
-
return @else.call(target) if @else
|
118
|
-
|
119
|
-
nil
|
120
|
-
end
|
121
|
-
|
122
|
-
alias_method :===, :call
|
123
|
-
alias_method :[], :call
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|