<%= post.title -%>
<%= post.comments[[approved: true]].size -%> comments
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
= 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| -%>
<%- end -%>
== Testing
bundle exec rake