An open API service indexing awesome lists of open source software.

https://github.com/shuber/queryable_array

Provides a simplified DSL allowing arrays of objects to be searched by their attributes
https://github.com/shuber/queryable_array

Last synced: about 1 year ago
JSON representation

Provides a simplified DSL allowing arrays of objects to be searched by their attributes

Awesome Lists containing this project

README

          

= queryable_array - {}[http://travis-ci.org/shuber/queryable_array] {}[https://codeclimate.com/github/shuber/queryable_array] {}[https://codeclimate.com/github/shuber/queryable_array]

A +QueryableArray+ inherits from +Array+ and is intended to store a group of
objects which share the same attributes allowing them to be searched. It
overrides [], +find_all+ and +method_missing+ to provide a simplified DSL
for looking up objects by querying their attributes.

View the full documentation over at rubydoc.info[http://rubydoc.info/github/shuber/queryable_array/frames].

== Installation

gem install queryable_array

== Requirements

Ruby 1.9+

== Usage

=== Basic

Initialize the +QueryableArray+ with a collection of objects e.g. +Page+ objects from a JSON response or database query (although you should probably restrict database queries with WHERE conditions instead if you have the opportunity)

pages = QueryableArray.new Page.all

The +pages+ object can then be queried by passing a search hash to the [] method

pages[uri: '/'] # => #
pages[name: 'About'] # => #
pages[uri: '/', name: 'Home'] # => #
pages[uri: '/', name: 'Mismatch'] # => nil

Notice that it only returns the first matching object or +nil+ if one is not found. If you'd like to find
all matching objects, simply wrap your search hash in an array

pages[[published: true]] # => [#, #, ...]
pages[[uri: '/missing']] # => []

Attributes may also be searched by regular expressions

pages[name: /home/i] # => #
pages[[uri: /users/]] # => [#, #, ...]

The methods +find_by+ and +find_all+ behave as aliases for [search_hash] and [[search_hash]] respectively

pages.find_by(name: 'Home') # => #
pages.find_by(name: 'Missing') # => nil
pages.find_all(uri: /users/) # => [#, #, ...]

The existing block form for those methods work as well

pages.find_all { |page| page.uri =~ /users/ } # => [#, #, ...]

A +Proc+ object may be passed to [] as well

pages[uri: proc { |uri| uri.split('/').size > 1 }] # => #
pages[proc { |page| page.uri == '/' }] # => #

Lookups by index or ranges still behave exactly as they do in regular +Array+ objects

pages[0] # => #
pages[-1] # => #
pages[99] # => nil
pages[0..1] # => [#, #]

=== Default finders

A +QueryableArray+ object can be initialized with a +default_finder+ to make lookups even simpler

pages = QueryableArray.new Page.all, :uri

Now the +pages+ object can be searched easily by +uri+

pages['/'] # => #
pages['/about'] # => #
pages['/missing'] # => nil

You can even specify multiple +default_finders+

pages = QueryableArray.new Page.all, [:uri, :name]

pages['/about'] # => #
pages['About'] # => #
pages[/home/i] # => #

Wrapping your search inside an array still returns all matches

pages[[/users/]] # => [#, #, ...]

=== Dynamic attribute-based finders

QueryableArray#method_missing allows you to lookup objects using a notation like the +ActiveRecord+ dynamic finders

pages.find_by_uri('/') # => #
pages.find_by_uri_and_name('/', 'Home') # => #
pages.find_by_uri('/missing') # => nil

pages.find_all_by_uri('/') # => [#]
pages.find_all_by_uri(/users/) # => [#, #, ...]

=== Dot notation finders

If any +default_finders+ are defined you may even use dot notation to lookup objects by those attributes

pages = QueryableArray.new Page.all, :name

pages.sitemap # => #
pages.missing # => NoMethodError
QueryableArray.new.missing # => NoMethodError

Calling pages.sitemap behaves the same as pages[/sitemap/i]

To perform a case-sensitive search, simply append a ! to the end of your method call
e.g. pages.sitemap! which calls pages['sitemap']

You may also query to see if a match exists by appending a ? to your search

pages.sitemap? # => true
pages.missing? # => false

=== Composable

Functionality for +QueryableArray+ has been separated out into individual modules
containing their own features which allows you to create your own objects and only
include the features you care about

* QueryableArray::DefaultFinder - Allows objects to be searched by +default_finders+ thru []
* QueryableArray::DotNotation - Allows objects to be searched using dot notation thru +method_missing+ which behaves like an alias to QueryableArray::DefaultFinder#[]
* QueryableArray::DynamicFinder - Allows objects to be searched by dynamic finders thru +method_missing+ similar to the ActiveRecord dynamic attribute-based finders e.g. +find_by_email+ or +find_all_by_last_name+
* QueryableArray::Queryable - 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
* QueryableArray::Shorthand - Makes [search_hash] and [[search_hash]] behave as an alias for +find_by+ and +find_all+ respectively

Try making your own classes with them

class Collection < Array
include QueryableArray::Queryable
end

pages = Collection.new Page.all
pages.find_all(published: true) # => [#, #]

=== Real world example

Try using it inside of your templates:


<%- posts[[published: true]].each do |post| -%>

<%= post.title -%>


<%= post.excerpt -%>

<%= post.comments[[approved: true]].size -%> comments

<%- end -%>

== Testing

bundle exec rake