eqq
-
This repository is archived
-
No longer maintained
-
Registered gem remains for now
Pattern objects builder
Usage
Require Ruby 3.2 or higher
Add below code into your Gemfile
gem 'eqq', '~> 0.1.1'
Overview
require 'eqq'
[4.2, 42, 42.0, 420].grep(Eqq.AND(Integer, 20..50)) #=> [42]
[42, nil, true, false, '', 0].grep(Eqq.BOOLEAN) #=> [true, false]
[42, [], {}, 'string', Object.new, nil].grep(Eqq.CAN(:to_h)) #=> [[], {}, nil]
pattern = Eqq.build do
OR(AND(Float, 20..50), Integer)
end
p pattern #=> "OR(AND(Float, 20..50), Integer)"
[4.2, 42, 42.0, 420].grep(pattern) #=> [42, 42.0, 420]
inverted = Eqq.NOT(pattern)
p inverted #=> "NOT(OR(AND(Float, 20..50), Integer))"
[4.2, 42, 42.0, 420].grep(inverted) #=> [4.2]
Eqq.SEND(:all?, pattern) === [4.2, 42, 42.0, 420] #=> false
Eqq.SEND(:any?, pattern) === [4.2, 42, 42.0, 420] #=> true
ret_in_case = (
case 42
when pattern
'Should be matched here! :)'
when inverted
'Should not be matched here! :<'
else
'Should not be matched here too! :<'
end
)
p ret_in_case #=> Should be matched here! :)
ret_in_case = (
case 4.2
when pattern
'Should not be matched here! :<'
when inverted
'Should be matched here! :)'
else
'Should not be matched here too! :<'
end
)
p ret_in_case #=> Should be matched here! :)
class MyClass
include Eqq::Buildable
def example
[4.2, 42, 42.0, 420].grep(OR(AND(Float, 20..50), Integer))
end
end
MyClass.new.example #=> [42, 42.0, 420]
Explanation
All products can be called as pattern === other
.
This signature will fit in most Ruby code.
-
case ~ when
syntax -
Enumerable#grep
-
Enumerable#grep_v
-
Enumerable#all?
-
Enumerable#any?
-
Enumerable#none?
-
Enumerable#one?
-
Enumerable#slice_after
-
Enumerable#slice_before
They can take this interface as the pattern
.
And you already saw. All of patterns can be mixed with other patterns as a parts. Reuse as you wish!
Builders
-
OR(*patterns) - Product returns
true
when matched even one pattern -
AND(*patterns) - Product returns
true
when matched all patterns -
NOT(pattern) - Product returns
true
when not matched the pattern -
CAN(*method_names) - Product returns
true
when it has all of the methods (checked withrespond_to?
) -
RESCUE(exception_class/module, pattern) - Product returns
true
when the pattern raises the exception -
QUIET(*patterns) - Product returns
true
when all patterns did not raise any exception -
EQ(object) - Product returns
true
when matched with#==
-
SAME(object) - Product returns
true
when matched with#equal?
-
SEND(name, pattern) - Basically provided for Enumerable
-
BOOLEAN() - Product returns
true
when matched totrue
orfalse
-
NIL() - Product returns
true
when matched tonil
(Not considernil?
) -
ANYTHING() - Product returns
true
, alwaystrue
-
NEVER() - Product returns
false
, alwaysfalse
-
XOR(pattern1, pattern2) - Product returns
true
when matched one of the pattern, when matched both returnsfalse
-
NAND(*patterns) - Product is an inverted
AND
-
NOR(*patterns) - Product is an inverted
OR
Best fit for RSpec’s satisfy
matcher too
All builders actually generate a Proc (lambda)
instance. The signature will fit for RSpec’s built-in “satisfy” matcher too.
RSpec.describe RSpec::Matchers::BuiltIn::Satisfy do
let(:product) { Eqq.AND(Integer, 24..42) }
it 'perfectly works' do
expect(23).not_to satisfy(&product)
expect(24).to satisfy(&product)
expect(24.0).not_to satisfy(&product)
expect(42).to satisfy(&product)
expect(42.0).not_to satisfy(&product)
expect(43).not_to satisfy(&product)
end
end
Use builders without receiver specifying
When you felt annoy to write Eqq
in many place, some ways exist.
-
Eqq.build(&block)
- In the block scope, all builder methods can be used without receiver -
extend Eqq::Buildable
- In the class/module, all builders can be used as class methods -
include Eqq::Buildable
- In the class/module, all builders can be used as instance methods