hunt_em 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +52 -0
- data/LICENSE +20 -0
- data/README.rdoc +59 -0
- data/Rakefile +7 -0
- data/examples/multiple.rb +38 -0
- data/examples/single.rb +41 -0
- data/hunt.gemspec +23 -0
- data/lib/hunt.rb +37 -0
- data/lib/hunt/util.rb +57 -0
- data/lib/hunt/version.rb +3 -0
- data/spec/helper.rb +17 -0
- data/spec/hunt/util_spec.rb +62 -0
- data/spec/hunt_spec.rb +185 -0
- data/specs.watchr +33 -0
- metadata +88 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c29b7e52a8f0370abd8e0d42e239ab83ebefef0b
|
4
|
+
data.tar.gz: af958e05d5b2788754452de786cc8f995ac99eac
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: be95f2afd795367f7f6ac270d369dc6b4c50d5a125fada106929349664a160c2d186a82ce352b4bebfe45ba57352d440fee4a33ac5d92cefed9f6f8fbb0abcf9
|
7
|
+
data.tar.gz: da20a3157479f8f6cf7477b7dee85ddaec506f689ad80f4bf0899fac1c94e7a1956d95ccf6ca2494f2f14ff20c4c0ddd736404e94022a0977aa4470da50a4731
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
hunt (0.4)
|
5
|
+
fast-stemmer (~> 1.0)
|
6
|
+
mongo_mapper (~> 0.9.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activemodel (3.1.0)
|
12
|
+
activesupport (= 3.1.0)
|
13
|
+
bcrypt-ruby (~> 3.0.0)
|
14
|
+
builder (~> 3.0.0)
|
15
|
+
i18n (~> 0.6)
|
16
|
+
activesupport (3.1.0)
|
17
|
+
multi_json (~> 1.0)
|
18
|
+
bcrypt-ruby (3.0.1)
|
19
|
+
bson (1.3.1)
|
20
|
+
bson_ext (1.3.1)
|
21
|
+
builder (3.0.0)
|
22
|
+
diff-lcs (1.1.2)
|
23
|
+
fast-stemmer (1.0.0)
|
24
|
+
i18n (0.6.0)
|
25
|
+
mongo (1.3.1)
|
26
|
+
bson (>= 1.3.1)
|
27
|
+
mongo_mapper (0.9.2)
|
28
|
+
activemodel (~> 3.0)
|
29
|
+
activesupport (~> 3.0)
|
30
|
+
plucky (~> 0.3.8)
|
31
|
+
multi_json (1.0.3)
|
32
|
+
plucky (0.3.8)
|
33
|
+
mongo (~> 1.3)
|
34
|
+
rake (0.9.2)
|
35
|
+
rspec (2.3.0)
|
36
|
+
rspec-core (~> 2.3.0)
|
37
|
+
rspec-expectations (~> 2.3.0)
|
38
|
+
rspec-mocks (~> 2.3.0)
|
39
|
+
rspec-core (2.3.1)
|
40
|
+
rspec-expectations (2.3.0)
|
41
|
+
diff-lcs (~> 1.1.2)
|
42
|
+
rspec-mocks (2.3.0)
|
43
|
+
|
44
|
+
PLATFORMS
|
45
|
+
ruby
|
46
|
+
|
47
|
+
DEPENDENCIES
|
48
|
+
bson_ext
|
49
|
+
hunt!
|
50
|
+
i18n
|
51
|
+
rake
|
52
|
+
rspec (~> 2.3)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 John Nunemaker
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
== Same as jnunemaker's hunt gem, but excludes mongo mapper as a dependency
|
2
|
+
|
3
|
+
= Hunt
|
4
|
+
|
5
|
+
Insanely stupid and basic indexed search for MongoMapper. Probably pointless, but something I am playing around with on side projects.
|
6
|
+
|
7
|
+
== Usage
|
8
|
+
|
9
|
+
Declare the plugin.
|
10
|
+
|
11
|
+
class Note
|
12
|
+
include MongoMapper::Document
|
13
|
+
plugin Hunt
|
14
|
+
|
15
|
+
key :title, String
|
16
|
+
key :body, String
|
17
|
+
key :tags, Array
|
18
|
+
timestamps!
|
19
|
+
|
20
|
+
searches :title, :body, :tags
|
21
|
+
end
|
22
|
+
|
23
|
+
This creates a key named searches that is a Hash. Title, body, and tags get mashed together before save into a unique array of stemmed words and stored in searches.default.
|
24
|
+
|
25
|
+
You can index the terms individually or with any other combination of keys.
|
26
|
+
|
27
|
+
Note.ensure_index :'searches.default' # or ...
|
28
|
+
Note.ensure_index [[:user_id, Mongo::Ascending], [:'searches.default', Mongo::Ascending]]
|
29
|
+
|
30
|
+
You also get a search class method that returns a scope.
|
31
|
+
|
32
|
+
# Returns Plucky::Query (MM Scope), no query actually fired
|
33
|
+
Note.search('mongodb')
|
34
|
+
|
35
|
+
# Gets everything matching mongodb
|
36
|
+
Note.search('mongodb').all
|
37
|
+
|
38
|
+
# Gets first page of everything matching mongodb
|
39
|
+
Note.search('mongodb').paginate(:page => 1)
|
40
|
+
|
41
|
+
# Counts everything matching mongodb
|
42
|
+
Note.search('mongodb').count
|
43
|
+
|
44
|
+
# Matches everything with any of the terms
|
45
|
+
Note.search('mongodb is awesome')
|
46
|
+
|
47
|
+
== Note on Patches/Pull Requests
|
48
|
+
|
49
|
+
* Fork the project.
|
50
|
+
* Make your feature addition or bug fix.
|
51
|
+
* Add tests for it. This is important so I don't break it in a
|
52
|
+
future version unintentionally.
|
53
|
+
* Commit, do not mess with rakefile, version, or history.
|
54
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
55
|
+
* Send me a pull request. Bonus points for topic branches.
|
56
|
+
|
57
|
+
== Copyright
|
58
|
+
|
59
|
+
Copyright (c) 2010 John Nunemaker. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
2
|
+
require 'pp'
|
3
|
+
require 'hunt'
|
4
|
+
|
5
|
+
MongoMapper.database = 'testing'
|
6
|
+
|
7
|
+
class Note
|
8
|
+
include MongoMapper::Document
|
9
|
+
plugin Hunt
|
10
|
+
|
11
|
+
key :title, String
|
12
|
+
key :tags, Array
|
13
|
+
|
14
|
+
# Declare which fields to search on.
|
15
|
+
# No problem declaring an array key.
|
16
|
+
searches :title, :tags
|
17
|
+
end
|
18
|
+
Note.delete_all # clean the slate
|
19
|
+
|
20
|
+
# Note that the search terms are stored in a searches hash in the key default.
|
21
|
+
# This is so that future versions can allow different combinations of search
|
22
|
+
# fields and use different keys in searches.
|
23
|
+
|
24
|
+
# Also, meaningless words are stripped out and all words less than 3 characters
|
25
|
+
# long. The words are then stemmed (http://en.wikipedia.org/wiki/Stemming) so
|
26
|
+
# exact matches when searching are not necessary.
|
27
|
+
|
28
|
+
pp Note.create(:title => 'I am lost without Mongo!', :tags => %w(mongo database nosql))
|
29
|
+
#<Note searches: {"default"=>["test", "mongo", "databas", "nosql"]}, title: "This is a test", _id: BSON::ObjectId('...'), tags: ["mongo", "database", "nosql"]>
|
30
|
+
|
31
|
+
pp Note.create(:title => 'Lost is a tv show', :tags => %w(lost tv))
|
32
|
+
#<Note searches: {"default"=>["lost", "tv", "show"]}, title: "Lost is a tv show", _id: BSON::ObjectId('...'), tags: ["lost", "tv"]>
|
33
|
+
|
34
|
+
pp Note.search('lost').count # 2
|
35
|
+
pp Note.search('tv').count # 1
|
36
|
+
|
37
|
+
# Multiple words work
|
38
|
+
pp Note.search('mongo tv').count # 2
|
data/examples/single.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
2
|
+
require 'pp'
|
3
|
+
require 'hunt'
|
4
|
+
|
5
|
+
MongoMapper.database = 'testing'
|
6
|
+
|
7
|
+
class Note
|
8
|
+
include MongoMapper::Document
|
9
|
+
plugin Hunt
|
10
|
+
|
11
|
+
key :title, String
|
12
|
+
|
13
|
+
# Declare which fields to search on.
|
14
|
+
searches :title
|
15
|
+
end
|
16
|
+
Note.delete_all # clean the slate
|
17
|
+
|
18
|
+
# Note that the search terms are stored in a searches hash in the key default.
|
19
|
+
# This is so that future versions can allow different combinations of search
|
20
|
+
# fields and use different keys in searches.
|
21
|
+
#
|
22
|
+
# Also, meaningless words are stripped out and all words less than 3 characters
|
23
|
+
# long. The words are then stemmed (http://en.wikipedia.org/wiki/Stemming) so
|
24
|
+
# exact matches when searching are not necessary.
|
25
|
+
|
26
|
+
note = Note.create(:title => 'This is a test')
|
27
|
+
pp note
|
28
|
+
# #<Note searches: {"default"=>["test"]}, title: "This is a test", _id: BSON::ObjectId('...')>
|
29
|
+
|
30
|
+
note.update_attributes(:title => 'A different test')
|
31
|
+
pp note
|
32
|
+
# #<Note searches: {"default"=>["differ", "test"]}, title: "A different test", _id: BSON::ObjectId('...')>
|
33
|
+
|
34
|
+
# Also, you get a handy
|
35
|
+
pp Note.search('test').count # 1
|
36
|
+
pp Note.search('testing').count # 1
|
37
|
+
pp Note.search('testing').all
|
38
|
+
# [#<Note searches: {"default"=>["differ", "test"]}, title: "A different test", _id: BSON::ObjectId('...')>]
|
39
|
+
|
40
|
+
pp Note.search('test').paginate(:page => 1)
|
41
|
+
# [#<Note searches: {"default"=>["differ", "test"]}, title: "A different test", _id: BSON::ObjectId('...')>]
|
data/hunt.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "hunt/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "hunt_em"
|
7
|
+
s.version = Hunt::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ryan T. Hosford"]
|
10
|
+
s.email = ["tad.hosford@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/rthbound/hunt"
|
12
|
+
s.summary = %q{Same as hunt, but excluding mongo_mapper as a dependency}
|
13
|
+
s.description = %q{Same as hunt, but excluding mongo_mapper as a dependency}
|
14
|
+
|
15
|
+
s.add_dependency 'fast-stemmer', '~> 1.0'
|
16
|
+
|
17
|
+
s.add_development_dependency 'rspec', '~> 2.3'
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
data/lib/hunt.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'fast_stemmer'
|
2
|
+
require 'mongo_mapper'
|
3
|
+
require 'hunt/util'
|
4
|
+
|
5
|
+
module Hunt
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
before_save(:index_search_terms)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def search_keys
|
14
|
+
@search_keys ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def searches(*keys)
|
18
|
+
# Using a hash to support multiple indexes per document at some point
|
19
|
+
key(:searches, Hash)
|
20
|
+
@search_keys = keys
|
21
|
+
end
|
22
|
+
|
23
|
+
def search(term)
|
24
|
+
where('searches.default' => Util.to_stemmed_words(term))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module InstanceMethods
|
29
|
+
def concatted_search_values
|
30
|
+
self.class.search_keys.map { |key| send(key) }.flatten.join(' ')
|
31
|
+
end
|
32
|
+
|
33
|
+
def index_search_terms
|
34
|
+
self.searches['default'] = Util.to_stemmed_words(concatted_search_values)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/hunt/util.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Hunt
|
2
|
+
module Util
|
3
|
+
Separator = ' '
|
4
|
+
StripPunctuationRegex = /[^a-zA-Z0-9]/
|
5
|
+
PunctuationReplacement = ''
|
6
|
+
WordsToIgnore = [
|
7
|
+
"a", "about", "above", "after", "again", "against", "all", "am", "an",
|
8
|
+
"and", "any", "are", "aren't", "as", "at", "be", "because", "been",
|
9
|
+
"before", "being", "below", "between", "both", "but", "by", "cannot",
|
10
|
+
"can't", "could", "couldn't", "did", "didn't", "do", "does", "doesn't",
|
11
|
+
"doing", "don't", "down", "during", "each", "few", "for", "from",
|
12
|
+
"further", "had", "hadn't", "has", "hasn't", "have", "haven't", "having",
|
13
|
+
"he", "he'd", "he'll", "her", "here", "here's", "hers", "herself", "he's",
|
14
|
+
"him", "himself", "his", "how", "how's", "i", "i'd", "if", "i'll", "i'm",
|
15
|
+
"in", "into", "is", "isn't", "it", "its", "it's", "itself", "i've", "let's",
|
16
|
+
"me", "more", "most", "mustn't", "my", "myself", "no", "nor", "not", "of",
|
17
|
+
"off", "on", "once", "only", "or", "other", "ought", "our", "ours", "ourselves",
|
18
|
+
"out", "over", "own", "same", "shan't", "she", "she'd", "she'll", "she's",
|
19
|
+
"should", "shouldn't", "so", "some", "such", "than", "that", "that's", "the",
|
20
|
+
"their", "theirs", "them", "themselves", "then", "there", "there's", "these",
|
21
|
+
"they", "they'd", "they'll", "they're", "they've", "this", "those", "through",
|
22
|
+
"to", "too", "under", "until", "up", "very", "was", "wasn't", "we", "we'd",
|
23
|
+
"we'll", "were", "we're", "weren't", "we've", "what", "what's", "when",
|
24
|
+
"when's", "where", "where's", "which", "while", "who", "whom", "who's",
|
25
|
+
"why", "why's", "with", "won't", "would", "wouldn't", "you", "you'd",
|
26
|
+
"you'll", "your", "you're", "yours", "yourself", "yourselves", "you've",
|
27
|
+
"the", "how"
|
28
|
+
]
|
29
|
+
|
30
|
+
def strip_puncuation(value)
|
31
|
+
value.to_s.gsub(StripPunctuationRegex, PunctuationReplacement)
|
32
|
+
end
|
33
|
+
|
34
|
+
def stem(word)
|
35
|
+
Stemmer.stem_word(word)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_words(value)
|
39
|
+
value.
|
40
|
+
to_s.
|
41
|
+
squeeze(Separator).
|
42
|
+
split(Separator).
|
43
|
+
map { |word| word.downcase }.
|
44
|
+
reject { |word| word.size < 2 }.
|
45
|
+
reject { |word| WordsToIgnore.include?(word) }.
|
46
|
+
map { |word| strip_puncuation(word) }.
|
47
|
+
reject { |word| word.blank? }.
|
48
|
+
uniq
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_stemmed_words(value)
|
52
|
+
to_words(value).map { |word| stem(word) }
|
53
|
+
end
|
54
|
+
|
55
|
+
extend self
|
56
|
+
end
|
57
|
+
end
|
data/lib/hunt/version.rb
ADDED
data/spec/helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
|
6
|
+
Bundler.require(:default, :development)
|
7
|
+
|
8
|
+
require 'hunt'
|
9
|
+
|
10
|
+
MongoMapper.connection = Mongo::Connection.new
|
11
|
+
MongoMapper.database = 'test'
|
12
|
+
|
13
|
+
Rspec.configure do |c|
|
14
|
+
c.before(:each) do
|
15
|
+
MongoMapper.database.collections.each(&:remove)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Hunt::Util do
|
4
|
+
describe ".strip_puncuation" do
|
5
|
+
it "removes punctuation" do
|
6
|
+
Hunt::Util.strip_puncuation('woot!').should == 'woot'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".stem" do
|
11
|
+
it "stems word" do
|
12
|
+
Hunt::Util.stem('kissing').should == 'kiss'
|
13
|
+
Hunt::Util.stem('hello').should == 'hello'
|
14
|
+
Hunt::Util.stem('barfing').should == 'barf'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".to_words" do
|
19
|
+
it "does not fail with nil" do
|
20
|
+
Hunt::Util.to_words(nil).should == []
|
21
|
+
end
|
22
|
+
|
23
|
+
it "converts string to array of words" do
|
24
|
+
Hunt::Util.to_words('first sentence').should == %w(first sentence)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "squeezes multiple spaces" do
|
28
|
+
Hunt::Util.to_words('first sentence').should == %w(first sentence)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "removes punctuation" do
|
32
|
+
Hunt::Util.to_words('woot!').should == %w(woot)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "removes blanks from removed punctuation" do
|
36
|
+
Hunt::Util.to_words('first sentence & second').should == %w(first sentence second)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "lowercases each word" do
|
40
|
+
Hunt::Util.to_words('Sweet First Sentence').should == %w(sweet first sentence)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "removes any words under 2 characters" do
|
44
|
+
Hunt::Util.to_words('a tv show').should == %w(tv show)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "removes words that should be ignored" do
|
48
|
+
Hunt::Util.to_words('how was your day').should == %w(day)
|
49
|
+
Hunt::Util.to_words("didn't you see that").should == %w(see)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "removes duplicates" do
|
53
|
+
Hunt::Util.to_words('boom boom').should == %w(boom)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe ".to_stemmed_words" do
|
58
|
+
it "converts value to array of stemmed words" do
|
59
|
+
Hunt::Util.to_stemmed_words('I just Caught you kissing.').should == %w(just caught kiss)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/spec/hunt_spec.rb
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class Note
|
4
|
+
include MongoMapper::Document
|
5
|
+
|
6
|
+
plugin Hunt
|
7
|
+
|
8
|
+
scope :by_user, lambda { |user| where(:user_id => user.id) }
|
9
|
+
|
10
|
+
key :title, String
|
11
|
+
key :body, String
|
12
|
+
key :tags, Array
|
13
|
+
key :user_id, ObjectId
|
14
|
+
|
15
|
+
belongs_to :user
|
16
|
+
end
|
17
|
+
|
18
|
+
class User
|
19
|
+
include MongoMapper::Document
|
20
|
+
many :notes
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Hunt do
|
24
|
+
it "adds searches key to model to store search terms" do
|
25
|
+
Note.searches(:title)
|
26
|
+
Note.new.should respond_to(:searches)
|
27
|
+
Note.new.should respond_to(:searches=)
|
28
|
+
end
|
29
|
+
|
30
|
+
describe ".search" do
|
31
|
+
before(:each) do
|
32
|
+
Note.searches(:title)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns query that matches nothing if nil" do
|
36
|
+
Note.create(:title => 'Mongo')
|
37
|
+
Note.search(nil).count.should == 0
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns query that matches nothing if blank" do
|
41
|
+
Note.create(:title => 'Mongo')
|
42
|
+
Note.search('').count.should == 0
|
43
|
+
end
|
44
|
+
|
45
|
+
context "chained on scope" do
|
46
|
+
before(:each) do
|
47
|
+
@user = User.create
|
48
|
+
@note = Note.create(:title => 'Mongo', :user_id => @user.id)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "works" do
|
52
|
+
Note.by_user(@user).search('Mongo').all.should == [@note]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "chained on association" do
|
57
|
+
before(:each) do
|
58
|
+
@user = User.create
|
59
|
+
@note = Note.create(:title => 'Mongo', :user_id => @user.id)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "works" do
|
63
|
+
@user.notes.search('Mongo').all.should == [@note]
|
64
|
+
@user.notes.search('Frank').all.should == []
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with one search term" do
|
69
|
+
before(:each) do
|
70
|
+
@note = Note.create(:title => 'MongoDB is awesome!')
|
71
|
+
@result = Note.search('mongodb')
|
72
|
+
end
|
73
|
+
|
74
|
+
let(:note) { @note }
|
75
|
+
let(:result) { @result }
|
76
|
+
|
77
|
+
it "returns plucky query" do
|
78
|
+
result.should be_instance_of(Plucky::Query)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "scopes query to searches.default in stemmed terms" do
|
82
|
+
result['searches.default'].should == {'$in' => %w(mongodb)}
|
83
|
+
end
|
84
|
+
|
85
|
+
it "does return matched documents" do
|
86
|
+
result.all.should include(note)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "does not query unmatched documents" do
|
90
|
+
not_found = Note.create(:title => 'Something different')
|
91
|
+
result.all.should_not include(not_found)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "with multiple search terms" do
|
96
|
+
before(:each) do
|
97
|
+
@note = Note.create(:title => 'MongoDB is awesome!')
|
98
|
+
@result = Note.search('mongodb is awesome')
|
99
|
+
end
|
100
|
+
|
101
|
+
let(:note) { @note }
|
102
|
+
let(:result) { @result }
|
103
|
+
|
104
|
+
it "returns plucky query" do
|
105
|
+
result.should be_instance_of(Plucky::Query)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "scopes query to searches.default in stemmed terms" do
|
109
|
+
result['searches.default'].should == {'$in' => Hunt::Util.to_stemmed_words(note.concatted_search_values)}
|
110
|
+
end
|
111
|
+
|
112
|
+
it "returns documents that match both terms" do
|
113
|
+
result.all.should include(note)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "returns documents that match any of the terms" do
|
117
|
+
awesome = Note.create(:title => 'Something awesome')
|
118
|
+
mongodb = Note.create(:title => 'Something MongoDB')
|
119
|
+
result.all.should include(awesome)
|
120
|
+
result.all.should include(mongodb)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "does not query unmatched documents" do
|
124
|
+
not_found = Note.create(:title => 'Something different')
|
125
|
+
result.all.should_not include(not_found)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "Search indexing" do
|
131
|
+
context "on one field" do
|
132
|
+
before(:each) do
|
133
|
+
Note.searches(:title)
|
134
|
+
@note = Note.create(:title => 'Woot for MongoDB!')
|
135
|
+
end
|
136
|
+
|
137
|
+
let(:note) { @note }
|
138
|
+
|
139
|
+
it "indexes terms on create" do
|
140
|
+
note.searches['default'].should == Hunt::Util.to_stemmed_words(note.concatted_search_values)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "indexes terms on update" do
|
144
|
+
note.update_attributes(:title => 'Another woot')
|
145
|
+
note.searches['default'].should == Hunt::Util.to_stemmed_words(note.concatted_search_values)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "on multiple fields" do
|
150
|
+
before(:each) do
|
151
|
+
Note.searches(:title, :body)
|
152
|
+
@note = Note.create(:title => 'Woot for MongoDB!', :body => 'This is my body.')
|
153
|
+
end
|
154
|
+
|
155
|
+
let(:note) { @note }
|
156
|
+
|
157
|
+
it "indexes merged terms on create" do
|
158
|
+
note.searches['default'].should == Hunt::Util.to_stemmed_words(note.concatted_search_values)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "indexes merged terms on update" do
|
162
|
+
note.update_attributes(:title => 'Another woot', :body => 'An updated body.')
|
163
|
+
note.searches['default'].should == Hunt::Util.to_stemmed_words(note.concatted_search_values)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "on multiple fields one of which is array key" do
|
168
|
+
before(:each) do
|
169
|
+
Note.searches(:title, :tags)
|
170
|
+
@note = Note.create(:title => 'Woot for MongoDB!', :tags => %w(mongo nosql))
|
171
|
+
end
|
172
|
+
|
173
|
+
let(:note) { @note }
|
174
|
+
|
175
|
+
it "indexes merged terms on create" do
|
176
|
+
note.searches['default'].should == Hunt::Util.to_stemmed_words(note.concatted_search_values)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "indexes merged terms on update" do
|
180
|
+
note.update_attributes(:title => 'Another woot', :tags => %w(mongo))
|
181
|
+
note.searches['default'].should == Hunt::Util.to_stemmed_words(note.concatted_search_values)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
data/specs.watchr
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
def run(cmd)
|
2
|
+
puts cmd
|
3
|
+
output = ""
|
4
|
+
IO.popen(cmd) do |com|
|
5
|
+
com.each_char do |c|
|
6
|
+
print c
|
7
|
+
output << c
|
8
|
+
$stdout.flush
|
9
|
+
end
|
10
|
+
end
|
11
|
+
output
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_spec(path)
|
15
|
+
path.gsub!('lib/', 'spec/')
|
16
|
+
path.gsub!('_spec', '')
|
17
|
+
file_name = File.basename(path, '.rb')
|
18
|
+
path.gsub!(file_name, file_name + "_spec")
|
19
|
+
run %Q(bundle exec rspec #{path})
|
20
|
+
end
|
21
|
+
|
22
|
+
watch('spec/helper\.rb') { system('clear'); run('rake') }
|
23
|
+
watch('lib/.*\.rb') { |m| system('clear'); run_spec(m[0]) }
|
24
|
+
watch('spec/.*_spec\.rb') { |m| system('clear'); run_spec(m[0]) }
|
25
|
+
|
26
|
+
# Ctrl-\
|
27
|
+
Signal.trap('QUIT') do
|
28
|
+
puts " --- Running all tests ---\n\n"
|
29
|
+
run('rake')
|
30
|
+
end
|
31
|
+
|
32
|
+
# Ctrl-C
|
33
|
+
Signal.trap('INT') { abort("\n") }
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hunt_em
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan T. Hosford
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fast-stemmer
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.3'
|
41
|
+
description: Same as hunt, but excluding mongo_mapper as a dependency
|
42
|
+
email:
|
43
|
+
- tad.hosford@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- LICENSE
|
52
|
+
- README.rdoc
|
53
|
+
- Rakefile
|
54
|
+
- examples/multiple.rb
|
55
|
+
- examples/single.rb
|
56
|
+
- hunt.gemspec
|
57
|
+
- lib/hunt.rb
|
58
|
+
- lib/hunt/util.rb
|
59
|
+
- lib/hunt/version.rb
|
60
|
+
- spec/helper.rb
|
61
|
+
- spec/hunt/util_spec.rb
|
62
|
+
- spec/hunt_spec.rb
|
63
|
+
- specs.watchr
|
64
|
+
homepage: http://github.com/rthbound/hunt
|
65
|
+
licenses: []
|
66
|
+
metadata: {}
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 2.0.3
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: Same as hunt, but excluding mongo_mapper as a dependency
|
87
|
+
test_files: []
|
88
|
+
has_rdoc:
|