Project

eqq

0.0
No release in over a year
Pattern objects builder. All products can be used as `pattern === something`. All products can be mixed with other products as a parts. Reuse as you wish!
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

eqq

Build Status Gem Version

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 with respond_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 to true or false
  • NIL() - Product returns true when matched to nil (Not consider nil?)
  • ANYTHING() - Product returns true, always true
  • NEVER() - Product returns false, always false
  • XOR(pattern1, pattern2) - Product returns true when matched one of the pattern, when matched both returns false
  • 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

Links

NOTE