easy_search 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2766cdc5f1074ec9e13036fb2c2fede256a7a23f
4
+ data.tar.gz: 1d00907cd274a6edf63fc6eac697bcc6b9b6d701
5
+ SHA512:
6
+ metadata.gz: 1ce0fa34e0dcd8377e7c9b91cfab9ff444cc33b42b6b66f7d5ced39be59933141bcecc6743acc90873aa5e145e15e793a85d24ab4f2623521ffd271ac7a0d7d5
7
+ data.tar.gz: c40f743b06954e8e84bd41cde5ea1ef25fea83a3e65e4a7dec541969d0bd8f2ecfabdf330de42909fab1885fce07529de81a151aa56af9436326eb70effcd89c
@@ -0,0 +1,5 @@
1
+ coverage
2
+ rdoc*
3
+ rdoc/*
4
+ .DS_Store
5
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in easy_search.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Ryan Heath
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,124 @@
1
+ h1. EasySearch
2
+
3
+ Easy search provides a convenient DSL for quickly searching your @ActiveRecord@ models.
4
+
5
+ h2. What It's NOT
6
+
7
+ Firstly, let's just get this out of the way. EasySearch is _not_ intended for search-intensive or high-performance applications. There are plenty of other (awesome) full-text plugins for that (e.g. acts_as_ferret, sphinx/ultrasphinx, etc). It's just an easy, quick-n-dirty search for your @ActiveRecord@ models. So if you're looking for a search solution to hunt through your 10 million record database, please, leave now while you still can.
8
+
9
+ h2. So, Why Build it?
10
+
11
+ Honestly? Because building a DSL interface to a simple thing is fun. It's actually a lot of fun. Also, I think it's a reasonable place to start for creating something bigger. Overall, this plugin is more-or-less the result of me toying around with the dynamism of Ruby :-)
12
+
13
+ h2. Installation
14
+
15
+ You can install this as a Rails plugin. Navigate to your project root and type:
16
+
17
+ <pre><code>git clone git://github.com/rpheath/easy_search.git vendor/plugins/easy_search</code></pre>
18
+
19
+ Use it at your own risk. You've been warned.
20
+
21
+ h2. General Use Case
22
+
23
+ Again, please don't attempt to use this if you'll be searching giant databases, as I'd imagine you would need something performance aware, which this is _not_. But. It should work fine for hundreds, thousands, maybe even tens-of-thousands of records. You know, like blogs, small forums, etc.
24
+
25
+ h3. Configuration
26
+
27
+ In config/initializers/easy_search_setup.rb (or config/environment.rb if you aren't running Rails 2.0+), you'd do something like this:
28
+
29
+ <pre><code>
30
+ EasySearch::Setup.config do
31
+ setup_tables do
32
+ users :first_name, :last_name, :email, :login
33
+ projects :title, :description
34
+ comments :name, :body
35
+ groups :name, :description
36
+ end
37
+ end
38
+ </code></pre>
39
+
40
+ The @setup_tables@ method allows you to specify which columns should be searched for each one of your tables. It's required if you want to use @EasySearch@ with one of your models. Otherwise, @EasySearch@ wouldn't have a clue what to do with your keywords.
41
+
42
+ And of course, should you try to search a model that has not been configured, @EasySearch@ will let you know :-)
43
+
44
+ h2. Examples
45
+
46
+ We'll go straight into it. First thing, you install the plugin. Then you add a generic class and give it the @EasySearch@ functionality. Like so:
47
+
48
+ <pre><code>
49
+ # app/models/search.rb
50
+ class Search
51
+ include EasySearch
52
+ end
53
+ </pre></code>
54
+
55
+ Now we have a @Search@ class that can easily handle search your @ActiveRecord@ models! Notice how this class _does not_ descend from @ActiveRecord@.
56
+
57
+ h3. Usage
58
+
59
+ In words, let's say we want to "search the users table with 'ryan heath'". To represent that in code, it's basically the same thing:
60
+
61
+ <pre><code>
62
+ $> Search.users.with('ryan heath')
63
+ $> => [<#User ...>]
64
+
65
+ $> Search.projects.with('webdesign')
66
+ $> => [<#Project ...>, <#Project ...>, ...]
67
+ </code></pre>
68
+
69
+ Note: the above will not compare 'ryan heath' with each of the configured columns, but it will compare 'ryan' and 'heath' separately against each of those columns for better results. Another thing worthy of mention about keyword splitting: it's slightly more sophisticated, in that it will strip out the dull keywords that would return innaccurate results, which also helps performance. For instance:
70
+
71
+ You can also search by an exact phrase. Let's say you wanted to support a search for '"ryan heath"', where you didn't want EasySearch to search "ryan" and "heath" separately. Well, all you have to do is tell your users to wrap their search terms in quotes (just like Google) and EasySearch will know to search that phrase, in that order, without splitting up the words.
72
+
73
+ <pre><code>Search.users.with('ryan and a term')</code></pre>
74
+
75
+ That would only search 'ryan' and 'term' against your columns. @EasySearch@ tries to be somewhat smart about what it searches. And in fact, you can see what @EasySearch@ considers "dull keywords" by doing:
76
+
77
+ <pre><code>
78
+ # default dull keywords (this is just an example)
79
+ $> EasySearch::Setup.dull_keywords
80
+ $> => ['a', 'and', 'the']
81
+ </code></pre>
82
+
83
+ The list is _far from complete_. So if you have words that you'd like to add to the "dull keywords" list (meaning words that would not be searched), you can do so quite easily. Going back to the @Setup.config@ block:
84
+
85
+ <pre><code>
86
+ EasySearch::Setup.config do
87
+ strip_keywords do
88
+ ['what', 'then', 'if', 'is', 'it']
89
+ end
90
+ end
91
+
92
+ # dull_keywords is now a sum of the defaults plus your custom keywords
93
+ $> EasySearch::Setup.dull_keywords
94
+ $> => ['a', 'and', 'the', 'what', 'then', 'if', 'is', 'it']
95
+ </code></pre>
96
+
97
+ Those keywords are appended to the existing list (all duplicates are removed). And if you'd rather your custom list replace the existing defaults entirely, just pass 'true' to the @strip_keywords@ method, like so:
98
+
99
+ <pre><code>
100
+ EasySearch::Setup.config do
101
+ strip_keywords(true) do
102
+ ['what', 'then', 'if', 'is', 'it']
103
+ end
104
+ end
105
+
106
+ # dull_keywords is now only your custom keywords
107
+ $> EasySearch::Setup.dull_keywords
108
+ $> => ['what', 'then', 'if', 'is', 'it']
109
+ </code></pre>
110
+
111
+ And finally, if you have additional conditions that you need to apply to all search results, just use a :conditions option on the @with@ method, like so:
112
+
113
+ <pre><code>
114
+ $> Search.users.with('ryan heath', :conditions => 'active => 1')
115
+ $> # active users matching 'ryan' and/or 'heath'
116
+ </code></pre>
117
+
118
+ Pretty easy, huh?
119
+
120
+ Again, this plugin is not meant for searching high-volume Databases. It doesn't handle indexing or any of the other things a full-text solution might handle. But it was a fun plugin to write, and it's a fun API/DSL to use, and that's why I wrote it.
121
+
122
+ h2. License
123
+
124
+ Copyright (c) 2008 Ryan Heath, released under the MIT license
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "easy_search"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'easy_search/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "easy_search"
8
+ spec.version = EasySearch::VERSION
9
+ spec.authors = ["Ryan Heath"]
10
+ spec.email = ["ryan@rpheath.com"]
11
+
12
+ spec.summary = %q{A small DSL for simple searches.}
13
+ spec.description = %q{A small Ruby library that provides a DSL for simple LIKE searches.}
14
+ spec.homepage = "http://www.github.com/rpheath/easy_search"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "minitest"
25
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'easy_search/core')
@@ -0,0 +1,15 @@
1
+ module EasySearch
2
+ require 'ostruct'
3
+
4
+ # holds any regexp constants when dealing with search terms
5
+ Regex = OpenStruct.new(
6
+ :email => /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/
7
+ )
8
+
9
+ Defaults = OpenStruct.new(
10
+ # these keywords will be removed from any search terms, as they
11
+ # provide no value and just increase the size of the query.
12
+ # (the idea is a small attempt to be as efficient as possible)
13
+ :dull_keywords => ['a', 'the', 'and', 'or', 'what', 'then', 'if', 'is', 'it']
14
+ )
15
+ end
@@ -0,0 +1,134 @@
1
+ %w(constants errors setup validations version).each do |f|
2
+ require File.join(File.dirname(__FILE__), f)
3
+ end
4
+
5
+ module EasySearch
6
+ def self.included(base)
7
+ base.send(:extend, ClassMethods)
8
+ base.send(:include, InstanceMethods)
9
+
10
+ # before continuing, validate that the models identified (if any) in the
11
+ # setup_tables block (within `Setup.config') exist and are valid ActiveRecord descendants
12
+ Validations.validate_settings!
13
+ end
14
+
15
+ module ClassMethods
16
+ # "Search.users" translates to "User.find" dynamically
17
+ def method_missing(name, *args)
18
+ # instantiate a new instance of self with
19
+ # the @klass set to the missing method
20
+ self.new(name.to_sym)
21
+ end
22
+ end
23
+
24
+ module InstanceMethods
25
+ def initialize(klass)
26
+ @klass = klass
27
+
28
+ # validate that the class derived from the missing method descends from
29
+ # ActiveRecord and has been "configured" in `Setup.config { setup_tables {...} }'
30
+ # (i.e. "Search.userz.with(...)" where "userz" is an invalid model)
31
+ Validations.validate_class!(@klass)
32
+ end
33
+
34
+ # used to collect/parse the keywords that are to be searched, and return
35
+ # the search results (hands off to the Rails finder)
36
+ #
37
+ # Example:
38
+ # Search.users.with("ryan heath")
39
+ # # => <#User ... > or []
40
+ def with(keywords, options={})
41
+ search_terms = keywords.match(/"(.+)"/) ? extract($1, :exact => true) : extract(keywords)
42
+ return [] if search_terms.blank?
43
+
44
+ klass = to_model(@klass)
45
+
46
+ conditions = "(#{build_conditions_for(search_terms)})"
47
+ conditions << " AND (#{options[:conditions]})" unless options[:conditions].blank?
48
+ sanitized_sql_conditions = klass.send(:sanitize_sql_for_conditions, conditions)
49
+
50
+ options = { :select => 'DISTINCT *', :conditions => sanitized_sql_conditions, :order => options[:order], :limit => options[:limit] }
51
+ options.update :include => associations_to_include
52
+ klass.find(:all, options)
53
+ end
54
+
55
+ private
56
+ # constructs the conditions for the WHERE clause in the SQL statement.
57
+ # (compares each search term against each configured column for that model)
58
+ #
59
+ # ultimately this allows for a single query rather than several small ones,
60
+ # alleviating the need to open/close DB connections and instantiate multiple
61
+ # ActiveRecord objects through the loop
62
+ #
63
+ # it should be noted that a search with too many keywords against too many columns
64
+ # in a DB with too many rows will inevitably hurt performance (use ultrasphinx!)
65
+ def build_conditions_for(terms)
66
+ klass = to_model(@klass)
67
+
68
+ [].tap do |clause|
69
+ Setup.table_settings[@klass].each do |column|
70
+ # handle search associated objects
71
+ if Hash === column
72
+ column.each do |association, columns|
73
+ reflection = klass.reflect_on_association(association.to_sym)
74
+ next unless reflection
75
+ model = reflection.class_name.constantize
76
+ columns.each do |associated_column|
77
+ clause << build_conditions_for_terms_on_model(model, associated_column, terms)
78
+ end
79
+ end
80
+ else
81
+ clause << build_conditions_for_terms_on_model(klass, column, terms)
82
+ end
83
+ end
84
+ end.flatten.join(" OR ")
85
+ end
86
+
87
+ def build_conditions_for_terms_on_model(klass, column, terms)
88
+ terms.inject([]) do |clause, term|
89
+ if klass.columns.map(&:name).include?(column.to_s)
90
+ clause << "`#{klass.table_name}`.`#{column}` LIKE '%#{term}%'"
91
+ end
92
+ end
93
+ end
94
+
95
+ def associations_to_include
96
+ Setup.table_settings[@klass].collect do |e|
97
+ Hash === e ? e.keys : nil
98
+ end.compact || []
99
+ end
100
+
101
+ # using scan(/\w+/) to parse the words
102
+ #
103
+ # emails were being separated (split on the "@" symbol since it's not a word)
104
+ # so "rheath@test.com" became ["rheath", "test.com"] as search terms, when we
105
+ # really want to keep emails intact. as a work around, the emails are pulled out before
106
+ # the words are scanned, then each email is pushed back into the array as its own criteria.
107
+ #
108
+ # TODO: refactor this method to be less complex for such a simple problem.
109
+ def extract(terms, options={})
110
+ return [terms] if options.delete(:exact)
111
+
112
+ terms.gsub!("'", "")
113
+ emails = strip_emails_from(terms)
114
+
115
+ keywords = unless emails.blank?
116
+ emails.inject(terms.gsub(Regex.email, '').scan(/\w+/)) { |t, email| t << email }
117
+ else
118
+ terms.scan(/\w+/)
119
+ end
120
+
121
+ return (keywords.collect { |k| k.downcase } - Setup.dull_keywords.collect { |k| k.downcase })
122
+ end
123
+
124
+ # extracts the emails from the keywords
125
+ def strip_emails_from(text)
126
+ text.split.reject { |t| t.match(Regex.email) == nil }
127
+ end
128
+
129
+ # converts the symbol representation of a table to an actual ActiveRecord model
130
+ def to_model(klass)
131
+ klass.to_s.singularize.classify.constantize
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,25 @@
1
+ module EasySearch
2
+ class Error < RuntimeError
3
+ def self.message(msg=nil); msg.nil? ? @message : self.message = msg; end
4
+ def self.message=(msg); @message = msg; end
5
+ end
6
+
7
+ # raised when a model is attempted to be configured, but doesn't exist
8
+ class NoModelError < Error
9
+ message "you've specified a model that doesn't exist"; end
10
+
11
+ # raised when any model (consant) is derived from the `Setup.config' block
12
+ # and is not a subclass of ActiveRecord::Base
13
+ class InvalidActiveRecordModel < Error
14
+ message "all models specified in `Setup.config' must descend from ActiveRecord"; end
15
+
16
+ # raised when a model has not been configured, but is attempted to be searched
17
+ # (each model used with EasySearch has to be configured, meaning, the columns
18
+ # to be searched for that model must be set)
19
+ class InvalidSettings < Error
20
+ message "you must specify all Models and the fields to search for each Model in the `Setup.config' block"; end
21
+
22
+ # raised when block passed to `Setup.strip_keywords' does not evaluate as an instance of Array
23
+ class InvalidDullKeywordsType < Error
24
+ message "specified keywords must be of type Array in the `Setup.strip_keywords' block"; end
25
+ end
@@ -0,0 +1,87 @@
1
+ module EasySearch
2
+ class Setup
3
+ class << self
4
+ # returns a hash with the keys as the models to be searched
5
+ # and the values as arrays of columns for the respective model
6
+ #
7
+ # Example:
8
+ # $> Setup.settings
9
+ # $> => {"users"=>[:first_name, :last_name, :email], "projects"=>[:title, :description]}
10
+ def table_settings
11
+ @@table_settings ||= HashWithIndifferentAccess.new
12
+ end
13
+
14
+ # returns an array of keywords that serve as no benefit in a search
15
+ #
16
+ # Example:
17
+ # $> Setup.dull_keywords
18
+ # $> => ['a', 'and', 'but', 'the', ...]
19
+ def dull_keywords
20
+ (@@dull_keywords ||= Defaults.dull_keywords).flatten.uniq
21
+ end
22
+
23
+ # accepts a block that specifies the columns
24
+ # to search for each model
25
+ #
26
+ # Example:
27
+ # Setup.config do
28
+ # setup_tables { ... }
29
+ # strip_keywords { ... }
30
+ # end
31
+ def config(&block)
32
+ return nil unless block_given?
33
+ self.class_eval(&block)
34
+ end
35
+
36
+ # REQUIRED
37
+ # accepts a block that specifies the columns
38
+ # to search for each model
39
+ #
40
+ # Example:
41
+ # setup_tables do
42
+ # users :first_name, :last_name, :email
43
+ # projects :title, :description
44
+ # end
45
+ def setup_tables(&block)
46
+ return nil unless block_given?
47
+ self.class_eval(&block)
48
+ self.table_settings
49
+ end
50
+
51
+ # OPTIONAL
52
+ # allows customization of the dull_keywords setting
53
+ # (can be overwritten or appended)
54
+ #
55
+ # Example:
56
+ # DEFAULT_DULL_KEYWORDS = ['the', 'and', 'is']
57
+ #
58
+ # 1) appending keywords to the default list
59
+ # strip_keywords do
60
+ # ['it', 'why', 'is']
61
+ # end
62
+ # # => ['the', 'and', 'it', 'why', 'is']
63
+ #
64
+ # 2) overwriting existing keywords
65
+ # strip_keywords(true) do
66
+ # ['something', 'whatever']
67
+ # end
68
+ # # => ['something', 'whatever']
69
+ def strip_keywords(overwrite=false, &block)
70
+ return nil unless block_given?
71
+ raise(InvalidDullKeywordsType, InvalidDullKeywordsType.message) unless block.call.is_a?(Array)
72
+
73
+ overwrite ? @@dull_keywords = block.call : @@dull_keywords = (self.dull_keywords << block.call)
74
+ self.dull_keywords
75
+ end
76
+
77
+ # this is the magic that makes `setup_tables' work like it does.
78
+ # once the block is eval'd those missing methods (i.e. "users" and "projects")
79
+ # will be caught here and the table_settings hash will be updated with the
80
+ # key set to the table, and the value set to the columns. this is what allows the
81
+ # EasySearch plugin to work generically for any rails application.
82
+ def method_missing(table, *columns)
83
+ table_settings[table] = columns
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,39 @@
1
+ module EasySearch
2
+ class Validations
3
+ # called once the EasySearch module is included.
4
+ #
5
+ # it ensures that any/all models in the settings hash exist
6
+ # and decend from ActiveRecord::Base
7
+ def self.validate_settings!
8
+ unless Setup.table_settings.blank?
9
+ Setup.table_settings.keys.each do |klass|
10
+ unless klass.to_s.classify.constantize.ancestors.include?(ActiveRecord::Base)
11
+ raise( InvalidActiveRecordModel, InvalidActiveRecordModel.message )
12
+ end
13
+ end
14
+ end
15
+ rescue NameError
16
+ raise $!
17
+ raise( NoModelError, "you've specified a table in your `Setup.config' block that doesn't exist" )
18
+ end
19
+
20
+ # called when a new EasySearch containing class is instantiated.
21
+ #
22
+ # For example, `Search.users.with("ryan heath")' would instantiate a
23
+ # new Search, setting the "users" part to the @klass variable.
24
+ # the following would ensure that the @klass variable is indeed valid.
25
+ def self.validate_class!(klass)
26
+ raise( InvalidActiveRecordModel, InvalidActiveRecordModel.message ) unless valid_model?(klass)
27
+ raise( InvalidSettings, InvalidSettings.message ) unless model_has_settings?(klass)
28
+ end
29
+
30
+ private
31
+ def self.valid_model?(klass)
32
+ klass.to_s.singularize.classify.constantize.ancestors.include?(ActiveRecord::Base) rescue false
33
+ end
34
+
35
+ def self.model_has_settings?(klass)
36
+ !Setup.table_settings[klass].blank? rescue false
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module EasySearch
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :easy_search do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: easy_search
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Heath
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-06-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A small Ruby library that provides a DSL for simple LIKE searches.
56
+ email:
57
+ - ryan@rpheath.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.textile
66
+ - Rakefile
67
+ - bin/console
68
+ - bin/setup
69
+ - easy_search.gemspec
70
+ - lib/easy_search.rb
71
+ - lib/easy_search/constants.rb
72
+ - lib/easy_search/core.rb
73
+ - lib/easy_search/errors.rb
74
+ - lib/easy_search/setup.rb
75
+ - lib/easy_search/validations.rb
76
+ - lib/easy_search/version.rb
77
+ - tasks/easy_search_tasks.rake
78
+ homepage: http://www.github.com/rpheath/easy_search
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.2.2
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: A small DSL for simple searches.
102
+ test_files: []