eqq 0.0.2 → 0.0.7
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 +4 -4
- data/README.md +123 -5
- data/lib/eqq.rb +37 -10
- data/lib/eqq/buildable.rb +177 -48
- data/lib/eqq/version.rb +2 -1
- data/sig/eqq.rbs +92 -20
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: becfb749a93e73ea402265899e57d3deea45bf0eb457a29a66eafa03965b1572
|
4
|
+
data.tar.gz: 3f6578bd2f0b3334369834ff1f344b4b033318172586a9324496027a057507a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d76a45da1f1e181d77b6f9cbfc6f80d88af6abed0782b1da92f6562934bf551c2f55e5691be7108d0acf0521562a042bb5cba6f54f9846af78b7ba4031d35fb
|
7
|
+
data.tar.gz: 2ec4137407dfaf6b4189255532e59669798ac9ed57be8e6ecdb07c31525d132b9246da9d9fd6b98975e31b712e002e2693f523acf285d172df1b13c7c46617d5
|
data/README.md
CHANGED
@@ -3,9 +3,7 @@
|
|
3
3
|

|
4
4
|
[](http://badge.fury.io/rb/eqq)
|
5
5
|
|
6
|
-
Pattern objects builder
|
7
|
-
|
8
|
-
`eqq` means `#===`
|
6
|
+
Pattern objects builder
|
9
7
|
|
10
8
|
## Usage
|
11
9
|
|
@@ -14,7 +12,7 @@ Require Ruby 2.6 or later
|
|
14
12
|
Add below code into your Gemfile
|
15
13
|
|
16
14
|
```ruby
|
17
|
-
gem 'eqq', '0.0.
|
15
|
+
gem 'eqq', '>= 0.0.7', '< 0.1.0'
|
18
16
|
```
|
19
17
|
|
20
18
|
### Overview
|
@@ -26,13 +24,133 @@ require 'eqq'
|
|
26
24
|
[42, nil, true, false, '', 0].grep(Eqq.BOOLEAN) #=> [true, false]
|
27
25
|
[42, [], {}, 'string', Object.new, nil].grep(Eqq.CAN(:to_h)) #=> [[], {}, nil]
|
28
26
|
|
29
|
-
pattern = Eqq.
|
27
|
+
pattern = Eqq.build do
|
30
28
|
OR(AND(Float, 20..50), Integer)
|
31
29
|
end
|
30
|
+
|
31
|
+
p pattern #=> "OR(AND(Float, 20..50), Integer)"
|
32
32
|
[4.2, 42, 42.0, 420].grep(pattern) #=> [42, 42.0, 420]
|
33
|
+
|
34
|
+
inverted = Eqq.NOT(pattern)
|
35
|
+
p inverted #=> "NOT(OR(AND(Float, 20..50), Integer))"
|
36
|
+
[4.2, 42, 42.0, 420].grep(inverted) #=> [4.2]
|
37
|
+
|
38
|
+
Eqq.SEND(:all?, pattern) === [4.2, 42, 42.0, 420] #=> false
|
39
|
+
Eqq.SEND(:any?, pattern) === [4.2, 42, 42.0, 420] #=> true
|
40
|
+
|
41
|
+
ret_in_case = (
|
42
|
+
case 42
|
43
|
+
when pattern
|
44
|
+
'Should be matched here! :)'
|
45
|
+
when inverted
|
46
|
+
'Should not be matched here! :<'
|
47
|
+
else
|
48
|
+
'Should not be matched here too! :<'
|
49
|
+
end
|
50
|
+
)
|
51
|
+
|
52
|
+
p ret_in_case #=> Should be matched here! :)
|
53
|
+
|
54
|
+
ret_in_case = (
|
55
|
+
case 4.2
|
56
|
+
when pattern
|
57
|
+
'Should not be matched here! :<'
|
58
|
+
when inverted
|
59
|
+
'Should be matched here! :)'
|
60
|
+
else
|
61
|
+
'Should not be matched here too! :<'
|
62
|
+
end
|
63
|
+
)
|
64
|
+
|
65
|
+
p ret_in_case #=> Should be matched here! :)
|
66
|
+
|
67
|
+
class MyClass
|
68
|
+
include Eqq::Buildable
|
69
|
+
|
70
|
+
def example
|
71
|
+
[4.2, 42, 42.0, 420].grep(OR(AND(Float, 20..50), Integer))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
MyClass.new.example #=> [42, 42.0, 420]
|
33
75
|
```
|
34
76
|
|
77
|
+
### Explanation
|
78
|
+
|
79
|
+
All products can be called as `pattern === other`.
|
80
|
+
|
81
|
+
This signature will fit in most Ruby code.
|
82
|
+
|
83
|
+
* `case ~ when` syntax
|
84
|
+
* Enumerable#grep
|
85
|
+
* Enumerable#grep_v
|
86
|
+
* Enumerable#all?
|
87
|
+
* Enumerable#any?
|
88
|
+
* Enumerable#none?
|
89
|
+
* Enumerable#one?
|
90
|
+
* Enumerable#slice_after
|
91
|
+
* Enumerable#slice_before
|
92
|
+
|
93
|
+
They can take this interface as the `pattern`.
|
94
|
+
|
95
|
+
And you already saw. All of patterns can be mixed with other patterns as a parts.
|
96
|
+
Reuse as you wish!
|
97
|
+
|
98
|
+
### Builders
|
99
|
+
|
100
|
+
* OR(*patterns) - Product returns `true` when matched even one pattern
|
101
|
+
* AND(*patterns) - Product returns `true` when matched all patterns
|
102
|
+
* NOT(pattern) - Product returns `true` when not matched the pattern
|
103
|
+
* CAN(*method_names) - Product returns `true` when it has all of the methods (checked with `respond_to?`)
|
104
|
+
* RESCUE(exception_class/module, pattern) - Product returns `true` when the pattern raises the exception
|
105
|
+
* QUIET(*patterns) - Product returns `true` when all patterns did not raise any exception
|
106
|
+
* EQ(object) - Product returns `true` when matched with `#==`
|
107
|
+
* SAME(object) - Product returns `true` when matched with `#equal?`
|
108
|
+
* SEND(name, pattern) - Basically provided for Enumerable
|
109
|
+
* BOOLEAN() - Product returns `true` when matched to `true` or `false`
|
110
|
+
* NIL() - Product returns `true` when matched to `nil` (Not consider `nil?`)
|
111
|
+
* ANYTHING() - Product returns `true`, always `true`
|
112
|
+
* NEVER() - Product returns `false`, always `false`
|
113
|
+
* XOR(pattern1, pattern2) - Product returns `true` when matched one of the pattern, when matched both returns `false`
|
114
|
+
* NAND(*patterns) - Product is an inverted `AND`
|
115
|
+
* NOR(*patterns) - Product is an inverted `OR`
|
116
|
+
|
117
|
+
### Best fit for RSpec's `satisfy` matcher too
|
118
|
+
|
119
|
+
All builders actually generate a `Proc (lambda)` instance.
|
120
|
+
The signature will fit for RSpec's built-in [`satisfy` matcher](https://relishapp.com/rspec/rspec-expectations/v/3-10/docs/built-in-matchers/satisfy-matcher) too.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
RSpec.describe RSpec::Matchers::BuiltIn::Satisfy do
|
124
|
+
let(:product) { Eqq.AND(Integer, 24..42) }
|
125
|
+
|
126
|
+
it 'perfectly works' do
|
127
|
+
expect(23).not_to satisfy(&product)
|
128
|
+
expect(24).to satisfy(&product)
|
129
|
+
expect(24.0).not_to satisfy(&product)
|
130
|
+
expect(42).to satisfy(&product)
|
131
|
+
expect(42.0).not_to satisfy(&product)
|
132
|
+
expect(43).not_to satisfy(&product)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
### Use builders without receiver specifying
|
138
|
+
|
139
|
+
When you felt annoy to write `Eqq` in many place, some ways exist.
|
140
|
+
|
141
|
+
* `Eqq.build(&block)` - In the block scope, all builder methods can be used without receiver
|
142
|
+
* `extend Eqq::Buildable` - In the class/module, all builders can be used as class methods
|
143
|
+
* `include Eqq::Buildable` - In the class/module, all builders can be used as instance methods
|
144
|
+
|
145
|
+
### Signature
|
146
|
+
|
147
|
+
* This gem provides [ruby/rbs](https://github.com/ruby/rbs) signature file
|
148
|
+
|
35
149
|
## Links
|
36
150
|
|
37
151
|
* [Repository](https://github.com/kachick/eqq)
|
38
152
|
* [API documents](https://kachick.github.io/eqq)
|
153
|
+
|
154
|
+
## NOTE
|
155
|
+
|
156
|
+
* [`eqq` is the implementation name of `#===` in CRuby](https://github.com/ruby/ruby/blob/2a685da1fcd928530509e99f5edb4117bc377994/range.c#L1859)
|
data/lib/eqq.rb
CHANGED
@@ -4,21 +4,18 @@
|
|
4
4
|
# Copyright (c) 2011 Kenichi Kamiya
|
5
5
|
# Forked from https://github.com/kachick/validation at 2021
|
6
6
|
|
7
|
-
require_relative 'eqq/buildable'
|
8
7
|
require_relative 'eqq/version'
|
9
8
|
|
9
|
+
# Pattern objects builder
|
10
10
|
module Eqq
|
11
|
-
|
12
|
-
|
11
|
+
# Base error of this library
|
13
12
|
class Error < StandardError; end
|
14
|
-
class InvalidProductError < Error; end
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
14
|
+
# Raised when found some products are invalid as a pattern object
|
15
|
+
class InvalidProductError < Error; end
|
19
16
|
|
20
17
|
class << self
|
21
|
-
def
|
18
|
+
def pattern?(object)
|
22
19
|
case object
|
23
20
|
when Proc, Method
|
24
21
|
object.arity == 1
|
@@ -31,11 +28,41 @@ module Eqq
|
|
31
28
|
end
|
32
29
|
end
|
33
30
|
|
34
|
-
|
31
|
+
# @deprecated Use {pattern?} instead. This will be dropped since `0.1.0`
|
32
|
+
def valid?(object)
|
33
|
+
pattern?(object)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @api private
|
37
|
+
def satisfy?(object)
|
38
|
+
(Proc === object) && object.lambda? && (object.arity == 1) && object.respond_to?(:inspect)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Proc]
|
42
|
+
# @raise [InvalidProductError] if the return value is not looks to be built with builders
|
43
|
+
def build(&block)
|
44
|
+
raise ArgumentError, 'might be mis used the `Eqq.build` in your code' unless block
|
45
|
+
|
35
46
|
pattern = DSLScope.new.instance_exec(&block)
|
36
|
-
raise InvalidProductError unless
|
47
|
+
raise InvalidProductError, 'might be mis used the `Eqq.build` in your code' unless satisfy?(pattern)
|
37
48
|
|
38
49
|
pattern
|
39
50
|
end
|
51
|
+
|
52
|
+
# @deprecated Use {build} instead. This will be dropped since `0.1.0`
|
53
|
+
def define(&block)
|
54
|
+
build(&block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
require_relative 'eqq/buildable'
|
60
|
+
|
61
|
+
module Eqq
|
62
|
+
extend Buildable
|
63
|
+
|
64
|
+
class DSLScope
|
65
|
+
include Buildable
|
40
66
|
end
|
67
|
+
private_constant(:DSLScope)
|
41
68
|
end
|
data/lib/eqq/buildable.rb
CHANGED
@@ -2,20 +2,69 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Eqq
|
5
|
+
# Actually having definitions for the pattern builders
|
5
6
|
module Buildable
|
6
|
-
|
7
|
+
class << self
|
8
|
+
# When the inspection is failed some unexpected reasons, it will fallback to this value
|
9
|
+
# This value is not fixed as a spec, might be changed in future
|
10
|
+
INSPECTION_FALLBACK = 'UninspectableObject'
|
7
11
|
|
12
|
+
# @api private
|
13
|
+
# @return [String]
|
14
|
+
def safe_inspect_for(object)
|
15
|
+
String.try_convert(object.inspect) || INSPECTION_FALLBACK
|
16
|
+
rescue Exception
|
17
|
+
# This implementation used `RSpec::Support::ObjectFormatter::UninspectableObjectInspector` as a reference, thank you!
|
18
|
+
# ref: https://github.com/kachick/times_kachick/issues/97
|
19
|
+
singleton_class = class << object; self; end
|
20
|
+
begin
|
21
|
+
klass = singleton_class.ancestors.detect { |ancestor| !ancestor.equal?(singleton_class) }
|
22
|
+
native_object_id = '%#016x' % (object.__id__ << 1)
|
23
|
+
"#<#{klass}:#{native_object_id}>"
|
24
|
+
rescue Exception
|
25
|
+
INSPECTION_FALLBACK
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
# @return [void]
|
31
|
+
def define_inspect_on(product, name:, arguments:)
|
32
|
+
inspect = "#{name}(#{arguments.map { |argument| safe_inspect_for(argument) }.join(', ')})".freeze
|
33
|
+
product.define_singleton_method(:inspect) do
|
34
|
+
inspect
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @api private
|
39
|
+
# @return [void]
|
40
|
+
def validate_patterns(*patterns)
|
41
|
+
invalids = patterns.reject { |pattern| Eqq.pattern?(pattern) }
|
42
|
+
invalid_inspections = invalids.map { |invalid| safe_inspect_for(invalid) }.join(', ')
|
43
|
+
raise ArgumentError, "given `#{invalid_inspections}` are invalid as pattern objects" unless invalids.empty?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Product returns `true` when matched all patterns
|
48
|
+
#
|
8
49
|
# @param pattern1 [Proc, Method, #===]
|
9
50
|
# @param pattern2 [Proc, Method, #===]
|
10
51
|
# @param patterns [Array<Proc, Method, #===>]
|
11
52
|
# @return [Proc]
|
12
|
-
# this lambda return true if match all patterns
|
13
53
|
def AND(pattern1, pattern2, *patterns)
|
14
|
-
|
15
|
-
|
54
|
+
patterns = [pattern1, pattern2, *patterns].freeze
|
55
|
+
Buildable.validate_patterns(*patterns)
|
56
|
+
|
57
|
+
product = ->v {
|
58
|
+
patterns.all? { |pattern| pattern === v }
|
16
59
|
}
|
60
|
+
|
61
|
+
Buildable.define_inspect_on(product, name: 'AND', arguments: patterns)
|
62
|
+
|
63
|
+
product
|
17
64
|
end
|
18
65
|
|
66
|
+
# Product is an inverted {#AND}
|
67
|
+
#
|
19
68
|
# @param pattern1 [Proc, Method, #===]
|
20
69
|
# @param pattern2 [Proc, Method, #===]
|
21
70
|
# @param patterns [Array<Proc, Method, #===>]
|
@@ -24,17 +73,26 @@ module Eqq
|
|
24
73
|
NOT(AND(pattern1, pattern2, *patterns))
|
25
74
|
end
|
26
75
|
|
76
|
+
# Product returns `true` when matched even one pattern
|
77
|
+
#
|
27
78
|
# @param pattern1 [Proc, Method, #===]
|
28
79
|
# @param pattern2 [Proc, Method, #===]
|
29
80
|
# @param patterns [Array<Proc, Method, #===>]
|
30
81
|
# @return [Proc]
|
31
|
-
# this lambda return true if match a any pattern
|
32
82
|
def OR(pattern1, pattern2, *patterns)
|
33
|
-
|
34
|
-
|
83
|
+
patterns = [pattern1, pattern2, *patterns].freeze
|
84
|
+
Buildable.validate_patterns(*patterns)
|
85
|
+
|
86
|
+
product = ->v {
|
87
|
+
patterns.any? { |pattern| pattern === v }
|
35
88
|
}
|
89
|
+
Buildable.define_inspect_on(product, name: 'OR', arguments: patterns)
|
90
|
+
|
91
|
+
product
|
36
92
|
end
|
37
93
|
|
94
|
+
# Product is an inverted {#OR}
|
95
|
+
#
|
38
96
|
# @param pattern1 [Proc, Method, #===]
|
39
97
|
# @param pattern2 [Proc, Method, #===]
|
40
98
|
# @param patterns [Array<Proc, Method, #===>]
|
@@ -43,56 +101,72 @@ module Eqq
|
|
43
101
|
NOT(OR(pattern1, pattern2, *patterns))
|
44
102
|
end
|
45
103
|
|
104
|
+
# Product returns `true` when matched one of the pattern, when matched both returns `false`
|
105
|
+
#
|
46
106
|
# @param pattern1 [Proc, Method, #===]
|
47
107
|
# @param pattern2 [Proc, Method, #===]
|
48
|
-
# @param patterns [Array<Proc, Method, #===>]
|
49
108
|
# @return [Proc]
|
50
|
-
def XOR(pattern1, pattern2
|
51
|
-
|
52
|
-
|
109
|
+
def XOR(pattern1, pattern2)
|
110
|
+
patterns = [pattern1, pattern2].freeze
|
111
|
+
Buildable.validate_patterns(*patterns)
|
112
|
+
|
113
|
+
product = ->v {
|
114
|
+
patterns.one? { |pattern| pattern === v }
|
53
115
|
}
|
54
|
-
|
116
|
+
Buildable.define_inspect_on(product, name: 'XOR', arguments: patterns)
|
55
117
|
|
56
|
-
|
57
|
-
# @param pattern2 [Proc, Method, #===]
|
58
|
-
# @param patterns [Array<Proc, Method, #===>]
|
59
|
-
# @return [Proc]
|
60
|
-
def XNOR(pattern1, pattern2, *patterns)
|
61
|
-
NOT(XOR(pattern1, pattern2, *patterns))
|
118
|
+
product
|
62
119
|
end
|
63
120
|
|
121
|
+
# Product returns `true` when not matched the pattern
|
122
|
+
#
|
64
123
|
# @param pattern [Proc, Method, #===]
|
65
124
|
# @return [Proc]
|
66
125
|
def NOT(pattern)
|
67
|
-
|
126
|
+
Buildable.validate_patterns(pattern)
|
68
127
|
|
69
|
-
->v { !(pattern === v) }
|
128
|
+
product = ->v { !(pattern === v) }
|
129
|
+
|
130
|
+
Buildable.define_inspect_on(product, name: 'NOT', arguments: [pattern])
|
131
|
+
|
132
|
+
product
|
70
133
|
end
|
71
134
|
|
72
|
-
#
|
135
|
+
# Product returns `true` when matched with `#==`
|
136
|
+
#
|
73
137
|
# @param obj [#==]
|
74
138
|
# @return [Proc]
|
75
139
|
def EQ(obj)
|
76
|
-
->v { obj == v }
|
140
|
+
product = ->v { obj == v }
|
141
|
+
Buildable.define_inspect_on(product, name: 'EQ', arguments: [obj])
|
142
|
+
product
|
77
143
|
end
|
78
144
|
|
145
|
+
# Product returns `true` when matched with `#equal?`
|
146
|
+
#
|
79
147
|
# @param obj [#equal?]
|
80
148
|
# @return [Proc]
|
81
149
|
def SAME(obj)
|
82
|
-
->v { obj.equal?(v) }
|
150
|
+
product = ->v { obj.equal?(v) }
|
151
|
+
Buildable.define_inspect_on(product, name: 'SAME', arguments: [obj])
|
152
|
+
product
|
83
153
|
end
|
84
154
|
|
85
|
-
#
|
86
|
-
#
|
155
|
+
# Product returns `true` when it has all of the methods (checked with `respond_to?`)
|
156
|
+
#
|
157
|
+
# @param message1 [Symbol, String, #to_sym]
|
158
|
+
# @param messages [Array<Symbol, String, #to_sym>]
|
87
159
|
# @return [Proc]
|
88
160
|
def CAN(message1, *messages)
|
89
|
-
messages =
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
161
|
+
messages = (
|
162
|
+
begin
|
163
|
+
[message1, *messages].map(&:to_sym).freeze
|
164
|
+
rescue NoMethodError
|
165
|
+
raise ArgumentError
|
166
|
+
end
|
167
|
+
)
|
94
168
|
|
95
|
-
->v {
|
169
|
+
product = ->v {
|
96
170
|
messages.all? { |message|
|
97
171
|
begin
|
98
172
|
v.respond_to?(message)
|
@@ -101,18 +175,22 @@ module Eqq
|
|
101
175
|
end
|
102
176
|
}
|
103
177
|
}
|
178
|
+
|
179
|
+
Buildable.define_inspect_on(product, name: 'CAN', arguments: messages)
|
180
|
+
|
181
|
+
product
|
104
182
|
end
|
105
183
|
|
184
|
+
# Product returns `true` when all patterns did not raise any exception
|
185
|
+
#
|
106
186
|
# @param pattern1 [Proc, Method, #===]
|
107
187
|
# @param patterns [Array<Proc, Method, #===>]
|
108
188
|
# @return [Proc]
|
109
189
|
def QUIET(pattern1, *patterns)
|
110
|
-
patterns = [pattern1, *patterns]
|
111
|
-
|
112
|
-
raise ArgumentError, 'wrong object for pattern'
|
113
|
-
end
|
190
|
+
patterns = [pattern1, *patterns].freeze
|
191
|
+
Buildable.validate_patterns(*patterns)
|
114
192
|
|
115
|
-
->v {
|
193
|
+
product = ->v {
|
116
194
|
patterns.all? { |pattern|
|
117
195
|
begin
|
118
196
|
pattern === v
|
@@ -123,16 +201,22 @@ module Eqq
|
|
123
201
|
end
|
124
202
|
}
|
125
203
|
}
|
204
|
+
|
205
|
+
Buildable.define_inspect_on(product, name: 'QUIET', arguments: patterns)
|
206
|
+
|
207
|
+
product
|
126
208
|
end
|
127
209
|
|
210
|
+
# Product returns `true` when the pattern raises the exception
|
211
|
+
#
|
128
212
|
# @param mod [Module]
|
129
213
|
# @param pattern [Proc, Method, #===]
|
130
214
|
# @return [Proc]
|
131
215
|
def RESCUE(mod, pattern)
|
132
|
-
|
216
|
+
Buildable.validate_patterns(pattern)
|
133
217
|
raise ArgumentError unless Module === mod
|
134
218
|
|
135
|
-
->v {
|
219
|
+
product = ->v {
|
136
220
|
begin
|
137
221
|
pattern === v
|
138
222
|
false
|
@@ -142,31 +226,76 @@ module Eqq
|
|
142
226
|
false
|
143
227
|
end
|
144
228
|
}
|
229
|
+
|
230
|
+
Buildable.define_inspect_on(product, name: 'RESCUE', arguments: [mod, pattern])
|
231
|
+
|
232
|
+
product
|
145
233
|
end
|
146
234
|
|
147
|
-
#
|
235
|
+
# Basically provided for Enumerable
|
236
|
+
#
|
237
|
+
# @param name [Symbol, String, #to_sym]
|
148
238
|
# @param pattern [Proc, Method, #===]
|
149
239
|
# @return [Proc]
|
150
240
|
def SEND(name, pattern)
|
151
|
-
|
241
|
+
name = (
|
242
|
+
begin
|
243
|
+
name.to_sym
|
244
|
+
rescue NoMethodError
|
245
|
+
raise ArgumentError
|
246
|
+
end
|
247
|
+
)
|
248
|
+
Buildable.validate_patterns(pattern)
|
152
249
|
|
153
|
-
->v {
|
250
|
+
product = ->v {
|
154
251
|
v.__send__(name, pattern)
|
155
252
|
}
|
253
|
+
|
254
|
+
Buildable.define_inspect_on(product, name: 'SEND', arguments: [name, pattern])
|
255
|
+
|
256
|
+
product
|
156
257
|
end
|
157
258
|
|
158
|
-
|
259
|
+
EQQ_BUILTIN_ANYTHING = ->_v { true }
|
260
|
+
define_inspect_on(EQQ_BUILTIN_ANYTHING, name: 'ANYTHING', arguments: [])
|
261
|
+
|
262
|
+
# Product returns `true`, always `true`
|
263
|
+
#
|
264
|
+
# @return [Proc]
|
159
265
|
def ANYTHING
|
160
|
-
|
161
|
-
|
266
|
+
EQQ_BUILTIN_ANYTHING
|
267
|
+
end
|
268
|
+
|
269
|
+
EQQ_BUILTIN_NEVER = ->_v { false }
|
270
|
+
define_inspect_on(EQQ_BUILTIN_NEVER, name: 'NEVER', arguments: [])
|
271
|
+
|
272
|
+
# Product returns `false`, always `false`
|
273
|
+
#
|
274
|
+
# @return [Proc]
|
275
|
+
def NEVER
|
276
|
+
EQQ_BUILTIN_NEVER
|
162
277
|
end
|
163
278
|
|
164
|
-
|
165
|
-
|
279
|
+
EQQ_BUILTIN_BOOLEAN = ->v { true.equal?(v) || false.equal?(v) }
|
280
|
+
define_inspect_on(EQQ_BUILTIN_BOOLEAN, name: 'BOOLEAN', arguments: [])
|
166
281
|
|
167
|
-
#
|
282
|
+
# Product returns `true` when matched to `true` or `false`
|
283
|
+
#
|
284
|
+
# @return [Proc]
|
168
285
|
def BOOLEAN
|
169
|
-
|
286
|
+
EQQ_BUILTIN_BOOLEAN
|
287
|
+
end
|
288
|
+
|
289
|
+
EQQ_BUILTIN_NIL = ->v { nil.equal?(v) }
|
290
|
+
define_inspect_on(EQQ_BUILTIN_NIL, name: 'NIL', arguments: [])
|
291
|
+
|
292
|
+
# Product returns `true` when matched to `nil` (Not consider `nil?`)
|
293
|
+
#
|
294
|
+
# @return [Proc]
|
295
|
+
def NIL
|
296
|
+
EQQ_BUILTIN_NIL
|
170
297
|
end
|
298
|
+
|
299
|
+
private_constant(:EQQ_BUILTIN_ANYTHING, :EQQ_BUILTIN_NEVER, :EQQ_BUILTIN_BOOLEAN, :EQQ_BUILTIN_NIL)
|
171
300
|
end
|
172
301
|
end
|
data/lib/eqq/version.rb
CHANGED
data/sig/eqq.rbs
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# Pattern objects builder
|
1
2
|
module Eqq
|
2
3
|
interface _Patternable
|
3
4
|
def ===: (untyped object) -> bool
|
@@ -7,43 +8,114 @@ module Eqq
|
|
7
8
|
def to_sym: -> Symbol
|
8
9
|
end
|
9
10
|
|
11
|
+
interface _Inspectable
|
12
|
+
def inspect: () -> String
|
13
|
+
end
|
14
|
+
|
10
15
|
module Buildable
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
def
|
28
|
-
|
29
|
-
|
16
|
+
type patternable_lambda = ^(untyped object) -> bool
|
17
|
+
type product = patternable_lambda & _Inspectable
|
18
|
+
|
19
|
+
# A private constant. Should not be used in your code.
|
20
|
+
EQQ_BUILTIN_ANYTHING: product
|
21
|
+
|
22
|
+
# A private constant. Should not be used in your code.
|
23
|
+
EQQ_BUILTIN_NEVER: product
|
24
|
+
|
25
|
+
# A private constant. Should not be used in your code.
|
26
|
+
EQQ_BUILTIN_BOOLEAN: product
|
27
|
+
|
28
|
+
# A private constant. Should not be used in your code.
|
29
|
+
EQQ_BUILTIN_NIL: product
|
30
|
+
|
31
|
+
# A private API. Should not be used in your code.
|
32
|
+
def self.safe_inspect_for: (untyped object)-> String
|
33
|
+
|
34
|
+
# A private API. Should not be used in your code.
|
35
|
+
def self.define_inspect_on: (patternable_lambda product, name: String, arguments: Array[untyped])-> void
|
36
|
+
|
37
|
+
# A private API. Should not be used in your code.
|
38
|
+
def self.validate_patterns: (*untyped) -> void
|
39
|
+
|
40
|
+
# Product returns `true` when matched even one pattern
|
41
|
+
def OR: (_Patternable, _Patternable, *_Patternable) -> product
|
42
|
+
|
43
|
+
# Product returns `true` when matched all patterns
|
44
|
+
def AND: (_Patternable, _Patternable, *_Patternable) -> product
|
45
|
+
|
46
|
+
# Product is an inverted `AND`
|
47
|
+
def NAND: (_Patternable, _Patternable, *_Patternable) -> product
|
48
|
+
|
49
|
+
# Product is an inverted `OR`
|
50
|
+
def NOR: (_Patternable, _Patternable, *_Patternable) -> product
|
51
|
+
|
52
|
+
# Product returns `true` when matched one of the pattern, when matched both returns `false`
|
53
|
+
def XOR: (_Patternable, _Patternable) -> product
|
54
|
+
|
55
|
+
# Product returns `true` when not matched the pattern
|
56
|
+
def NOT: (_Patternable) -> product
|
57
|
+
|
58
|
+
# Product returns `true` when matched with `#==`
|
59
|
+
def EQ: (untyped object) -> product
|
60
|
+
|
61
|
+
# Product returns `true` when matched with `#equal?`
|
62
|
+
def SAME: (untyped object) -> product
|
63
|
+
|
64
|
+
# Product returns `true` when it has all of the methods (checked with `respond_to?`)
|
65
|
+
def CAN: (_ToSym, *_ToSym) -> product
|
66
|
+
|
67
|
+
# Product returns `true` when the pattern raises the exception
|
68
|
+
def RESCUE: (Module, _Patternable) -> product
|
69
|
+
|
70
|
+
# Product returns `true` when all patterns did not raise any exception
|
71
|
+
def QUIET: (_Patternable, *_Patternable) -> product
|
72
|
+
|
73
|
+
# Basically provided for Enumerable
|
74
|
+
def SEND: (Symbol | String name, _Patternable) -> product
|
75
|
+
|
76
|
+
# Product returns `true`, always `true`
|
77
|
+
def ANYTHING: () -> product
|
78
|
+
|
79
|
+
# Product returns `false`, always `false`
|
80
|
+
def NEVER: () -> product
|
81
|
+
|
82
|
+
# Product returns `true` when matched to `true` or `false`
|
83
|
+
def BOOLEAN: () -> product
|
84
|
+
|
85
|
+
# Product returns `true` when matched to `nil` (Not consider `nil?`)
|
86
|
+
def NIL: () -> product
|
30
87
|
end
|
31
88
|
|
32
89
|
extend Buildable
|
33
90
|
|
91
|
+
# Base error of this library
|
34
92
|
class Error < StandardError
|
35
93
|
end
|
36
94
|
|
95
|
+
# Raised when found some products are invalid as a pattern object
|
37
96
|
class InvalidProductError < Error
|
38
97
|
end
|
39
98
|
|
40
|
-
# A
|
99
|
+
# A private API. Should not be used in your code.
|
41
100
|
class DSLScope
|
42
101
|
include Buildable
|
43
102
|
end
|
44
103
|
|
45
104
|
VERSION: String
|
46
105
|
|
106
|
+
# Returns `true` when given object has patternable signature
|
107
|
+
def self.pattern?: (untyped object) -> bool
|
108
|
+
|
109
|
+
# Alias of `pattern?`. But deperecated. Do not use in your code anymore.
|
47
110
|
def self.valid?: (untyped object) -> bool
|
111
|
+
|
112
|
+
# Returns `true` when given object has correct signature as a product of builders
|
113
|
+
# Basically this is a private API. Should not be used in your code.
|
114
|
+
def self.satisfy?: (untyped object) -> bool
|
115
|
+
|
116
|
+
# In the block scope, all builder methods can be used without receiver
|
117
|
+
def self.build: { () -> _Patternable } -> _Patternable
|
118
|
+
|
119
|
+
# Alias of `build`. But deperecated. Do not use in your code anymore.
|
48
120
|
def self.define: { () -> _Patternable } -> _Patternable
|
49
121
|
end
|
metadata
CHANGED
@@ -1,16 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eqq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenichi Kamiya
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-06-
|
11
|
+
date: 2021-06-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
13
|
+
description: |2
|
14
|
+
Pattern objects builder.
|
15
|
+
|
16
|
+
All products can be used as `pattern === something`.
|
17
|
+
|
18
|
+
All products can be mixed with other products as a parts.
|
19
|
+
|
20
|
+
Reuse as you wish!
|
14
21
|
email:
|
15
22
|
- kachick1+ruby@gmail.com
|
16
23
|
executables: []
|
@@ -49,5 +56,5 @@ requirements: []
|
|
49
56
|
rubygems_version: 3.2.15
|
50
57
|
signing_key:
|
51
58
|
specification_version: 4
|
52
|
-
summary: Pattern objects builder
|
59
|
+
summary: Pattern objects builder
|
53
60
|
test_files: []
|