eqq 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +87 -5
- data/lib/eqq.rb +11 -7
- data/lib/eqq/buildable.rb +122 -43
- data/lib/eqq/version.rb +1 -1
- data/sig/eqq.rbs +39 -18
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22307661e329771fea7efcd7c282d17eda0130d0edb7aec3088257b21b73e4ba
|
4
|
+
data.tar.gz: ebc3138ade59e38f9bc34a42a93654d3a6ab1564a48b47df13d65ed7227c7488
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16ae2b50b3c81291028946ec6ddb8753c06bc7fc472f29ab00b3f69b9136540f26079b8c23f983d0bf1482f93543744f2fae557bb0ef71f6fdcc73f115df9455
|
7
|
+
data.tar.gz: eced8529614ce3b1b8a4cc4087d58943bdbaabd0637a86bb10bcafe472ccdece82bae71d390fde84e95176318961e4ef74207ab4debc6e117411608f2e074176
|
data/README.md
CHANGED
@@ -3,9 +3,7 @@
|
|
3
3
|
![Build Status](https://github.com/kachick/eqq/actions/workflows/test_behaviors.yml/badge.svg?branch=main)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/eqq.png)](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.3'
|
18
16
|
```
|
19
17
|
|
20
18
|
### Overview
|
@@ -29,10 +27,94 @@ require 'eqq'
|
|
29
27
|
pattern = Eqq.define 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! :)
|
33
66
|
```
|
34
67
|
|
68
|
+
### Explanation
|
69
|
+
|
70
|
+
All products can be called as `pattern === other`.
|
71
|
+
|
72
|
+
This signature will fit in most Ruby code.
|
73
|
+
|
74
|
+
* `case ~ when` syntax
|
75
|
+
* Enumerable#grep
|
76
|
+
* Enumerable#grep_v
|
77
|
+
* Enumerable#all?
|
78
|
+
* Enumerable#any?
|
79
|
+
* Enumerable#none?
|
80
|
+
* Enumerable#one?
|
81
|
+
* Enumerable#slice_after
|
82
|
+
* Enumerable#slice_before
|
83
|
+
|
84
|
+
They can take this interface as the `pattern`.
|
85
|
+
|
86
|
+
And you already saw. All of patterns can be mixed with other patterns as a parts.
|
87
|
+
Reuse as you wish!
|
88
|
+
|
89
|
+
Major builders as below
|
90
|
+
|
91
|
+
* OR(*patterns) - Product returns true when matched even one pattern
|
92
|
+
* AND(*patterns) - Product returns true when matched all patterns
|
93
|
+
* NOT(pattern) - Product returns true when not matched the pattern
|
94
|
+
* CAN(*method_names) - Product returns true when it has all of the methods (checked with `respond_to?`)
|
95
|
+
* RESCUE(exception_class/module, pattern) - Product returns true when the pattern raises the exception
|
96
|
+
* QUIET(*patterns) - Product returns true when all patterns did not raise any exception
|
97
|
+
* EQ(object) - Product returns true when matched with `#==`
|
98
|
+
* SAME(object) - Product returns true when matched with `#equal?`
|
99
|
+
* SEND(name, pattern) - Basically provided for Enumerable
|
100
|
+
* BOOLEAN() - Product returns true when matched to true or false
|
101
|
+
* ANYTHING() - Product returns true, always true
|
102
|
+
|
103
|
+
Minor builders as below, please see [API documents](https://kachick.github.io/eqq) for them.
|
104
|
+
|
105
|
+
* NAND
|
106
|
+
* NOR
|
107
|
+
* XOR
|
108
|
+
|
109
|
+
When you feel annoy to write `Eqq` in many place, please use `Eqq.define`.
|
110
|
+
In the block scope, all builder methods can be used without receiver specifying.
|
111
|
+
|
112
|
+
This gem provide [ruby/rbs](https://github.com/ruby/rbs) signature
|
113
|
+
|
35
114
|
## Links
|
36
115
|
|
37
116
|
* [Repository](https://github.com/kachick/eqq)
|
38
|
-
|
117
|
+
|
118
|
+
## NOTE
|
119
|
+
|
120
|
+
* [`eqq` is the implementation name of `#===` in CRuby](https://github.com/ruby/ruby/blob/2a685da1fcd928530509e99f5edb4117bc377994/range.c#L1859)
|
data/lib/eqq.rb
CHANGED
@@ -4,19 +4,12 @@
|
|
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
|
|
10
9
|
module Eqq
|
11
|
-
extend Buildable
|
12
|
-
|
13
10
|
class Error < StandardError; end
|
14
11
|
class InvalidProductError < Error; end
|
15
12
|
|
16
|
-
class DSLScope
|
17
|
-
include Buildable
|
18
|
-
end
|
19
|
-
|
20
13
|
class << self
|
21
14
|
def valid?(object)
|
22
15
|
case object
|
@@ -31,6 +24,7 @@ module Eqq
|
|
31
24
|
end
|
32
25
|
end
|
33
26
|
|
27
|
+
# @return [#===]
|
34
28
|
def define(&block)
|
35
29
|
pattern = DSLScope.new.instance_exec(&block)
|
36
30
|
raise InvalidProductError unless valid?(pattern)
|
@@ -39,3 +33,13 @@ module Eqq
|
|
39
33
|
end
|
40
34
|
end
|
41
35
|
end
|
36
|
+
|
37
|
+
require_relative 'eqq/buildable'
|
38
|
+
|
39
|
+
module Eqq
|
40
|
+
extend Buildable
|
41
|
+
|
42
|
+
class DSLScope
|
43
|
+
include Buildable
|
44
|
+
end
|
45
|
+
end
|
data/lib/eqq/buildable.rb
CHANGED
@@ -5,15 +5,59 @@ module Eqq
|
|
5
5
|
module Buildable
|
6
6
|
extend self
|
7
7
|
|
8
|
+
class << self
|
9
|
+
INSPECTION_FALLBACK = 'UninspectableObject'
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
# @return [String]
|
13
|
+
def safe_inspect(object)
|
14
|
+
String.try_convert(object.inspect) || INSPECTION_FALLBACK
|
15
|
+
rescue Exception
|
16
|
+
# This implementation used `RSpec::Support::ObjectFormatter::UninspectableObjectInspector` as a reference, thank you!
|
17
|
+
# ref: https://github.com/kachick/times_kachick/issues/97
|
18
|
+
singleton_class = class << object; self; end
|
19
|
+
begin
|
20
|
+
klass = singleton_class.ancestors.detect { |ancestor| !ancestor.equal?(singleton_class) }
|
21
|
+
native_object_id = '%#016x' % (object.__id__ << 1)
|
22
|
+
"#<#{klass}:#{native_object_id}>"
|
23
|
+
rescue Exception
|
24
|
+
INSPECTION_FALLBACK
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
# @return [void]
|
30
|
+
def set_inspect(name:, product:, arguments:)
|
31
|
+
inspect = "#{name}(#{arguments.map { |argument| safe_inspect(argument) }.join(', ')})".freeze
|
32
|
+
product.define_singleton_method(:inspect) do
|
33
|
+
inspect
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
# @return [void]
|
39
|
+
def validate_patterns(*patterns)
|
40
|
+
invalids = patterns.reject { |pattern| Eqq.valid?(pattern) }
|
41
|
+
invalid_inspections = invalids.map { |invalid| safe_inspect(invalid) }.join(', ')
|
42
|
+
raise ArgumentError, "given `#{invalid_inspections}` are invalid as pattern objects" unless invalids.empty?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
8
46
|
# @param pattern1 [Proc, Method, #===]
|
9
47
|
# @param pattern2 [Proc, Method, #===]
|
10
48
|
# @param patterns [Array<Proc, Method, #===>]
|
11
49
|
# @return [Proc]
|
12
|
-
# this lambda return true if match all patterns
|
13
50
|
def AND(pattern1, pattern2, *patterns)
|
14
|
-
|
15
|
-
|
51
|
+
patterns = [pattern1, pattern2, *patterns].freeze
|
52
|
+
Buildable.validate_patterns(*patterns)
|
53
|
+
|
54
|
+
product = ->v {
|
55
|
+
patterns.all? { |pattern| pattern === v }
|
16
56
|
}
|
57
|
+
|
58
|
+
Buildable.set_inspect(name: 'AND', product: product, arguments: patterns)
|
59
|
+
|
60
|
+
product
|
17
61
|
end
|
18
62
|
|
19
63
|
# @param pattern1 [Proc, Method, #===]
|
@@ -28,11 +72,16 @@ module Eqq
|
|
28
72
|
# @param pattern2 [Proc, Method, #===]
|
29
73
|
# @param patterns [Array<Proc, Method, #===>]
|
30
74
|
# @return [Proc]
|
31
|
-
# this lambda return true if match a any pattern
|
32
75
|
def OR(pattern1, pattern2, *patterns)
|
33
|
-
|
34
|
-
|
76
|
+
patterns = [pattern1, pattern2, *patterns].freeze
|
77
|
+
Buildable.validate_patterns(*patterns)
|
78
|
+
|
79
|
+
product = ->v {
|
80
|
+
patterns.any? { |pattern| pattern === v }
|
35
81
|
}
|
82
|
+
Buildable.set_inspect(name: 'OR', product: product, arguments: patterns)
|
83
|
+
|
84
|
+
product
|
36
85
|
end
|
37
86
|
|
38
87
|
# @param pattern1 [Proc, Method, #===]
|
@@ -45,54 +94,60 @@ module Eqq
|
|
45
94
|
|
46
95
|
# @param pattern1 [Proc, Method, #===]
|
47
96
|
# @param pattern2 [Proc, Method, #===]
|
48
|
-
# @param patterns [Array<Proc, Method, #===>]
|
49
97
|
# @return [Proc]
|
50
|
-
def XOR(pattern1, pattern2
|
51
|
-
|
52
|
-
|
98
|
+
def XOR(pattern1, pattern2)
|
99
|
+
patterns = [pattern1, pattern2].freeze
|
100
|
+
Buildable.validate_patterns(*patterns)
|
101
|
+
|
102
|
+
product = ->v {
|
103
|
+
patterns.one? { |pattern| pattern === v }
|
53
104
|
}
|
54
|
-
|
105
|
+
Buildable.set_inspect(name: 'XOR', product: product, arguments: patterns)
|
55
106
|
|
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))
|
107
|
+
product
|
62
108
|
end
|
63
109
|
|
64
110
|
# @param pattern [Proc, Method, #===]
|
65
111
|
# @return [Proc]
|
66
112
|
def NOT(pattern)
|
67
|
-
|
113
|
+
Buildable.validate_patterns(pattern)
|
114
|
+
|
115
|
+
product = ->v { !(pattern === v) }
|
68
116
|
|
69
|
-
|
117
|
+
Buildable.set_inspect(name: 'NOT', product: product, arguments: [pattern])
|
118
|
+
|
119
|
+
product
|
70
120
|
end
|
71
121
|
|
72
|
-
# A pattern builder.
|
73
122
|
# @param obj [#==]
|
74
123
|
# @return [Proc]
|
75
124
|
def EQ(obj)
|
76
|
-
->v { obj == v }
|
125
|
+
->v { obj == v }.tap do |product|
|
126
|
+
Buildable.set_inspect(name: 'EQ', product: product, arguments: [obj])
|
127
|
+
end
|
77
128
|
end
|
78
129
|
|
79
130
|
# @param obj [#equal?]
|
80
131
|
# @return [Proc]
|
81
132
|
def SAME(obj)
|
82
|
-
->v { obj.equal?(v) }
|
133
|
+
->v { obj.equal?(v) }.tap do |product|
|
134
|
+
Buildable.set_inspect(name: 'SAME', product: product, arguments: [obj])
|
135
|
+
end
|
83
136
|
end
|
84
137
|
|
85
|
-
# @param message1 [Symbol, String]
|
86
|
-
# @param messages [Array<Symbol, String>]
|
138
|
+
# @param message1 [Symbol, String, #to_sym]
|
139
|
+
# @param messages [Array<Symbol, String, #to_sym>]
|
87
140
|
# @return [Proc]
|
88
141
|
def CAN(message1, *messages)
|
89
|
-
messages =
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
142
|
+
messages = (
|
143
|
+
begin
|
144
|
+
[message1, *messages].map(&:to_sym).freeze
|
145
|
+
rescue NoMethodError
|
146
|
+
raise ArgumentError
|
147
|
+
end
|
148
|
+
)
|
94
149
|
|
95
|
-
->v {
|
150
|
+
product = ->v {
|
96
151
|
messages.all? { |message|
|
97
152
|
begin
|
98
153
|
v.respond_to?(message)
|
@@ -101,18 +156,20 @@ module Eqq
|
|
101
156
|
end
|
102
157
|
}
|
103
158
|
}
|
159
|
+
|
160
|
+
Buildable.set_inspect(name: 'CAN', product: product, arguments: messages)
|
161
|
+
|
162
|
+
product
|
104
163
|
end
|
105
164
|
|
106
165
|
# @param pattern1 [Proc, Method, #===]
|
107
166
|
# @param patterns [Array<Proc, Method, #===>]
|
108
167
|
# @return [Proc]
|
109
168
|
def QUIET(pattern1, *patterns)
|
110
|
-
patterns = [pattern1, *patterns]
|
111
|
-
|
112
|
-
raise ArgumentError, 'wrong object for pattern'
|
113
|
-
end
|
169
|
+
patterns = [pattern1, *patterns].freeze
|
170
|
+
Buildable.validate_patterns(*patterns)
|
114
171
|
|
115
|
-
->v {
|
172
|
+
product = ->v {
|
116
173
|
patterns.all? { |pattern|
|
117
174
|
begin
|
118
175
|
pattern === v
|
@@ -123,16 +180,20 @@ module Eqq
|
|
123
180
|
end
|
124
181
|
}
|
125
182
|
}
|
183
|
+
|
184
|
+
Buildable.set_inspect(name: 'QUIET', product: product, arguments: patterns)
|
185
|
+
|
186
|
+
product
|
126
187
|
end
|
127
188
|
|
128
189
|
# @param mod [Module]
|
129
190
|
# @param pattern [Proc, Method, #===]
|
130
191
|
# @return [Proc]
|
131
192
|
def RESCUE(mod, pattern)
|
132
|
-
|
193
|
+
Buildable.validate_patterns(pattern)
|
133
194
|
raise ArgumentError unless Module === mod
|
134
195
|
|
135
|
-
->v {
|
196
|
+
product = ->v {
|
136
197
|
begin
|
137
198
|
pattern === v
|
138
199
|
false
|
@@ -142,23 +203,41 @@ module Eqq
|
|
142
203
|
false
|
143
204
|
end
|
144
205
|
}
|
206
|
+
|
207
|
+
Buildable.set_inspect(name: 'RESCUE', product: product, arguments: [mod, pattern])
|
208
|
+
|
209
|
+
product
|
145
210
|
end
|
146
211
|
|
147
|
-
# @param name [Symbol, #to_sym]
|
212
|
+
# @param name [Symbol, String, #to_sym]
|
148
213
|
# @param pattern [Proc, Method, #===]
|
149
214
|
# @return [Proc]
|
150
215
|
def SEND(name, pattern)
|
151
|
-
|
216
|
+
name = (
|
217
|
+
begin
|
218
|
+
name.to_sym
|
219
|
+
rescue NoMethodError
|
220
|
+
raise ArgumentError
|
221
|
+
end
|
222
|
+
)
|
223
|
+
Buildable.validate_patterns(pattern)
|
152
224
|
|
153
|
-
->v {
|
225
|
+
product = ->v {
|
154
226
|
v.__send__(name, pattern)
|
155
227
|
}
|
228
|
+
|
229
|
+
Buildable.set_inspect(name: 'SEND', product: product, arguments: [name, pattern])
|
230
|
+
|
231
|
+
product
|
156
232
|
end
|
157
233
|
|
158
|
-
|
234
|
+
ANYTHING = ->_v { true }
|
235
|
+
Buildable.set_inspect(name: 'ANYTHING', product: ANYTHING, arguments: [])
|
236
|
+
private_constant :ANYTHING
|
237
|
+
|
238
|
+
# @return [ANYTHING]
|
159
239
|
def ANYTHING
|
160
|
-
|
161
|
-
BasicObject
|
240
|
+
ANYTHING
|
162
241
|
end
|
163
242
|
|
164
243
|
BOOLEAN = OR(SAME(true), SAME(false))
|
data/lib/eqq/version.rb
CHANGED
data/sig/eqq.rbs
CHANGED
@@ -7,26 +7,44 @@ module Eqq
|
|
7
7
|
def to_sym: -> Symbol
|
8
8
|
end
|
9
9
|
|
10
|
+
interface _Inspectable
|
11
|
+
def inspect: () -> String
|
12
|
+
end
|
13
|
+
|
10
14
|
module Buildable
|
11
|
-
|
12
|
-
|
15
|
+
type patternable_lambda = ^(untyped object) -> bool
|
16
|
+
type product = patternable_lambda & _Inspectable
|
17
|
+
|
18
|
+
# A private constant. Should not be used in your code.
|
19
|
+
ANYTHING: product
|
20
|
+
|
21
|
+
# A private constant. Should not be used in your code.
|
22
|
+
BOOLEAN: product
|
23
|
+
|
24
|
+
# A private API. Should not be used in your code.
|
25
|
+
def self.safe_inspect: (untyped object)-> String
|
26
|
+
|
27
|
+
# A private API. Should not be used in your code.
|
28
|
+
def self.set_inspect: (name: String, product: patternable_lambda, arguments: Array[untyped])-> void
|
29
|
+
|
30
|
+
# A private API. Should not be used in your code.
|
31
|
+
def self.validate_patterns: (*untyped) -> void
|
13
32
|
|
14
33
|
extend Buildable
|
15
|
-
def OR: (_Patternable, _Patternable, *_Patternable) ->
|
16
|
-
def AND: (_Patternable, _Patternable, *_Patternable) ->
|
17
|
-
def NAND: (_Patternable, _Patternable, *_Patternable) ->
|
18
|
-
def NOR: (_Patternable, _Patternable, *_Patternable) ->
|
19
|
-
def XOR: (_Patternable, _Patternable
|
20
|
-
def
|
21
|
-
def
|
22
|
-
def
|
23
|
-
def
|
24
|
-
def
|
25
|
-
def
|
26
|
-
def
|
27
|
-
def
|
28
|
-
def
|
29
|
-
def BOOLEAN: () -> ^(untyped object) -> bool
|
34
|
+
def OR: (_Patternable, _Patternable, *_Patternable) -> product
|
35
|
+
def AND: (_Patternable, _Patternable, *_Patternable) -> product
|
36
|
+
def NAND: (_Patternable, _Patternable, *_Patternable) -> product
|
37
|
+
def NOR: (_Patternable, _Patternable, *_Patternable) -> product
|
38
|
+
def XOR: (_Patternable, _Patternable) -> product
|
39
|
+
def NOT: (_Patternable) -> product
|
40
|
+
def EQ: (untyped object) -> product
|
41
|
+
def SAME: (untyped object) -> product
|
42
|
+
def CAN: (_ToSym, *_ToSym) -> product
|
43
|
+
def RESCUE: (Module, _Patternable) -> product
|
44
|
+
def QUIET: (_Patternable, *_Patternable) -> product
|
45
|
+
def SEND: (Symbol | String name, _Patternable) -> product
|
46
|
+
def ANYTHING: () -> product
|
47
|
+
def BOOLEAN: () -> product
|
30
48
|
end
|
31
49
|
|
32
50
|
extend Buildable
|
@@ -37,13 +55,16 @@ module Eqq
|
|
37
55
|
class InvalidProductError < Error
|
38
56
|
end
|
39
57
|
|
40
|
-
# A
|
58
|
+
# A private API. Should not be used in your code.
|
41
59
|
class DSLScope
|
42
60
|
include Buildable
|
43
61
|
end
|
44
62
|
|
45
63
|
VERSION: String
|
46
64
|
|
65
|
+
# A private constant. Should not be used in your code.
|
66
|
+
INSPECTION_FALLBACK: String
|
67
|
+
|
47
68
|
def self.valid?: (untyped object) -> bool
|
48
69
|
def self.define: { () -> _Patternable } -> _Patternable
|
49
70
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.3
|
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-02 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: " [4.2, 42, 42.0, 420].grep(Eqq.AND(Integer, 20..50)) #=> [42]\n"
|
14
14
|
email:
|