- This repository is archived
- No longer maintained
- Registered gem remains for now
Pattern objects builder
Require Ruby 3.2 or higher
Add below code into your Gemfile
gem 'eqq', '~> 0.1.1'
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]
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!
- 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
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
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 receiverextend Eqq::Buildable
- In the class/module, all builders can be used as class methodsinclude Eqq::Buildable
- In the class/module, all builders can be used as instance methods