hunt_em 0.1

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: c29b7e52a8f0370abd8e0d42e239ab83ebefef0b
4
+ data.tar.gz: af958e05d5b2788754452de786cc8f995ac99eac
5
+ SHA512:
6
+ metadata.gz: be95f2afd795367f7f6ac270d369dc6b4c50d5a125fada106929349664a160c2d186a82ce352b4bebfe45ba57352d440fee4a33ac5d92cefed9f6f8fbb0abcf9
7
+ data.tar.gz: da20a3157479f8f6cf7477b7dee85ddaec506f689ad80f4bf0899fac1c94e7a1956d95ccf6ca2494f2f14ff20c4c0ddd736404e94022a0977aa4470da50a4731
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'bson_ext', :require => false
4
+
5
+ gemspec
6
+
7
+ gem 'i18n'
8
+ gem 'rake'
@@ -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.
@@ -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.
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new
6
+
7
+ task :default => :spec
@@ -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
@@ -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('...')>]
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Hunt
2
+ VERSION = "0.1"
3
+ end
@@ -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
@@ -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
@@ -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: