Module: QueryableArray::Queryable

Defined in:
lib/queryable_array/queryable.rb

Overview

Allows find_by and find_all to accept search hashes which are converted into Proc searches and passed as the block arguments for find and find_all respectively

Instance Method Summary collapse

Instance Method Details

#find_all(search = {}, &block) ⇒ Object

Returns a dup'd Queryable replaced with objects matching the search criteria. When a block is specified, it behaves exactly like Enumerable#find_all. Otherwise the search hash is converted into a finder proc and passed as the block argument to Enumerable#find_all.

users.find_all(age: 30)                  # => [#<User @age=30>, #<User @age=30>, ...]
users.find_all(name: 'missing')          # => []
users.find_all { |user| user.age < 30 }  # => [#<User @age=22>, #<User @age=26>, ...]

14
15
16
17
# File 'lib/queryable_array/queryable.rb', line 14

def find_all(search = {}, &block)
  block = finder search unless block_given?
  dup.replace super(&block)
end

#find_by(search = {}, &block) ⇒ Object

Behaves exactly like find_all but only returns the first match. If no match is found then nil is returned.

users.find_by(age: 25)          # => #<User @age=25>
users.find_by(name: 'missing')  # => nil

24
25
26
27
# File 'lib/queryable_array/queryable.rb', line 24

def find_by(search = {}, &block)
  block = finder search unless block_given?
  find(&block)
end

#finder(search) ⇒ Object

Accepts a search hash and returns a Proc which determines if all of an object's searched attributes match their expected values. It can be used as the block arguments for find, find_by and find_all.

Values are compared with expected values using == or ===. If the expected value is a Proc or anything that responds to call then it is evaluated with the value as an argument and checks for a response other than nil or false.

Searched attributes first check if the object responds to the attribute so NoMethodError is never thrown if an attribute doesn't exist.

query = finder(name: 'bob')    # => proc { |user| user.name == 'bob' } # pseudo code
query User.new(name: 'steve')  # => false
query User.new(name: 'bob')    # => true

users.find(&query)             # => #<User @name='bob'>

users.find &finder(missing: 'value')  # => nil

48
49
50
51
52
53
54
55
# File 'lib/queryable_array/queryable.rb', line 48

def finder(search)
  Proc.new do |object|
    search.all? do |attribute, expected|
      value = object.send attribute if object.respond_to?(attribute)
      expected == value || expected === value || (expected.respond_to?(:call) && expected.call(value))
    end
  end
end