Смешав @ комментарий Ричарда-Дегенна и ответ Максима, вы могли бы написать что-то вроде этого.
Вероятно, не очень хорошая идея определить:>,: <, ... для <code>Symbol, чтобы вы моглихочу использовать уточнения .Используйте на свой страх и риск!
class Record
attr_reader :name, :address, :amount
def initialize(name, address, amount)
@name = name
@address = address
@amount = amount
end
def to_s
[name, address, amount].join(' ')
end
def inspect
to_s
end
end
module Enumerable
def where(query)
select do |record|
case query
when Hash
query.all? do |key, pattern|
pattern === record.send(key)
end
when WhereComparator
query.match? record
end
end
end
end
class WhereComparator
def initialize(sym, operator, other)
@sym = sym
@operator = operator
@other = other
end
def match?(record)
record.send(@sym).send(@operator, @other)
end
end
module MyWhereSyntax
refine Symbol do
[:<, :<=, :==, :>=, :>].each do |operator|
define_method operator do |other|
WhereComparator.new(self, operator, other)
end
end
end
end
using MyWhereSyntax
records = [
Record.new('John', 'a', 7),
Record.new('Jack', 'b', 12),
Record.new('Alice', 'c', 19),
Record.new('John', 'd', 2),
]
p records.where(name: 'John')
#=> [John a 7, John d 2]
p records.where(name: 'John', amount: 2)
#=> [John d 2]
p records.where(name: 'John').where(:amount > 5)
#=> [John a 7]
p records.where(name: 'John').where(:amount > 7)
#=> []
p records.where(:amount > 8).where(:address <= 'c')
#=> [Jack b 12, Alice c 19]
p records.where(name: /^J...$/)
#=> [John a 7, Jack b 12, John d 2]
В качестве бонуса вы можете написать:
long_enough = :size > 7
# => #<WhereComparator:0x00000000017072f8 @operator=:>, @other=7, @sym=:size>
long_enough.match? 'abcdefgh'
# => true
long_enough.match? 'abc':
# => false