eqq 0.0.1 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bca6982f43fb57004acdca8facb594d0d178999bdcb323a41663138d9f00325
4
- data.tar.gz: 31f2e909e814925d47cf64824ac1267597fc2b85d3a4704ed9612704f6b41071
3
+ metadata.gz: d0645f6178f68b0a105efa1bcf389bd3c0b1f056cd94a6c6684b0d18bc9284f8
4
+ data.tar.gz: a93f3a7df8098fbb1e7bdb61b5ad36c29a67e4471e563c63bb562b7896cfa60d
5
5
  SHA512:
6
- metadata.gz: e30c7e8c661ffb9764e9c604503454e3bd29de40075f6e8296540d0b3a41a482c1221178d155e2c090b1b075ea4ec4d6f63306d5eaeba3b69e505e981abd0712
7
- data.tar.gz: '0885388e12a098f0c26415b252f0bc552c39e526df9ffbed2beffcc046ffe778eee99a71120e23e6ea80c61c1aee67b5769208196fee9d422646a6d90e4e92d4'
6
+ metadata.gz: a5d02720dfa28fc5aefed2907008e14e76dc00fd087eb83eb6c89bbf8c976b0258410d554592fc1368938bfcda8e96efc99ae2a811f285dfba33b210bf795ba5
7
+ data.tar.gz: e8077c6bd4ab3c5e363abeaa5154dca3bf8154140a73f75d238883cefe92855fb8da843ba46037c12ffb9bc710b9449b1d121a6e2119dc774520bd237f71d564
data/MIT-LICENSE.txt CHANGED
@@ -7,7 +7,7 @@ of this software and associated documentation files (the "Software"), to deal
7
7
  in the Software without restriction, including without limitation the rights
8
8
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
9
  copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
10
+ furnished to do so, subject to the following patterns:
11
11
 
12
12
  The above copyright notice and this permission notice shall be included in all
13
13
  copies or substantial portions of the Software.
data/README.md CHANGED
@@ -3,18 +3,16 @@
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
 
12
- Require Ruby 2.5 or later
10
+ Require Ruby 2.6 or later
13
11
 
14
12
  Add below code into your Gemfile
15
13
 
16
14
  ```ruby
17
- gem 'eqq', '>= 0.0.1', '< 0.1.0'
15
+ gem 'eqq', '>= 0.0.6', '< 0.1.0'
18
16
  ```
19
17
 
20
18
  ### Overview
@@ -29,10 +27,129 @@ 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! :)
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
+ * ANYTHING() - Product returns `true`, always `true`
111
+ * NEVER() - Product returns `false`, always `false`
112
+ * XOR(pattern1, pattern2) - Product returns `true` when matched one of the pattern, when matched both returns `false`
113
+ * NAND(*patterns) - Product is an inverted `AND`
114
+ * NOR(*patterns) - Product is an inverted `OR`
115
+
116
+ ### Best fit for RSpec's `satisfy` matcher too
117
+
118
+ All builders actually generate a `Proc (lambda)` instance.
119
+ 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.
120
+
121
+ ```ruby
122
+ RSpec.describe RSpec::Matchers::BuiltIn::Satisfy do
123
+ let(:product) { Eqq.AND(Integer, 24..42) }
124
+
125
+ it 'perfectly works' do
126
+ expect(23).not_to satisfy(&product)
127
+ expect(24).to satisfy(&product)
128
+ expect(24.0).not_to satisfy(&product)
129
+ expect(42).to satisfy(&product)
130
+ expect(42.0).not_to satisfy(&product)
131
+ expect(43).not_to satisfy(&product)
132
+ end
133
+ end
134
+ ```
135
+
136
+ ### Use builders without receiver specifying
137
+
138
+ When you felt annoy to write `Eqq` in many place, some ways exist.
139
+
140
+ * `Eqq.define(&block)` - In the block scope, all builder methods can be used without receiver
141
+ * `extend Eqq::Buildable` - In the class/module, all builders can be used as class methods
142
+ * `include Eqq::Buildable` - In the class/module, all builders can be used as instance methods
143
+
144
+ ### Signature
145
+
146
+ * This gem provides [ruby/rbs](https://github.com/ruby/rbs) signature file
147
+
35
148
  ## Links
36
149
 
37
150
  * [Repository](https://github.com/kachick/eqq)
38
151
  * [API documents](https://kachick.github.io/eqq)
152
+
153
+ ## NOTE
154
+
155
+ * [`eqq` is the implementation name of `#===` in CRuby](https://github.com/ruby/ruby/blob/2a685da1fcd928530509e99f5edb4117bc377994/range.c#L1859)
data/lib/eqq.rb CHANGED
@@ -2,238 +2,60 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Copyright (c) 2011 Kenichi Kamiya
5
- # Forked from https://github.com/kachick/eqq at 2021
5
+ # Forked from https://github.com/kachick/validation at 2021
6
6
 
7
- module Eqq
8
- def self.conditionable?(object)
9
- case object
10
- when Proc, Method
11
- object.arity == 1
12
- else
13
- begin
14
- object.respond_to?(:===)
15
- rescue NoMethodError
16
- false
17
- end
18
- end
19
- end
20
-
21
- def self.define(&block)
22
- module_exec(&block)
23
- end
24
-
25
- module_function
26
-
27
- # A condition builder.
28
- # @param condition1 [Proc, Method, #===]
29
- # @param condition2 [Proc, Method, #===]
30
- # @param conditions [Array<Proc, Method, #===>]
31
- # @return [Proc]
32
- # this lambda return true if match all conditions
33
- def AND(condition1, condition2, *conditions)
34
- ->v {
35
- [condition1, condition2, *conditions].all? { |condition| condition === v }
36
- }
37
- end
38
-
39
- # A condition builder.
40
- # @param condition1 [Proc, Method, #===]
41
- # @param condition2 [Proc, Method, #===]
42
- # @param conditions [Array<Proc, Method, #===>]
43
- # @return [Proc]
44
- def NAND(condition1, condition2, *conditions)
45
- NOT(AND(condition1, condition2, *conditions))
46
- end
47
-
48
- # A condition builder.
49
- # @param condition1 [Proc, Method, #===]
50
- # @param condition2 [Proc, Method, #===]
51
- # @param conditions [Array<Proc, Method, #===>]
52
- # @return [Proc]
53
- # this lambda return true if match a any condition
54
- def OR(condition1, condition2, *conditions)
55
- ->v {
56
- [condition1, condition2, *conditions].any? { |condition| condition === v }
57
- }
58
- end
59
-
60
- # A condition builder.
61
- # @param condition1 [Proc, Method, #===]
62
- # @param condition2 [Proc, Method, #===]
63
- # @param conditions [Array<Proc, Method, #===>]
64
- # @return [Proc]
65
- def NOR(condition1, condition2, *conditions)
66
- NOT(OR(condition1, condition2, *conditions))
67
- end
68
-
69
- # A condition builder.
70
- # @param condition1 [Proc, Method, #===]
71
- # @param condition2 [Proc, Method, #===]
72
- # @param conditions [Array<Proc, Method, #===>]
73
- # @return [Proc]
74
- def XOR(condition1, condition2, *conditions)
75
- ->v {
76
- [condition1, condition2, *conditions].one? { |condition| condition === v }
77
- }
78
- end
79
-
80
- # A condition builder.
81
- # @param condition1 [Proc, Method, #===]
82
- # @param condition2 [Proc, Method, #===]
83
- # @param conditions [Array<Proc, Method, #===>]
84
- # @return [Proc]
85
- def XNOR(condition1, condition2, *conditions)
86
- NOT(XOR(condition1, condition2, *conditions))
87
- end
88
-
89
- # A condition builder.
90
- # @param condition [Proc, Method, #===]
91
- # @return [Proc] A condition invert the original condition.
92
- def NOT(condition)
93
- unless Eqq.conditionable?(condition)
94
- raise TypeError, 'wrong object for condition'
95
- end
96
-
97
- ->v { !(condition === v) }
98
- end
99
-
100
- # A condition builder.
101
- # @param obj [#==]
102
- # @return [Proc]
103
- # this lambda return true if a argument match under #== method
104
- def EQ(obj)
105
- ->v { obj == v }
106
- end
107
-
108
- # A condition builder.
109
- # @param obj [#equal?]
110
- # @return [Proc]
111
- # this lambda return true if a argument match under #equal? method
112
- def SAME(obj)
113
- ->v { obj.equal?(v) }
114
- end
115
-
116
- # A condition builder.
117
- # @param message1 [Symbol, String]
118
- # @param messages [Array<Symbol, String>]
119
- # @return [Proc]
120
- # this lambda return true if a argument respond to all messages
121
- def CAN(message1, *messages)
122
- messages = [message1, *messages].map(&:to_sym)
7
+ require_relative 'eqq/version'
123
8
 
124
- ->v {
125
- messages.all? { |message| v.respond_to?(message) }
126
- }
127
- end
9
+ # Pattern objects builder
10
+ module Eqq
11
+ # Base error of this library
12
+ class Error < StandardError; end
128
13
 
129
- # A condition builder.
130
- # @param condition1 [Proc, Method, #===]
131
- # @param conditions [Array<Proc, Method, #===>]
132
- # @return [Proc]
133
- # this lambda return true
134
- # if face no exception when a argument checking under all conditions
135
- def QUIET(condition1, *conditions)
136
- conditions = [condition1, *conditions]
137
- unless conditions.all? { |c| Eqq.conditionable?(c) }
138
- raise TypeError, 'wrong object for condition'
139
- end
14
+ # Raised when found some products are invalid as a pattern object
15
+ class InvalidProductError < Error; end
140
16
 
141
- ->v {
142
- conditions.all? { |condition|
17
+ class << self
18
+ def pattern?(object)
19
+ case object
20
+ when Proc, Method
21
+ object.arity == 1
22
+ else
143
23
  begin
144
- condition === v
145
- rescue Exception
24
+ object.respond_to?(:===)
25
+ rescue NoMethodError
146
26
  false
147
- else
148
- true
149
27
  end
150
- }
151
- }
152
- end
153
-
154
- # A condition builder.
155
- # @param exception [Exception]
156
- # @param exceptions [Array<Exception>]
157
- # @return [Proc]
158
- # this lambda return true
159
- # if catch any kindly exceptions when a argument checking in a block parameter
160
- def RESCUE(exception, *exceptions, &condition)
161
- exceptions = [exception, *exceptions]
162
- raise ArgumentError unless Eqq.conditionable?(condition)
163
- raise ArgumentError unless exceptions.all?(Exception)
164
-
165
- ->v {
166
- begin
167
- condition.call(v)
168
- false
169
- rescue *exceptions
170
- true
171
- rescue Exception
172
- false
173
28
  end
174
- }
175
- end
176
-
177
- # A condition builder.
178
- # @param exception [Exception]
179
- # @return [Proc]
180
- # this lambda return true
181
- # if catch a specific exception when a argument checking in a block parameter
182
- def CATCH(exception, &condition)
183
- raise ArgumentError unless Eqq.conditionable?(condition)
184
- raise ArgumentError unless exceptions.all?(Exception)
29
+ end
185
30
 
186
- ->v {
187
- begin
188
- condition.call(v)
189
- rescue Exception => err
190
- err.instance_of?(exception)
191
- else
192
- false
193
- end
194
- }
195
- end
31
+ # @deprecated Use {pattern?} instead. This will be dropped since `0.1.0`
32
+ def valid?(object)
33
+ pattern?(object)
34
+ end
196
35
 
197
- # A condition builder.
198
- # @param condition1 [Proc, Method, #===]
199
- # @param condition2 [Proc, Method, #===]
200
- # @param conditions [Array<Proc, Method, #===>]
201
- # @return [Proc]
202
- # this lambda return true
203
- # if all included objects match all conditions
204
- def ALL(condition1, condition2, *conditions)
205
- condition = Eqq.AND(condition1, condition2, *conditions)
36
+ # @api private
37
+ def satisfy?(object)
38
+ (Proc === object) && object.lambda? && (object.arity == 1)
39
+ end
206
40
 
207
- ->list {
208
- enum = (
209
- case
210
- when list.respond_to?(:each_value)
211
- list.each_value
212
- when list.respond_to?(:all?)
213
- list
214
- when list.respond_to?(:each)
215
- list.each
216
- else
217
- return false
218
- end
219
- )
41
+ # @return [#===]
42
+ # @raise [InvalidProductError] if the return value is invalid as a pattern object
43
+ def define(&block)
44
+ pattern = DSLScope.new.instance_exec(&block)
45
+ raise InvalidProductError unless satisfy?(pattern)
220
46
 
221
- enum.all?(condition)
222
- }
47
+ pattern
48
+ end
223
49
  end
50
+ end
224
51
 
225
- def ANYTHING
226
- # BasicObject.=== always passing
227
- BasicObject
228
- end
52
+ require_relative 'eqq/buildable'
229
53
 
230
- BOOLEAN = OR(SAME(true), SAME(false))
54
+ module Eqq
55
+ extend Buildable
231
56
 
232
- # A getter for a useful condition.
233
- # @return [BOOLEAN] "true or false"
234
- def BOOLEAN
235
- BOOLEAN
57
+ class DSLScope
58
+ include Buildable
236
59
  end
60
+ private_constant :DSLScope
237
61
  end
238
-
239
- require_relative 'eqq/version'
@@ -0,0 +1,292 @@
1
+ # coding: us-ascii
2
+ # frozen_string_literal: true
3
+
4
+ module Eqq
5
+ # Actually having definitions for the pattern builders
6
+ module Buildable
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'
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
+ #
49
+ # @param pattern1 [Proc, Method, #===]
50
+ # @param pattern2 [Proc, Method, #===]
51
+ # @param patterns [Array<Proc, Method, #===>]
52
+ # @return [Proc]
53
+ def AND(pattern1, pattern2, *patterns)
54
+ patterns = [pattern1, pattern2, *patterns].freeze
55
+ Buildable.validate_patterns(*patterns)
56
+
57
+ product = ->v {
58
+ patterns.all? { |pattern| pattern === v }
59
+ }
60
+
61
+ Buildable.define_inspect_on(product, name: 'AND', arguments: patterns)
62
+
63
+ product
64
+ end
65
+
66
+ # Product is an inverted {#AND}
67
+ #
68
+ # @param pattern1 [Proc, Method, #===]
69
+ # @param pattern2 [Proc, Method, #===]
70
+ # @param patterns [Array<Proc, Method, #===>]
71
+ # @return [Proc]
72
+ def NAND(pattern1, pattern2, *patterns)
73
+ NOT(AND(pattern1, pattern2, *patterns))
74
+ end
75
+
76
+ # Product returns `true` when matched even one pattern
77
+ #
78
+ # @param pattern1 [Proc, Method, #===]
79
+ # @param pattern2 [Proc, Method, #===]
80
+ # @param patterns [Array<Proc, Method, #===>]
81
+ # @return [Proc]
82
+ def OR(pattern1, pattern2, *patterns)
83
+ patterns = [pattern1, pattern2, *patterns].freeze
84
+ Buildable.validate_patterns(*patterns)
85
+
86
+ product = ->v {
87
+ patterns.any? { |pattern| pattern === v }
88
+ }
89
+ Buildable.define_inspect_on(product, name: 'OR', arguments: patterns)
90
+
91
+ product
92
+ end
93
+
94
+ # Product is an inverted {#OR}
95
+ #
96
+ # @param pattern1 [Proc, Method, #===]
97
+ # @param pattern2 [Proc, Method, #===]
98
+ # @param patterns [Array<Proc, Method, #===>]
99
+ # @return [Proc]
100
+ def NOR(pattern1, pattern2, *patterns)
101
+ NOT(OR(pattern1, pattern2, *patterns))
102
+ end
103
+
104
+ # Product returns `true` when matched one of the pattern, when matched both returns `false`
105
+ #
106
+ # @param pattern1 [Proc, Method, #===]
107
+ # @param pattern2 [Proc, Method, #===]
108
+ # @return [Proc]
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 }
115
+ }
116
+ Buildable.define_inspect_on(product, name: 'XOR', arguments: patterns)
117
+
118
+ product
119
+ end
120
+
121
+ # Product returns `true` when not matched the pattern
122
+ #
123
+ # @param pattern [Proc, Method, #===]
124
+ # @return [Proc]
125
+ def NOT(pattern)
126
+ Buildable.validate_patterns(pattern)
127
+
128
+ product = ->v { !(pattern === v) }
129
+
130
+ Buildable.define_inspect_on(product, name: 'NOT', arguments: [pattern])
131
+
132
+ product
133
+ end
134
+
135
+ # Product returns `true` when matched with `#==`
136
+ #
137
+ # @param obj [#==]
138
+ # @return [Proc]
139
+ def EQ(obj)
140
+ product = ->v { obj == v }
141
+ Buildable.define_inspect_on(product, name: 'EQ', arguments: [obj])
142
+ product
143
+ end
144
+
145
+ # Product returns `true` when matched with `#equal?`
146
+ #
147
+ # @param obj [#equal?]
148
+ # @return [Proc]
149
+ def SAME(obj)
150
+ product = ->v { obj.equal?(v) }
151
+ Buildable.define_inspect_on(product, name: 'SAME', arguments: [obj])
152
+ product
153
+ end
154
+
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>]
159
+ # @return [Proc]
160
+ def CAN(message1, *messages)
161
+ messages = (
162
+ begin
163
+ [message1, *messages].map(&:to_sym).freeze
164
+ rescue NoMethodError
165
+ raise ArgumentError
166
+ end
167
+ )
168
+
169
+ product = ->v {
170
+ messages.all? { |message|
171
+ begin
172
+ v.respond_to?(message)
173
+ rescue NoMethodError
174
+ false
175
+ end
176
+ }
177
+ }
178
+
179
+ Buildable.define_inspect_on(product, name: 'CAN', arguments: messages)
180
+
181
+ product
182
+ end
183
+
184
+ # Product returns `true` when all patterns did not raise any exception
185
+ #
186
+ # @param pattern1 [Proc, Method, #===]
187
+ # @param patterns [Array<Proc, Method, #===>]
188
+ # @return [Proc]
189
+ def QUIET(pattern1, *patterns)
190
+ patterns = [pattern1, *patterns].freeze
191
+ Buildable.validate_patterns(*patterns)
192
+
193
+ product = ->v {
194
+ patterns.all? { |pattern|
195
+ begin
196
+ pattern === v
197
+ rescue Exception
198
+ false
199
+ else
200
+ true
201
+ end
202
+ }
203
+ }
204
+
205
+ Buildable.define_inspect_on(product, name: 'QUIET', arguments: patterns)
206
+
207
+ product
208
+ end
209
+
210
+ # Product returns `true` when the pattern raises the exception
211
+ #
212
+ # @param mod [Module]
213
+ # @param pattern [Proc, Method, #===]
214
+ # @return [Proc]
215
+ def RESCUE(mod, pattern)
216
+ Buildable.validate_patterns(pattern)
217
+ raise ArgumentError unless Module === mod
218
+
219
+ product = ->v {
220
+ begin
221
+ pattern === v
222
+ false
223
+ rescue mod
224
+ true
225
+ rescue Exception
226
+ false
227
+ end
228
+ }
229
+
230
+ Buildable.define_inspect_on(product, name: 'RESCUE', arguments: [mod, pattern])
231
+
232
+ product
233
+ end
234
+
235
+ # Basically provided for Enumerable
236
+ #
237
+ # @param name [Symbol, String, #to_sym]
238
+ # @param pattern [Proc, Method, #===]
239
+ # @return [Proc]
240
+ def SEND(name, pattern)
241
+ name = (
242
+ begin
243
+ name.to_sym
244
+ rescue NoMethodError
245
+ raise ArgumentError
246
+ end
247
+ )
248
+ Buildable.validate_patterns(pattern)
249
+
250
+ product = ->v {
251
+ v.__send__(name, pattern)
252
+ }
253
+
254
+ Buildable.define_inspect_on(product, name: 'SEND', arguments: [name, pattern])
255
+
256
+ product
257
+ end
258
+
259
+ ANYTHING = ->_v { true }
260
+ define_inspect_on(ANYTHING, name: 'ANYTHING', arguments: [])
261
+ private_constant :ANYTHING
262
+
263
+ # Product returns `true`, always `true`
264
+ #
265
+ # @return [Proc]
266
+ def ANYTHING
267
+ ANYTHING
268
+ end
269
+
270
+ NEVER = ->_v { false }
271
+ define_inspect_on(NEVER, name: 'NEVER', arguments: [])
272
+ private_constant :NEVER
273
+
274
+ # Product returns `false`, always `false`
275
+ #
276
+ # @return [Proc]
277
+ def NEVER
278
+ NEVER
279
+ end
280
+
281
+ BOOLEAN = ->v { true.equal?(v) || false.equal?(v) }
282
+ define_inspect_on(BOOLEAN, name: 'BOOLEAN', arguments: [])
283
+ private_constant :BOOLEAN
284
+
285
+ # Product returns `true` when matched to `true` or `false`
286
+ #
287
+ # @return [Proc]
288
+ def BOOLEAN
289
+ BOOLEAN
290
+ end
291
+ end
292
+ end
data/lib/eqq/version.rb CHANGED
@@ -2,5 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Eqq
5
- VERSION = '0.0.1'
5
+ # This will be same as latest published gem version
6
+ VERSION = '0.0.6'
6
7
  end
data/sig/eqq.rbs ADDED
@@ -0,0 +1,112 @@
1
+ # Pattern objects builder
2
+ module Eqq
3
+ interface _Patternable
4
+ def ===: (untyped object) -> bool
5
+ end
6
+
7
+ interface _ToSym
8
+ def to_sym: -> Symbol
9
+ end
10
+
11
+ interface _Inspectable
12
+ def inspect: () -> String
13
+ end
14
+
15
+ module Buildable
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
+ ANYTHING: product
21
+
22
+ # A private constant. Should not be used in your code.
23
+ NEVER: product
24
+
25
+ # A private constant. Should not be used in your code.
26
+ BOOLEAN: product
27
+
28
+ # A private API. Should not be used in your code.
29
+ def self.safe_inspect_for: (untyped object)-> String
30
+
31
+ # A private API. Should not be used in your code.
32
+ def self.define_inspect_on: (patternable_lambda product, name: String, arguments: Array[untyped])-> void
33
+
34
+ # A private API. Should not be used in your code.
35
+ def self.validate_patterns: (*untyped) -> void
36
+
37
+ # Product returns `true` when matched even one pattern
38
+ def OR: (_Patternable, _Patternable, *_Patternable) -> product
39
+
40
+ # Product returns `true` when matched all patterns
41
+ def AND: (_Patternable, _Patternable, *_Patternable) -> product
42
+
43
+ # Product is an inverted `AND`
44
+ def NAND: (_Patternable, _Patternable, *_Patternable) -> product
45
+
46
+ # Product is an inverted `OR`
47
+ def NOR: (_Patternable, _Patternable, *_Patternable) -> product
48
+
49
+ # Product returns `true` when matched one of the pattern, when matched both returns `false`
50
+ def XOR: (_Patternable, _Patternable) -> product
51
+
52
+ # Product returns `true` when not matched the pattern
53
+ def NOT: (_Patternable) -> product
54
+
55
+ # Product returns `true` when matched with `#==`
56
+ def EQ: (untyped object) -> product
57
+
58
+ # Product returns `true` when matched with `#equal?`
59
+ def SAME: (untyped object) -> product
60
+
61
+ # Product returns `true` when it has all of the methods (checked with `respond_to?`)
62
+ def CAN: (_ToSym, *_ToSym) -> product
63
+
64
+ # Product returns `true` when the pattern raises the exception
65
+ def RESCUE: (Module, _Patternable) -> product
66
+
67
+ # Product returns `true` when all patterns did not raise any exception
68
+ def QUIET: (_Patternable, *_Patternable) -> product
69
+
70
+ # Basically provided for Enumerable
71
+ def SEND: (Symbol | String name, _Patternable) -> product
72
+
73
+ # Product returns `true`, always `true`
74
+ def ANYTHING: () -> product
75
+
76
+ # Product returns `false`, always `false`
77
+ def NEVER: () -> product
78
+
79
+ # Product returns `true` when matched to `true` or `false`
80
+ def BOOLEAN: () -> product
81
+ end
82
+
83
+ extend Buildable
84
+
85
+ # Base error of this library
86
+ class Error < StandardError
87
+ end
88
+
89
+ # Raised when found some products are invalid as a pattern object
90
+ class InvalidProductError < Error
91
+ end
92
+
93
+ # A private API. Should not be used in your code.
94
+ class DSLScope
95
+ include Buildable
96
+ end
97
+
98
+ VERSION: String
99
+
100
+ # Returns `true` when given object has patternable signature
101
+ def self.pattern?: (untyped object) -> bool
102
+
103
+ # Alias of `pattern?`. But deperecated. Do not use in your code anymore.
104
+ def self.valid?: (untyped object) -> bool
105
+
106
+ # Returns `true` when given object has correct signature as a product of builders
107
+ # Basically this is a private API. Should not be used in your code.
108
+ def self.satisfy?: (untyped object) -> bool
109
+
110
+ # In the block scope, all builder methods can be used without receiver
111
+ def self.define: { () -> _Patternable } -> _Patternable
112
+ end
metadata CHANGED
@@ -1,230 +1,23 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eqq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.6
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-01 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: test-unit
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 3.4.1
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '4.0'
23
- type: :development
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 3.4.1
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '4.0'
33
- - !ruby/object:Gem::Dependency
34
- name: irb
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: 1.3.5
40
- - - "<"
41
- - !ruby/object:Gem::Version
42
- version: '2.0'
43
- type: :development
44
- prerelease: false
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 1.3.5
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: '2.0'
53
- - !ruby/object:Gem::Dependency
54
- name: irb-power_assert
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - '='
58
- - !ruby/object:Gem::Version
59
- version: 0.0.2
60
- type: :development
61
- prerelease: false
62
- version_requirements: !ruby/object:Gem::Requirement
63
- requirements:
64
- - - '='
65
- - !ruby/object:Gem::Version
66
- version: 0.0.2
67
- - !ruby/object:Gem::Dependency
68
- name: warning
69
- requirement: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 1.2.0
74
- - - "<"
75
- - !ruby/object:Gem::Version
76
- version: '2.0'
77
- type: :development
78
- prerelease: false
79
- version_requirements: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- version: 1.2.0
84
- - - "<"
85
- - !ruby/object:Gem::Version
86
- version: '2.0'
87
- - !ruby/object:Gem::Dependency
88
- name: rake
89
- requirement: !ruby/object:Gem::Requirement
90
- requirements:
91
- - - ">="
92
- - !ruby/object:Gem::Version
93
- version: 13.0.3
94
- - - "<"
95
- - !ruby/object:Gem::Version
96
- version: '20.0'
97
- type: :development
98
- prerelease: false
99
- version_requirements: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 13.0.3
104
- - - "<"
105
- - !ruby/object:Gem::Version
106
- version: '20.0'
107
- - !ruby/object:Gem::Dependency
108
- name: yard
109
- requirement: !ruby/object:Gem::Requirement
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- version: 0.9.26
114
- - - "<"
115
- - !ruby/object:Gem::Version
116
- version: '2'
117
- type: :development
118
- prerelease: false
119
- version_requirements: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - ">="
122
- - !ruby/object:Gem::Version
123
- version: 0.9.26
124
- - - "<"
125
- - !ruby/object:Gem::Version
126
- version: '2'
127
- - !ruby/object:Gem::Dependency
128
- name: rubocop
129
- requirement: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - ">="
132
- - !ruby/object:Gem::Version
133
- version: 1.15.0
134
- - - "<"
135
- - !ruby/object:Gem::Version
136
- version: 1.16.0
137
- type: :development
138
- prerelease: false
139
- version_requirements: !ruby/object:Gem::Requirement
140
- requirements:
141
- - - ">="
142
- - !ruby/object:Gem::Version
143
- version: 1.15.0
144
- - - "<"
145
- - !ruby/object:Gem::Version
146
- version: 1.16.0
147
- - !ruby/object:Gem::Dependency
148
- name: rubocop-rake
149
- requirement: !ruby/object:Gem::Requirement
150
- requirements:
151
- - - ">="
152
- - !ruby/object:Gem::Version
153
- version: 0.5.1
154
- - - "<"
155
- - !ruby/object:Gem::Version
156
- version: 0.6.0
157
- type: :development
158
- prerelease: false
159
- version_requirements: !ruby/object:Gem::Requirement
160
- requirements:
161
- - - ">="
162
- - !ruby/object:Gem::Version
163
- version: 0.5.1
164
- - - "<"
165
- - !ruby/object:Gem::Version
166
- version: 0.6.0
167
- - !ruby/object:Gem::Dependency
168
- name: rubocop-performance
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: 1.11.3
174
- - - "<"
175
- - !ruby/object:Gem::Version
176
- version: 1.12.0
177
- type: :development
178
- prerelease: false
179
- version_requirements: !ruby/object:Gem::Requirement
180
- requirements:
181
- - - ">="
182
- - !ruby/object:Gem::Version
183
- version: 1.11.3
184
- - - "<"
185
- - !ruby/object:Gem::Version
186
- version: 1.12.0
187
- - !ruby/object:Gem::Dependency
188
- name: rubocop-rubycw
189
- requirement: !ruby/object:Gem::Requirement
190
- requirements:
191
- - - ">="
192
- - !ruby/object:Gem::Version
193
- version: 0.1.6
194
- - - "<"
195
- - !ruby/object:Gem::Version
196
- version: 0.2.0
197
- type: :development
198
- prerelease: false
199
- version_requirements: !ruby/object:Gem::Requirement
200
- requirements:
201
- - - ">="
202
- - !ruby/object:Gem::Version
203
- version: 0.1.6
204
- - - "<"
205
- - !ruby/object:Gem::Version
206
- version: 0.2.0
207
- - !ruby/object:Gem::Dependency
208
- name: rubocop-md
209
- requirement: !ruby/object:Gem::Requirement
210
- requirements:
211
- - - ">="
212
- - !ruby/object:Gem::Version
213
- version: 1.0.1
214
- - - "<"
215
- - !ruby/object:Gem::Version
216
- version: 2.0.0
217
- type: :development
218
- prerelease: false
219
- version_requirements: !ruby/object:Gem::Requirement
220
- requirements:
221
- - - ">="
222
- - !ruby/object:Gem::Version
223
- version: 1.0.1
224
- - - "<"
225
- - !ruby/object:Gem::Version
226
- version: 2.0.0
227
- description: " [4.2, 42, 42.0, 420].grep(Eqq.AND(Integer, 20..50)) #=> [42]\n"
11
+ date: 2021-06-06 00:00:00.000000000 Z
12
+ dependencies: []
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!
228
21
  email:
229
22
  - kachick1+ruby@gmail.com
230
23
  executables: []
@@ -234,7 +27,9 @@ files:
234
27
  - MIT-LICENSE.txt
235
28
  - README.md
236
29
  - lib/eqq.rb
30
+ - lib/eqq/buildable.rb
237
31
  - lib/eqq/version.rb
32
+ - sig/eqq.rbs
238
33
  homepage: https://github.com/kachick/eqq
239
34
  licenses:
240
35
  - MIT
@@ -251,7 +46,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
251
46
  requirements:
252
47
  - - ">="
253
48
  - !ruby/object:Gem::Version
254
- version: 2.5.0
49
+ version: 2.6.0
255
50
  required_rubygems_version: !ruby/object:Gem::Requirement
256
51
  requirements:
257
52
  - - ">="
@@ -261,5 +56,5 @@ requirements: []
261
56
  rubygems_version: 3.2.15
262
57
  signing_key:
263
58
  specification_version: 4
264
- summary: Pattern objects builder. `eqq` means `#===`
59
+ summary: Pattern objects builder
265
60
  test_files: []