pose 1.2.0 → 1.2.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.
- data/README.md +1 -1
- data/lib/pose.rb +3 -2
- data/lib/pose/{base_additions.rb → activerecord_base_additions.rb} +2 -1
- data/lib/pose/internal_helpers.rb +118 -0
- data/lib/pose/model_additions.rb +5 -5
- data/lib/pose/models/pose_assignment.rb +0 -4
- data/lib/pose/models/pose_word.rb +18 -4
- data/lib/pose/railtie.rb +1 -1
- data/lib/pose/static_api.rb +87 -0
- data/lib/pose/version.rb +1 -1
- data/spec/internal_helpers_spec.rb +178 -0
- data/spec/pose_api_spec.rb +279 -0
- data/spec/pose_assignment_spec.rb +10 -13
- data/spec/pose_word_spec.rb +19 -16
- data/spec/spec_helper.rb +34 -57
- data/spec/support/matchers.rb +20 -0
- data/spec/support/models.rb +8 -0
- metadata +29 -6
- data/lib/pose/static_helpers.rb +0 -173
- data/spec/pose_spec.rb +0 -401
@@ -0,0 +1,20 @@
|
|
1
|
+
# Verifies that a posable object has the given pose words in its search index.
|
2
|
+
RSpec::Matchers.define :have_pose_words do |expected|
|
3
|
+
|
4
|
+
match do |actual|
|
5
|
+
actual.should have(expected.size).pose_words
|
6
|
+
texts = actual.pose_words.map &:text
|
7
|
+
expected.each do |expected_word|
|
8
|
+
# Note (KG): Can't use text.should include(expected_word) here
|
9
|
+
# because Ruby thinks I want to include a Module for some reason.
|
10
|
+
texts.include?(expected_word).should be_true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
failure_message_for_should do |actual|
|
15
|
+
texts = actual.pose_words.map &:text
|
16
|
+
"expected that subject would have pose words [#{expected.join ', '}], but it has [#{texts.join ', '}]"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -75,6 +75,22 @@ dependencies:
|
|
75
75
|
- - ! '>='
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: database_cleaner
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
78
94
|
- !ruby/object:Gem::Dependency
|
79
95
|
name: factory_girl
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|
@@ -183,12 +199,13 @@ files:
|
|
183
199
|
- doc/top-level-namespace.html
|
184
200
|
- lib/generators/pose_generator.rb
|
185
201
|
- lib/generators/templates/migration.rb
|
186
|
-
- lib/pose/
|
202
|
+
- lib/pose/activerecord_base_additions.rb
|
203
|
+
- lib/pose/internal_helpers.rb
|
187
204
|
- lib/pose/model_additions.rb
|
188
205
|
- lib/pose/models/pose_assignment.rb
|
189
206
|
- lib/pose/models/pose_word.rb
|
190
207
|
- lib/pose/railtie.rb
|
191
|
-
- lib/pose/
|
208
|
+
- lib/pose/static_api.rb
|
192
209
|
- lib/pose/version.rb
|
193
210
|
- lib/pose.rb
|
194
211
|
- lib/tasks/pose_tasks.rake
|
@@ -196,10 +213,13 @@ files:
|
|
196
213
|
- Rakefile
|
197
214
|
- README.md
|
198
215
|
- spec/factories.rb
|
216
|
+
- spec/internal_helpers_spec.rb
|
217
|
+
- spec/pose_api_spec.rb
|
199
218
|
- spec/pose_assignment_spec.rb
|
200
|
-
- spec/pose_spec.rb
|
201
219
|
- spec/pose_word_spec.rb
|
202
220
|
- spec/spec_helper.rb
|
221
|
+
- spec/support/matchers.rb
|
222
|
+
- spec/support/models.rb
|
203
223
|
homepage: http://github.com/kevgo/pose
|
204
224
|
licenses: []
|
205
225
|
post_install_message:
|
@@ -226,7 +246,10 @@ specification_version: 3
|
|
226
246
|
summary: A polymorphic, storage-system independent search engine for Ruby on Rails.
|
227
247
|
test_files:
|
228
248
|
- spec/factories.rb
|
249
|
+
- spec/internal_helpers_spec.rb
|
250
|
+
- spec/pose_api_spec.rb
|
229
251
|
- spec/pose_assignment_spec.rb
|
230
|
-
- spec/pose_spec.rb
|
231
252
|
- spec/pose_word_spec.rb
|
232
253
|
- spec/spec_helper.rb
|
254
|
+
- spec/support/matchers.rb
|
255
|
+
- spec/support/models.rb
|
data/lib/pose/static_helpers.rb
DELETED
@@ -1,173 +0,0 @@
|
|
1
|
-
# Static helper methods of the Pose gem.
|
2
|
-
module Pose
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
# By default, doesn't run in tests.
|
6
|
-
# Set this to true to test the search functionality.
|
7
|
-
CONFIGURATION = { search_in_tests: false }
|
8
|
-
|
9
|
-
class <<self
|
10
|
-
|
11
|
-
# Returns whether Pose is configured to perform search.
|
12
|
-
# This setting exists to disable search in tests.
|
13
|
-
#
|
14
|
-
# @return [false, true]
|
15
|
-
def perform_search?
|
16
|
-
!(Rails.env == 'test' and !CONFIGURATION[:search_in_tests])
|
17
|
-
end
|
18
|
-
|
19
|
-
# Returns all words that begin with the given query string.
|
20
|
-
# This can be used for autocompletion functionality.
|
21
|
-
#
|
22
|
-
# @param [String]
|
23
|
-
# @return [Array<String>]
|
24
|
-
def autocomplete_words query
|
25
|
-
return [] if query.blank?
|
26
|
-
PoseWord.where('text LIKE ?', "#{Pose.root_word(query)[0]}%").map(&:text)
|
27
|
-
end
|
28
|
-
|
29
|
-
# Returns all strings that are in new_words, but not in existing_words.
|
30
|
-
# Helper method.
|
31
|
-
#
|
32
|
-
# @param [Array<String>] existing_words The words that are already associated with the object.
|
33
|
-
# @param [Array<String>] new_words The words thet the object should have from now on.
|
34
|
-
#
|
35
|
-
# @return [Array<String>] The words that need to be added to the existing_words array.
|
36
|
-
def get_words_to_add existing_words, new_words
|
37
|
-
new_words - existing_words.map(&:text)
|
38
|
-
end
|
39
|
-
|
40
|
-
# Helper method.
|
41
|
-
# Returns the id of all word objects that are in existing_words, but not in new_words.
|
42
|
-
#
|
43
|
-
# @param [Array<String>] existing_words The words that are already associated with the object.
|
44
|
-
# @param [Array<String>] new_words The words thet the object should have from now on.
|
45
|
-
#
|
46
|
-
# @return [Array<String>] The words that need to be removed from the existing_words array.
|
47
|
-
def get_words_to_remove existing_words, new_words
|
48
|
-
existing_words.map do |existing_word|
|
49
|
-
existing_word unless new_words.include?(existing_word.text)
|
50
|
-
end.compact
|
51
|
-
end
|
52
|
-
|
53
|
-
# Returns whether the given string is a URL.
|
54
|
-
#
|
55
|
-
# @param [String] word The string to check.
|
56
|
-
#
|
57
|
-
# @return [Boolean]
|
58
|
-
def is_url? word
|
59
|
-
URI::parse(word).scheme == 'http'
|
60
|
-
rescue URI::InvalidURIError
|
61
|
-
false
|
62
|
-
end
|
63
|
-
|
64
|
-
# Simplifies the given word to a generic search form.
|
65
|
-
#
|
66
|
-
# @param [String] raw_word The word to make searchable.
|
67
|
-
#
|
68
|
-
# @return [String] The stemmed version of the word.
|
69
|
-
def root_word raw_word
|
70
|
-
result = []
|
71
|
-
raw_word_copy = raw_word[0..-1]
|
72
|
-
raw_word_copy.gsub! '%20', ' '
|
73
|
-
raw_word_copy.gsub! /[()*<>'",;\?\-\=&%#]/, ' '
|
74
|
-
raw_word_copy.gsub! /\s+/, ' '
|
75
|
-
raw_word_copy.split(' ').each do |word|
|
76
|
-
if Pose.is_url?(word)
|
77
|
-
result.concat word.split(/[\.\/\:]/).delete_if(&:blank?)
|
78
|
-
else
|
79
|
-
word.gsub! /[\-\/\._:]/, ' '
|
80
|
-
word.gsub! /\s+/, ' '
|
81
|
-
word.split(' ').each do |w|
|
82
|
-
stemmed_word = w.parameterize.singularize
|
83
|
-
result.concat stemmed_word.split ' '
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
result.uniq
|
88
|
-
end
|
89
|
-
|
90
|
-
# Returns all objects matching the given query.
|
91
|
-
#
|
92
|
-
# @param [String] query
|
93
|
-
# @param (Class|[Array<Class>]) classes
|
94
|
-
# @param [Hash?] options Additional options.
|
95
|
-
#
|
96
|
-
# @return [Hash<Class, ActiveRecord::Relation>]
|
97
|
-
def search query, classes, options = {}
|
98
|
-
|
99
|
-
# Turn 'classes' into an array.
|
100
|
-
classes = [classes].flatten
|
101
|
-
classes_names = classes.map &:name
|
102
|
-
classes_names = classes_names[0] if classes_names.size == 1
|
103
|
-
|
104
|
-
# Get the ids of the results.
|
105
|
-
result_classes_and_ids = {}
|
106
|
-
query_words = query.split(' ').map{|query_word| Pose.root_word query_word}.flatten
|
107
|
-
query_words.each do |query_word|
|
108
|
-
current_word_classes_and_ids = {}
|
109
|
-
classes.each { |clazz| current_word_classes_and_ids[clazz.name] = [] }
|
110
|
-
query = PoseAssignment.joins(:pose_word) \
|
111
|
-
.select('pose_assignments.posable_id, pose_assignments.posable_type') \
|
112
|
-
.where('pose_words.text LIKE ?', "#{query_word}%") \
|
113
|
-
.where('posable_type IN (?)', classes_names)
|
114
|
-
PoseAssignment.connection.select_all(query.to_sql).each do |pose_assignment|
|
115
|
-
current_word_classes_and_ids[pose_assignment['posable_type']] << pose_assignment['posable_id'].to_i
|
116
|
-
end
|
117
|
-
# This is the old ActiveRecord way. Removed for performance reasons.
|
118
|
-
# query.each do |pose_assignment|
|
119
|
-
# current_word_classes_and_ids[pose_assignment.posable_type] << pose_assignment.posable_id
|
120
|
-
# end
|
121
|
-
|
122
|
-
current_word_classes_and_ids.each do |class_name, ids|
|
123
|
-
if result_classes_and_ids.has_key? class_name
|
124
|
-
result_classes_and_ids[class_name] = result_classes_and_ids[class_name] & ids
|
125
|
-
else
|
126
|
-
result_classes_and_ids[class_name] = ids
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
# Load the results by id.
|
132
|
-
{}.tap do |result|
|
133
|
-
result_classes_and_ids.each do |class_name, ids|
|
134
|
-
result_class = Kernel.const_get class_name
|
135
|
-
|
136
|
-
if ids.size == 0
|
137
|
-
# Handle no results.
|
138
|
-
result[result_class] = []
|
139
|
-
|
140
|
-
else
|
141
|
-
# Here we have results.
|
142
|
-
|
143
|
-
# Limit.
|
144
|
-
ids = ids.slice(0, options[:limit]) if options[:limit]
|
145
|
-
|
146
|
-
if options[:result_type] == :ids
|
147
|
-
# Ids requested for result.
|
148
|
-
|
149
|
-
if options.has_key? :scope
|
150
|
-
# We have a scope.
|
151
|
-
options[:scope].each do |scope|
|
152
|
-
result[result_class] = result_class.select('id').where(scope).map(&:id)
|
153
|
-
end
|
154
|
-
else
|
155
|
-
result[result_class] = ids
|
156
|
-
end
|
157
|
-
|
158
|
-
else
|
159
|
-
# Classes requested for result.
|
160
|
-
|
161
|
-
result[result_class] = result_class.where(id: ids)
|
162
|
-
if options.has_key? :scope
|
163
|
-
options[:scope].each do |scope|
|
164
|
-
result[result_class] = result[result_class].where(scope)
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
data/spec/pose_spec.rb
DELETED
@@ -1,401 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
ActiveRecord::Base.establish_connection adapter: 'postgresql', database: 'pose_test', min_messages: 'WARNING'
|
6
|
-
|
7
|
-
describe Pose do
|
8
|
-
subject { PosableOne.new }
|
9
|
-
|
10
|
-
before :each do
|
11
|
-
PosableOne.delete_all
|
12
|
-
PosableTwo.delete_all
|
13
|
-
PoseAssignment.delete_all
|
14
|
-
PoseWord.delete_all
|
15
|
-
end
|
16
|
-
|
17
|
-
describe 'associations' do
|
18
|
-
it 'allows to access the associated words of a posable object directly' do
|
19
|
-
subject.should have(0).pose_words
|
20
|
-
subject.pose_words << PoseWord.new(text: 'one')
|
21
|
-
subject.should have_pose_words(['one'])
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe 'update_pose_index' do
|
26
|
-
|
27
|
-
context "in the 'test' environment" do
|
28
|
-
after :each do
|
29
|
-
Pose::CONFIGURATION[:search_in_tests] = true
|
30
|
-
end
|
31
|
-
|
32
|
-
it "doesn't calls update_pose_words in tests if the test flag is not enabled" do
|
33
|
-
Pose::CONFIGURATION[:search_in_tests] = false
|
34
|
-
subject.should_not_receive :update_pose_words
|
35
|
-
subject.update_pose_index
|
36
|
-
end
|
37
|
-
|
38
|
-
it "calls update_pose_words in tests if the test flag is enabled" do
|
39
|
-
Pose::CONFIGURATION[:search_in_tests] = true
|
40
|
-
subject.should_receive :update_pose_words
|
41
|
-
subject.update_pose_index
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context "in the 'production' environment' do" do
|
46
|
-
before :each do
|
47
|
-
@old_env = Rails.env
|
48
|
-
Rails.env = 'production'
|
49
|
-
end
|
50
|
-
|
51
|
-
after :each do
|
52
|
-
Rails.env = @old_env
|
53
|
-
end
|
54
|
-
|
55
|
-
it "calls update_pose_words" do
|
56
|
-
subject.should_receive :update_pose_words
|
57
|
-
subject.update_pose_index
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe 'update_pose_words' do
|
63
|
-
|
64
|
-
it 'saves the words for search' do
|
65
|
-
subject.text = 'foo bar'
|
66
|
-
subject.update_pose_words
|
67
|
-
subject.should have(2).pose_words
|
68
|
-
subject.should have_pose_words ['foo', 'bar']
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'updates the search index when the text is changed' do
|
72
|
-
subject.text = 'foo'
|
73
|
-
subject.save!
|
74
|
-
|
75
|
-
subject.text = 'other text'
|
76
|
-
subject.update_pose_words
|
77
|
-
|
78
|
-
subject.should have_pose_words ['other', 'text']
|
79
|
-
end
|
80
|
-
|
81
|
-
it "doesn't create duplicate words" do
|
82
|
-
subject.text = 'foo foo'
|
83
|
-
subject.save!
|
84
|
-
subject.should have(1).pose_words
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
describe 'get_words_to_remove' do
|
89
|
-
|
90
|
-
it "returns an array of word objects that need to be removed" do
|
91
|
-
word1 = PoseWord.new text: 'one'
|
92
|
-
word2 = PoseWord.new text: 'two'
|
93
|
-
existing_words = [word1, word2]
|
94
|
-
new_words = ['one', 'three']
|
95
|
-
|
96
|
-
result = Pose.get_words_to_remove existing_words, new_words
|
97
|
-
|
98
|
-
result.should eql([word2])
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'returns an empty array if there are no words to be removed' do
|
102
|
-
word1 = PoseWord.new text: 'one'
|
103
|
-
word2 = PoseWord.new text: 'two'
|
104
|
-
existing_words = [word1, word2]
|
105
|
-
new_words = ['one', 'two']
|
106
|
-
|
107
|
-
result = Pose.get_words_to_remove existing_words, new_words
|
108
|
-
|
109
|
-
result.should eql([])
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
describe 'get_words_to_add' do
|
114
|
-
|
115
|
-
it 'returns an array with strings that need to be added' do
|
116
|
-
word1 = PoseWord.new text: 'one'
|
117
|
-
word2 = PoseWord.new text: 'two'
|
118
|
-
existing_words = [word1, word2]
|
119
|
-
new_words = ['one', 'three']
|
120
|
-
|
121
|
-
result = Pose.get_words_to_add existing_words, new_words
|
122
|
-
|
123
|
-
result.should eql(['three'])
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'returns an empty array if there is nothing to be added' do
|
127
|
-
word1 = PoseWord.new text: 'one'
|
128
|
-
word2 = PoseWord.new text: 'two'
|
129
|
-
existing_words = [word1, word2]
|
130
|
-
new_words = ['one', 'two']
|
131
|
-
|
132
|
-
result = Pose.get_words_to_add existing_words, new_words
|
133
|
-
|
134
|
-
result.should eql([])
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
describe 'root_word' do
|
139
|
-
|
140
|
-
it 'converts words into singular' do
|
141
|
-
Pose.root_word('bars').should eql(['bar'])
|
142
|
-
end
|
143
|
-
|
144
|
-
it 'removes special characters' do
|
145
|
-
Pose.root_word('(bar').should eql(['bar'])
|
146
|
-
Pose.root_word('bar)').should eql(['bar'])
|
147
|
-
Pose.root_word('(bar)').should eql(['bar'])
|
148
|
-
Pose.root_word('>foo').should eql(['foo'])
|
149
|
-
Pose.root_word('<foo').should eql(['foo'])
|
150
|
-
Pose.root_word('"foo"').should eql(['foo'])
|
151
|
-
Pose.root_word('"foo').should eql(['foo'])
|
152
|
-
Pose.root_word("'foo'").should eql(['foo'])
|
153
|
-
Pose.root_word("'foo's").should eql(['foo'])
|
154
|
-
Pose.root_word("foo?").should eql(['foo'])
|
155
|
-
Pose.root_word("foo!").should eql(['foo'])
|
156
|
-
Pose.root_word("foo/bar").should eql(['foo', 'bar'])
|
157
|
-
Pose.root_word("foo-bar").should eql(['foo', 'bar'])
|
158
|
-
Pose.root_word("foo--bar").should eql(['foo', 'bar'])
|
159
|
-
Pose.root_word("foo.bar").should eql(['foo', 'bar'])
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'removes umlauts' do
|
163
|
-
Pose.root_word('fünf').should eql(['funf'])
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'splits up numbers' do
|
167
|
-
Pose.root_word('11.2.2011').should eql(['11', '2', '2011'])
|
168
|
-
Pose.root_word('11-2-2011').should eql(['11', '2', '2011'])
|
169
|
-
Pose.root_word('30:4-5').should eql(['30', '4', '5'])
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'converts into lowercase' do
|
173
|
-
Pose.root_word('London').should eql(['london'])
|
174
|
-
end
|
175
|
-
|
176
|
-
it "stores single-letter words" do
|
177
|
-
Pose.root_word('a b').should eql(['a', 'b'])
|
178
|
-
end
|
179
|
-
|
180
|
-
it "does't encode external URLs" do
|
181
|
-
Pose.root_word('http://web.com').should eql(['http', 'web', 'com'])
|
182
|
-
end
|
183
|
-
|
184
|
-
it "doesn't store empty words" do
|
185
|
-
Pose.root_word(' one two ').should eql(['one', 'two'])
|
186
|
-
end
|
187
|
-
|
188
|
-
it "removes duplicates" do
|
189
|
-
Pose.root_word('one_one').should eql(['one'])
|
190
|
-
Pose.root_word('one one').should eql(['one'])
|
191
|
-
end
|
192
|
-
|
193
|
-
it "splits up complex URLs" do
|
194
|
-
Pose.root_word('books?id=p7uyWPcVGZsC&dq=closure%20definitive%20guide&pg=PP1#v=onepage&q&f=false').should eql([
|
195
|
-
"book", "id", "p7uywpcvgzsc", "dq", "closure", "definitive", "guide", "pg", "pp1", "v", "onepage", "q", "f", "false"])
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
describe 'search' do
|
200
|
-
|
201
|
-
it 'works' do
|
202
|
-
pos1 = PosableOne.create text: 'one'
|
203
|
-
|
204
|
-
result = Pose.search 'one', PosableOne
|
205
|
-
|
206
|
-
result.should have(1).items
|
207
|
-
result[PosableOne].should have(1).items
|
208
|
-
result[PosableOne][0].should == pos1
|
209
|
-
end
|
210
|
-
|
211
|
-
describe 'classes parameter' do
|
212
|
-
it 'returns all different classes by default' do
|
213
|
-
pos1 = PosableOne.create text: 'foo'
|
214
|
-
pos2 = PosableTwo.create text: 'foo'
|
215
|
-
|
216
|
-
result = Pose.search 'foo', [PosableOne, PosableTwo]
|
217
|
-
|
218
|
-
result.should have(2).items
|
219
|
-
result[PosableOne].should == [pos1]
|
220
|
-
result[PosableTwo].should == [pos2]
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'allows to provide different classes to return' do
|
224
|
-
pos1 = PosableOne.create text: 'foo'
|
225
|
-
pos2 = PosableTwo.create text: 'foo'
|
226
|
-
|
227
|
-
result = Pose.search 'foo', [PosableOne, PosableTwo]
|
228
|
-
|
229
|
-
result.should have(2).items
|
230
|
-
result[PosableOne].should == [pos1]
|
231
|
-
result[PosableTwo].should == [pos2]
|
232
|
-
end
|
233
|
-
|
234
|
-
it 'returns only instances of the given classes' do
|
235
|
-
pos1 = PosableOne.create text: 'one'
|
236
|
-
pos2 = PosableTwo.create text: 'one'
|
237
|
-
|
238
|
-
result = Pose.search 'one', PosableOne
|
239
|
-
|
240
|
-
result.should have(1).items
|
241
|
-
result[PosableOne].should == [pos1]
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
describe 'query parameter' do
|
246
|
-
|
247
|
-
it 'returns an empty array if nothing matches' do
|
248
|
-
pos1 = PosableOne.create text: 'one'
|
249
|
-
|
250
|
-
result = Pose.search 'two', PosableOne
|
251
|
-
|
252
|
-
result.should == { PosableOne => [] }
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'returns only objects that match all given query words' do
|
256
|
-
pos1 = PosableOne.create text: 'one two'
|
257
|
-
pos2 = PosableOne.create text: 'one three'
|
258
|
-
pos3 = PosableOne.create text: 'two three'
|
259
|
-
|
260
|
-
result = Pose.search 'two one', PosableOne
|
261
|
-
|
262
|
-
result.should have(1).items
|
263
|
-
result[PosableOne].should == [pos1]
|
264
|
-
end
|
265
|
-
|
266
|
-
it 'returns nothing if searching for a non-existing word' do
|
267
|
-
pos1 = PosableOne.create text: 'one two'
|
268
|
-
|
269
|
-
result = Pose.search 'one zonk', PosableOne
|
270
|
-
|
271
|
-
result.should have(1).items
|
272
|
-
result[PosableOne].should == []
|
273
|
-
end
|
274
|
-
|
275
|
-
it 'works if the query is given in uppercase' do
|
276
|
-
pos1 = PosableOne.create text: 'one two'
|
277
|
-
|
278
|
-
result = Pose.search 'OnE TwO', PosableOne
|
279
|
-
|
280
|
-
result.should have(1).items
|
281
|
-
result[PosableOne].should == [pos1]
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
describe "'limit' parameter" do
|
286
|
-
|
287
|
-
it 'works' do
|
288
|
-
FactoryGirl.create :posable_one, text: 'foo one'
|
289
|
-
FactoryGirl.create :posable_one, text: 'foo two'
|
290
|
-
FactoryGirl.create :posable_one, text: 'foo three'
|
291
|
-
FactoryGirl.create :posable_one, text: 'foo four'
|
292
|
-
|
293
|
-
result = Pose.search 'foo', PosableOne, limit: 3
|
294
|
-
|
295
|
-
result[PosableOne].should have(3).items
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
describe "'result_type' parameter" do
|
300
|
-
|
301
|
-
before :each do
|
302
|
-
@foo_one = FactoryGirl.create :posable_one, text: 'foo one'
|
303
|
-
end
|
304
|
-
|
305
|
-
describe 'default behavior' do
|
306
|
-
it 'returns full objects' do
|
307
|
-
result = Pose.search 'foo', PosableOne
|
308
|
-
result[PosableOne][0].should == @foo_one
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
context ':ids given' do
|
313
|
-
it 'returns ids instead of objects' do
|
314
|
-
result = Pose.search 'foo', PosableOne, result_type: :ids
|
315
|
-
result[PosableOne][0].should == @foo_one.id
|
316
|
-
end
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
describe "'scopes' parameter" do
|
321
|
-
|
322
|
-
before :each do
|
323
|
-
@one = FactoryGirl.create :posable_one, text: 'foo one', private: true
|
324
|
-
@two = FactoryGirl.create :posable_one, text: 'foo two', private: false
|
325
|
-
end
|
326
|
-
|
327
|
-
context 'with result type :classes' do
|
328
|
-
|
329
|
-
it 'limits the result set by the given scope' do
|
330
|
-
result = Pose.search 'foo', PosableOne, scope: [ private: true ]
|
331
|
-
result[PosableOne].should have(1).item
|
332
|
-
result[PosableOne].should include @one
|
333
|
-
end
|
334
|
-
|
335
|
-
it 'allows to use the hash syntax for queries' do
|
336
|
-
result = Pose.search 'foo', PosableOne, scope: [ private: true ]
|
337
|
-
result[PosableOne].should have(1).item
|
338
|
-
result[PosableOne].should include @one
|
339
|
-
end
|
340
|
-
|
341
|
-
it 'allows to use the string syntax for queries' do
|
342
|
-
result = Pose.search 'foo', PosableOne, scope: [ ['private = ?', true] ]
|
343
|
-
result[PosableOne].should have(1).item
|
344
|
-
result[PosableOne].should include @one
|
345
|
-
end
|
346
|
-
|
347
|
-
it 'allows to combine several scopes' do
|
348
|
-
@three = FactoryGirl.create :posable_one, text: 'foo two', private: true
|
349
|
-
result = Pose.search 'foo', PosableOne, scope: [ {private: true}, ['text = ?', 'foo two'] ]
|
350
|
-
result[PosableOne].should have(1).item
|
351
|
-
result[PosableOne].should include @three
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
|
-
context 'with result type :ids' do
|
356
|
-
|
357
|
-
it 'limits the result set by the given scope' do
|
358
|
-
result = Pose.search 'foo', PosableOne, result_type: :ids, scope: [ private: true ]
|
359
|
-
result[PosableOne].should have(1).item
|
360
|
-
result[PosableOne].should include @one.id
|
361
|
-
end
|
362
|
-
end
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
describe 'autocomplete_words' do
|
367
|
-
|
368
|
-
it 'returns words that start with the given phrase' do
|
369
|
-
PosableOne.create text: 'great green pine tree'
|
370
|
-
|
371
|
-
result = Pose.autocomplete_words 'gr'
|
372
|
-
|
373
|
-
result.should have(2).words
|
374
|
-
result.should include('great')
|
375
|
-
result.should include('green')
|
376
|
-
end
|
377
|
-
|
378
|
-
it 'returns words that match the given phrase exactly' do
|
379
|
-
PoseWord.create text: 'cat'
|
380
|
-
|
381
|
-
result = Pose.autocomplete_words 'cat'
|
382
|
-
|
383
|
-
result.should == ['cat']
|
384
|
-
end
|
385
|
-
|
386
|
-
it 'stems the search query' do
|
387
|
-
PosableOne.create text: 'car'
|
388
|
-
|
389
|
-
result = Pose.autocomplete_words 'cars'
|
390
|
-
|
391
|
-
result.should have(1).words
|
392
|
-
result[0].should == 'car'
|
393
|
-
end
|
394
|
-
|
395
|
-
it 'returns nothing if the search query is empty' do
|
396
|
-
PosableOne.create text: 'foo bar'
|
397
|
-
result = Pose.autocomplete_words ''
|
398
|
-
result.should have(0).words
|
399
|
-
end
|
400
|
-
end
|
401
|
-
end
|