Module: Eqq::Buildable

Included in:
Eqq
Defined in:
lib/eqq/buildable.rb

Overview

Actually having definitions for the pattern builders

Constant Summary collapse

INSPECTION_FALLBACK =

When the inspection is failed some unexpected reasons, it will fallback to this value This value is not fixed as a spec, might be changed in future

'UninspectableObject'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.define_inspect_on(product, name:, arguments:) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.



31
32
33
34
35
36
# File 'lib/eqq/buildable.rb', line 31

def define_inspect_on(product, name:, arguments:)
  inspect = "#{name}(#{arguments.map { |argument| safe_inspect_for(argument) }.join(', ')})".freeze
  product.define_singleton_method(:inspect) do
    inspect
  end
end

.safe_inspect_for(object) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (String)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/eqq/buildable.rb', line 14

def safe_inspect_for(object)
  String.try_convert(object.inspect) || INSPECTION_FALLBACK
rescue Exception
  # This implementation used `RSpec::Support::ObjectFormatter::UninspectableObjectInspector` as a reference, thank you!
  # ref: https://github.com/kachick/times_kachick/issues/97
  singleton_class = class << object; self; end
  begin
    klass = singleton_class.ancestors.detect { |ancestor| !ancestor.equal?(singleton_class) }
    native_object_id = '%#016x' % (object.__id__ << 1)
    "#<#{klass}:#{native_object_id}>"
  rescue Exception
    INSPECTION_FALLBACK
  end
end

.validate_patterns(*patterns) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Raises:

  • (ArgumentError)


40
41
42
43
44
# File 'lib/eqq/buildable.rb', line 40

def validate_patterns(*patterns)
  invalids = patterns.reject { |pattern| Eqq.pattern?(pattern) }
  invalid_inspections = invalids.map { |invalid| safe_inspect_for(invalid) }.join(', ')
  raise ArgumentError, "given `#{invalid_inspections}` are invalid as pattern objects" unless invalids.empty?
end

Instance Method Details

#AND(pattern1, pattern2, *patterns) ⇒ Proc

Product returns ‘true` when matched all patterns

Parameters:

  • pattern1 (Proc, Method, #===)
  • pattern2 (Proc, Method, #===)
  • patterns (Array<Proc, Method, #===>)

Returns:

  • (Proc)


53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/eqq/buildable.rb', line 53

def AND(pattern1, pattern2, *patterns)
  patterns = [pattern1, pattern2, *patterns].freeze
  Buildable.validate_patterns(*patterns)

  product = ->v {
    patterns.all? { |pattern| pattern === v }
  }

  Buildable.define_inspect_on(product, name: 'AND', arguments: patterns)

  product
end

#ANYTHINGProc

Product returns ‘true`, always `true`

Returns:

  • (Proc)


265
266
267
# File 'lib/eqq/buildable.rb', line 265

def ANYTHING
  EQQ_BUILTIN_ANYTHING
end

#BOOLEANProc

Product returns ‘true` when matched to `true` or `false`

Returns:

  • (Proc)


285
286
287
# File 'lib/eqq/buildable.rb', line 285

def BOOLEAN
  EQQ_BUILTIN_BOOLEAN
end

#CAN(message1, *messages) ⇒ Proc

Product returns ‘true` when it has all of the methods (checked with `respond_to?`)

Parameters:

  • message1 (Symbol, String, #to_sym)
  • messages (Array<Symbol, String, #to_sym>)

Returns:

  • (Proc)


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/eqq/buildable.rb', line 160

def CAN(message1, *messages)
  messages = (
    begin
      [message1, *messages].map(&:to_sym).freeze
    rescue NoMethodError
      raise ArgumentError
    end
  )

  product = ->v {
    messages.all? { |message|
      begin
        v.respond_to?(message)
      rescue NoMethodError
        false
      end
    }
  }

  Buildable.define_inspect_on(product, name: 'CAN', arguments: messages)

  product
end

#EQ(obj) ⇒ Proc

Product returns ‘true` when matched with `#==`

Parameters:

  • obj (#==)

Returns:

  • (Proc)


139
140
141
142
143
# File 'lib/eqq/buildable.rb', line 139

def EQ(obj)
  product = ->v { obj == v }
  Buildable.define_inspect_on(product, name: 'EQ', arguments: [obj])
  product
end

#NAND(pattern1, pattern2, *patterns) ⇒ Proc

Product is an inverted #AND

Parameters:

  • pattern1 (Proc, Method, #===)
  • pattern2 (Proc, Method, #===)
  • patterns (Array<Proc, Method, #===>)

Returns:

  • (Proc)


72
73
74
# File 'lib/eqq/buildable.rb', line 72

def NAND(pattern1, pattern2, *patterns)
  NOT(AND(pattern1, pattern2, *patterns))
end

#NEVERProc

Product returns ‘false`, always `false`

Returns:

  • (Proc)


275
276
277
# File 'lib/eqq/buildable.rb', line 275

def NEVER
  EQQ_BUILTIN_NEVER
end

#NILProc

Product returns ‘true` when matched to `nil` (Not consider `nil?`)

Returns:

  • (Proc)


295
296
297
# File 'lib/eqq/buildable.rb', line 295

def NIL
  EQQ_BUILTIN_NIL
end

#NOR(pattern1, pattern2, *patterns) ⇒ Proc

Product is an inverted #OR

Parameters:

  • pattern1 (Proc, Method, #===)
  • pattern2 (Proc, Method, #===)
  • patterns (Array<Proc, Method, #===>)

Returns:

  • (Proc)


100
101
102
# File 'lib/eqq/buildable.rb', line 100

def NOR(pattern1, pattern2, *patterns)
  NOT(OR(pattern1, pattern2, *patterns))
end

#NOT(pattern) ⇒ Proc

Product returns ‘true` when not matched the pattern

Parameters:

  • pattern (Proc, Method, #===)

Returns:

  • (Proc)


125
126
127
128
129
130
131
132
133
# File 'lib/eqq/buildable.rb', line 125

def NOT(pattern)
  Buildable.validate_patterns(pattern)

  product = ->v { !(pattern === v) }

  Buildable.define_inspect_on(product, name: 'NOT', arguments: [pattern])

  product
end

#OR(pattern1, pattern2, *patterns) ⇒ Proc

Product returns ‘true` when matched even one pattern

Parameters:

  • pattern1 (Proc, Method, #===)
  • pattern2 (Proc, Method, #===)
  • patterns (Array<Proc, Method, #===>)

Returns:

  • (Proc)


82
83
84
85
86
87
88
89
90
91
92
# File 'lib/eqq/buildable.rb', line 82

def OR(pattern1, pattern2, *patterns)
  patterns = [pattern1, pattern2, *patterns].freeze
  Buildable.validate_patterns(*patterns)

  product = ->v {
    patterns.any? { |pattern| pattern === v }
  }
  Buildable.define_inspect_on(product, name: 'OR', arguments: patterns)

  product
end

#QUIET(pattern1, *patterns) ⇒ Proc

Product returns ‘true` when all patterns did not raise any exception

Parameters:

  • pattern1 (Proc, Method, #===)
  • patterns (Array<Proc, Method, #===>)

Returns:

  • (Proc)


189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/eqq/buildable.rb', line 189

def QUIET(pattern1, *patterns)
  patterns = [pattern1, *patterns].freeze
  Buildable.validate_patterns(*patterns)

  product = ->v {
    patterns.all? { |pattern|
      begin
        pattern === v
      rescue Exception
        false
      else
        true
      end
    }
  }

  Buildable.define_inspect_on(product, name: 'QUIET', arguments: patterns)

  product
end

#RESCUE(mod, pattern) ⇒ Proc

Product returns ‘true` when the pattern raises the exception

Parameters:

  • mod (Module)
  • pattern (Proc, Method, #===)

Returns:

  • (Proc)

Raises:

  • (ArgumentError)


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/eqq/buildable.rb', line 215

def RESCUE(mod, pattern)
  Buildable.validate_patterns(pattern)
  raise ArgumentError unless Module === mod

  product = ->v {
    begin
      pattern === v
      false
    rescue mod
      true
    rescue Exception
      false
    end
  }

  Buildable.define_inspect_on(product, name: 'RESCUE', arguments: [mod, pattern])

  product
end

#SAME(obj) ⇒ Proc

Product returns ‘true` when matched with `#equal?`

Parameters:

  • obj (#equal?)

Returns:

  • (Proc)


149
150
151
152
153
# File 'lib/eqq/buildable.rb', line 149

def SAME(obj)
  product = ->v { obj.equal?(v) }
  Buildable.define_inspect_on(product, name: 'SAME', arguments: [obj])
  product
end

#SEND(name, pattern) ⇒ Proc

Basically provided for Enumerable

Parameters:

  • name (Symbol, String, #to_sym)
  • pattern (Proc, Method, #===)

Returns:

  • (Proc)


240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/eqq/buildable.rb', line 240

def SEND(name, pattern)
  name = (
    begin
      name.to_sym
    rescue NoMethodError
      raise ArgumentError
    end
  )
  Buildable.validate_patterns(pattern)

  product = ->v {
    v.__send__(name, pattern)
  }

  Buildable.define_inspect_on(product, name: 'SEND', arguments: [name, pattern])

  product
end

#XOR(pattern1, pattern2) ⇒ Proc

Product returns ‘true` when matched one of the pattern, when matched both returns `false`

Parameters:

  • pattern1 (Proc, Method, #===)
  • pattern2 (Proc, Method, #===)

Returns:

  • (Proc)


109
110
111
112
113
114
115
116
117
118
119
# File 'lib/eqq/buildable.rb', line 109

def XOR(pattern1, pattern2)
  patterns = [pattern1, pattern2].freeze
  Buildable.validate_patterns(*patterns)

  product = ->v {
    patterns.one? { |pattern| pattern === v }
  }
  Buildable.define_inspect_on(product, name: 'XOR', arguments: patterns)

  product
end