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.
@@ -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