红宝石(无有效记录)
def where(options)
end
选项可以是键,值对或诸如>,<,> =,<=
之类的比较如果我有一系列记录...
record = Struct.new(:name, :address, :amount)
如何测试哪些内容并对其进行过滤?
例如,如果我这样做:
.where(:amount > 5)
vs
.where(name: 'John')
甚至
.where(name: 'John', :amount>5)
我希望它退回符合要求的物品。
array_of_records.select { |record| record.name == 'John' }
array_of_records.select { |record| record.amount > 5 }
我当时以为我需要这样的东西,但不确定从哪里开始。
option_type(option)
case option
when keyvalue?(option)
when gtr_then?(option)
when gtr_then_eql?(option)
when less_then?(option)
when less_then_eql?(option)
end
end
keyvalue?(mykey: 5)
# Code detects key value pair
# Return true
end
gtr_then?(mykey > 5)
# Code detects > operator
# Return True
end
less_then?(mykey < 5)
# Code detects < operator
# Return true
end
less_then_eql?(mykey <= 5)
# Code detects <= operator
# return true
end
gtr_then_eql?(mykey >= 5)
# Code detects >= operator
# return true
end
答案 0 :(得分:2)
嗯,甚至ActiveRecord都使用字符串表示形式来表示这样的选项:
.where('amount > 5')
AR这样做可能会更容易,因为它可以直接传递到数据库。在这种情况下,您必须解析字符串,找到运算符和操作数,然后执行操作。
但是还有一种选择(也受AR支持)来使用范围。在Ruby 2.6中具有无限范围是很容易的:
.where(amount: 5..)
而在以前的版本中,您可以使用.where(amount: 5..Float::INFINITY)
然后,您只需要检查参数是否为范围,是否覆盖值(请确保使用cover?
而不是include?
,因为您不想遍历无限数组)
答案 1 :(得分:2)
混合@ Richard-Degenne的评论和Maxim的答案,您可以编写如下内容。
为Symbol
定义:>,:<,...可能不是一个好主意,因此您可能要使用Refinements。使用后果自负!
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