pose 2.0.1 → 2.1.0

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.
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :posable_two do
3
+ text { Faker::Lorem.words(2).join ' ' }
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :user do
3
+ name 'foo'
4
+ end
5
+ end
6
+
@@ -0,0 +1,147 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Pose::Helpers do
5
+
6
+ describe :get_words_to_add do
7
+ let(:one) { Pose::Word.new(text: 'one') }
8
+ let(:two) { Pose::Word.new(text: 'two') }
9
+
10
+ context 'having a new word to be added' do
11
+ it 'returns an array with strings that need to be added' do
12
+ expect(Pose::Helpers.get_words_to_add([one, two], %w{one three})).to eql(['three'])
13
+ end
14
+ end
15
+
16
+ context 'nothing to add' do
17
+ it 'returns an empty array' do
18
+ expect(Pose::Helpers.get_words_to_add([one, two], %w{one two})).to be_empty
19
+ end
20
+ end
21
+ end
22
+
23
+
24
+ describe :get_words_to_remove do
25
+ let(:one) { Pose::Word.new(text: 'one') }
26
+ let(:two) { Pose::Word.new(text: 'two') }
27
+
28
+ it "returns an array of word objects that need to be removed" do
29
+ expect(Pose::Helpers.get_words_to_remove([one, two], %w{one three})).to eql([two])
30
+ end
31
+
32
+ it 'returns an empty array if there are no words to be removed' do
33
+ expect(Pose::Helpers.get_words_to_remove([one, two], %w{one two})).to be_empty
34
+ end
35
+ end
36
+
37
+
38
+ describe :is_sql_database? do
39
+
40
+ it 'recognizes postgres databases' do
41
+ ActiveRecord::Base.connection.class.stub(:name).and_return 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
42
+ expect(Pose::Helpers.is_sql_database?).to be_true
43
+ end
44
+
45
+ it 'recognizes sqlite3 databases' do
46
+ ActiveRecord::Base.connection.class.stub(:name).and_return 'ActiveRecord::ConnectionAdapters::SQLite3Adapter'
47
+ expect(Pose::Helpers.is_sql_database?).to be_true
48
+ end
49
+ end
50
+
51
+ describe 'is_url?' do
52
+
53
+ it 'returns TRUE if the given string is a URL' do
54
+ expect(Pose::Helpers.is_url? 'http://web.com').to be_true
55
+ end
56
+
57
+ it 'returns TRUE if the given string is a HTTPS URL' do
58
+ expect(Pose::Helpers.is_url? 'https://web.com').to be_true
59
+ end
60
+
61
+ it 'returns FALSE if the given string is not a URL' do
62
+ expect(Pose::Helpers.is_url? 'foo').to be_false
63
+ end
64
+
65
+ it 'returns FALSE if the given string is a malformed URL' do
66
+ expect(Pose::Helpers.is_url? 'http://web').to be_false
67
+ end
68
+ end
69
+
70
+ describe :make_array do
71
+
72
+ it 'converts a single value into an array' do
73
+ expect(Pose::Helpers.make_array(1)).to eq [1]
74
+ end
75
+
76
+ it 'leaves arrays as arrays' do
77
+ expect(Pose::Helpers.make_array([1])).to eq [1]
78
+ end
79
+
80
+ it 'flattens nested arrays' do
81
+ Pose::Helpers.make_array([1, [2], [[3]]]).should eq [1, 2, 3]
82
+ end
83
+ end
84
+
85
+
86
+ describe :root_word do
87
+
88
+ it 'converts words into singular' do
89
+ expect(Pose::Helpers.root_word('bars')).to eql(['bar'])
90
+ end
91
+
92
+ it 'removes special characters' do
93
+ expect(Pose::Helpers.root_word('(bar')).to eq ['bar']
94
+ expect(Pose::Helpers.root_word('bar)')).to eq ['bar']
95
+ expect(Pose::Helpers.root_word('(bar)')).to eq ['bar']
96
+ expect(Pose::Helpers.root_word('>foo')).to eq ['foo']
97
+ expect(Pose::Helpers.root_word('<foo')).to eq ['foo']
98
+ expect(Pose::Helpers.root_word('"foo"')).to eq ['foo']
99
+ expect(Pose::Helpers.root_word('"foo')).to eq ['foo']
100
+ expect(Pose::Helpers.root_word("'foo'")).to eq ['foo']
101
+ expect(Pose::Helpers.root_word("'foo's")).to eq ['foo']
102
+ expect(Pose::Helpers.root_word("foo?")).to eq ['foo']
103
+ expect(Pose::Helpers.root_word("foo!")).to eq ['foo']
104
+ expect(Pose::Helpers.root_word("foo/bar")).to eq ['foo', 'bar']
105
+ expect(Pose::Helpers.root_word("foo-bar")).to eq ['foo', 'bar']
106
+ expect(Pose::Helpers.root_word("foo--bar")).to eq ['foo', 'bar']
107
+ expect(Pose::Helpers.root_word("foo.bar")).to eq ['foo', 'bar']
108
+ end
109
+
110
+ it 'removes umlauts' do
111
+ expect(Pose::Helpers.root_word('fünf')).to eq ['funf']
112
+ end
113
+
114
+ it 'splits up numbers' do
115
+ expect(Pose::Helpers.root_word('11.2.2011')).to eq ['11', '2', '2011']
116
+ expect(Pose::Helpers.root_word('11-2-2011')).to eq ['11', '2', '2011']
117
+ expect(Pose::Helpers.root_word('30:4-5')).to eq ['30', '4', '5']
118
+ end
119
+
120
+ it 'converts into lowercase' do
121
+ expect(Pose::Helpers.root_word('London')).to eq ['london']
122
+ end
123
+
124
+ it "stores single-letter words" do
125
+ expect(Pose::Helpers.root_word('a b')).to eq ['a', 'b']
126
+ end
127
+
128
+ it "does't encode external URLs" do
129
+ expect(Pose::Helpers.root_word('http://web.com')).to eq ['http', 'web', 'com']
130
+ end
131
+
132
+ it "doesn't store empty words" do
133
+ expect(Pose::Helpers.root_word(' one two ')).to eq ['one', 'two']
134
+ end
135
+
136
+ it "removes duplicates" do
137
+ expect(Pose::Helpers.root_word('one_one')).to eq ['one']
138
+ expect(Pose::Helpers.root_word('one one')).to eq ['one']
139
+ end
140
+
141
+ it "splits up complex URLs" do
142
+ expect(Pose::Helpers.root_word('books?id=p7uyWPcVGZsC&dq=closure%20definitive%20guide&pg=PP1#v=onepage&q&f=false')).to eql([
143
+ "book", "id", "p7uywpcvgzsc", "dq", "closure", "definitive", "guide", "pg", "pp1", "v", "onepage", "q", "f", "false"])
144
+ end
145
+ end
146
+
147
+ end
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ module Pose
5
+
6
+ describe Query do
7
+
8
+ let(:subject) { Pose::Query.new [PosableOne, [PosableTwo]], 'query string' }
9
+
10
+ describe :initialize do
11
+
12
+ it 'flattens the given classes' do
13
+ expect(subject.classes).to eql [PosableOne, PosableTwo]
14
+ end
15
+ end
16
+
17
+ describe :class_names do
18
+
19
+ it 'returns the names of the given classes' do
20
+ expect(subject.class_names).to eql ['PosableOne', 'PosableTwo']
21
+ end
22
+ end
23
+
24
+
25
+ describe :has_joins? do
26
+ it 'returns TRUE if the query has joins' do
27
+ query = Query.new [], '', joins: :user
28
+ expect(query).to have_joins
29
+ end
30
+
31
+ it 'returns FALSE if the query has no joins' do
32
+ query = Query.new [], ''
33
+ expect(query).to_not have_joins
34
+ end
35
+ end
36
+
37
+ describe :joins do
38
+
39
+ it 'returns the given joins' do
40
+ query = Query.new [], '', joins: [:foo, :bar]
41
+ expect(query.joins).to eql [:foo, :bar]
42
+ end
43
+
44
+ it 'returns the given join as an array' do
45
+ query = Query.new [], '', joins: :foo
46
+ expect(query.joins).to eql [:foo]
47
+ end
48
+
49
+ it 'returns an empty array if no joins are given' do
50
+ query = Query.new [], ''
51
+ expect(query.joins).to eql []
52
+ end
53
+ end
54
+
55
+ describe :query_words do
56
+
57
+ it 'returns all individual words resulting from the given query' do
58
+ expect(Pose::Query.new([], 'foo bar').query_words).to eq ['foo', 'bar']
59
+ end
60
+
61
+ it 'converts the individual words into their root form' do
62
+ expect(Pose::Query.new([], 'bars').query_words).to eq ['bar']
63
+ end
64
+
65
+ it 'splits complex words into separate terms' do
66
+ expect(Pose::Query.new([], 'one-two').query_words).to eq ['one', 'two']
67
+ end
68
+
69
+ it 'removes duplicates' do
70
+ expect(Pose::Query.new([], 'foo-bar foo').query_words).to eq ['foo', 'bar']
71
+ end
72
+ end
73
+
74
+ describe :where do
75
+
76
+ it 'returns the given simple WHERE clause as an iterable array' do
77
+ query = Query.new [], '', where: ['foo = ?', false]
78
+ expect(query.where).to eq [['foo = ?', false]]
79
+ end
80
+
81
+ it 'returns the given multiple WHERE clauses as given' do
82
+ query = Query.new [], '', where: [ ['foo = ?', false], ['bar = ?', true] ]
83
+ expect(query.where).to eq [ ['foo = ?', false], ['bar = ?', true] ]
84
+ end
85
+
86
+ it 'returns the given multiple string WHERE clauses as given' do
87
+ query = Query.new [], '', where: [ ['foo = 1'], ['bar = 2'] ]
88
+ expect(query.where).to eq [ ['foo = 1'], ['bar = 2'] ]
89
+ end
90
+
91
+ it 'returns an empty array if no where clause is given' do
92
+ query = Query.new [], ''
93
+ expect(query.where).to eq []
94
+ end
95
+
96
+ it 'returns the given hash clause as it is given' do
97
+ query = Query.new [], '', where: { foo: 'foo' }
98
+ expect(query.where).to eql({ foo: 'foo' })
99
+ end
100
+
101
+ it 'returns multiple hash clauses as given' do
102
+ query = Query.new [], '', where: [{ foo: 'foo' }, { bar: 'bar' }]
103
+ expect(query.where).to eql [{ foo: 'foo' }, {bar: 'bar'}]
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,360 @@
1
+ require "spec_helper"
2
+
3
+ module Pose
4
+
5
+ describe Search do
6
+ let(:subject) { Search.new [PosableOne, [PosableTwo]], 'query string' }
7
+ let(:arel) { stub() }
8
+ let(:arel_2) { stub() }
9
+ let(:arel_3) { stub() }
10
+
11
+
12
+ describe :add_join do
13
+
14
+ it 'returns the new arel' do
15
+ arel.should_receive(:joins).with('foo').and_return(arel_2)
16
+ expect(subject.add_join arel, 'foo').to eql arel_2
17
+ end
18
+
19
+ context 'given a class' do
20
+ it 'adds a join from PoseAssignment to the given class' do
21
+ arel.should_receive(:joins)
22
+ .with "INNER JOIN posable_ones ON pose_assignments.posable_id=posable_ones.id AND pose_assignments.posable_type='PosableOne'"
23
+ subject.add_join arel, PosableOne
24
+ end
25
+ end
26
+
27
+ context 'given a string' do
28
+ it 'applies the join as given' do
29
+ arel.should_receive(:joins).with "join string"
30
+ subject.add_join arel, 'join string'
31
+ end
32
+ end
33
+
34
+ context 'given a symbol' do
35
+ it 'applies the join as given' do
36
+ arel.should_receive(:joins).with :association
37
+ subject.add_join arel, :association
38
+ end
39
+ end
40
+ end
41
+
42
+
43
+ describe :add_joins do
44
+
45
+ it 'adds all joins to the given arel' do
46
+ arel.should_receive(:joins).with('one').and_return(arel_2)
47
+ arel_2.should_receive(:joins).with('two').and_return(arel_3)
48
+ search = Search.new nil, nil, joins: ['one', 'two']
49
+ search.add_joins arel
50
+ end
51
+
52
+ it 'returns the given arel' do
53
+ arel.should_receive(:joins).and_return(arel_2)
54
+ arel_2.should_receive(:joins).and_return(arel_3)
55
+ search = Search.new nil, nil, joins: ['one', 'two']
56
+ expect(search.add_joins arel).to eql arel_3
57
+ end
58
+ end
59
+
60
+
61
+ describe :add_wheres do
62
+
63
+ it 'adds all joins to the given arel' do
64
+ arel.should_receive(:where).with(['one = ?', true]).and_return(arel_2)
65
+ arel_2.should_receive(:where).with(['two = ?', false]).and_return(arel_3)
66
+ search = Search.new nil, nil, where: [['one = ?', true], ['two = ?', false]]
67
+ search.add_wheres arel
68
+ end
69
+
70
+ it 'returns the given arel' do
71
+ arel.should_receive(:where).and_return(arel_2)
72
+ arel_2.should_receive(:where).and_return(arel_3)
73
+ search = Search.new nil, nil, where: [['one'], ['two']]
74
+ expect(search.add_wheres arel).to eql arel_3
75
+ end
76
+ end
77
+
78
+
79
+ describe :empty_result do
80
+
81
+ it 'returns a hash with classes and empty arrays for each class in the search query' do
82
+ search = Search.new [PosableOne, PosableTwo], ''
83
+ result = search.empty_result
84
+ expect(result['PosableOne']).to eq []
85
+ expect(result['PosableTwo']).to eq []
86
+ expect(result).to_not have_key 'User'
87
+ end
88
+ end
89
+
90
+
91
+ describe :limit_ids do
92
+ before :each do
93
+ @search = Search.new nil, nil, limit: 2
94
+ end
95
+
96
+ context 'with empty id set' do
97
+ it 'does nothing' do
98
+ result = { PosableOne => [] }
99
+ @search.limit_ids result
100
+ expect(result[PosableOne]).to eql []
101
+ end
102
+ end
103
+
104
+ context 'with id set less than the given limit' do
105
+ it 'does nothing' do
106
+ result = { PosableOne => [1, 2] }
107
+ @search.limit_ids result
108
+ expect(result[PosableOne]).to eql [1, 2]
109
+ end
110
+ end
111
+
112
+ context 'with id set longer than the given limit' do
113
+ it 'truncates the id set' do
114
+ result = { PosableOne => [1, 2, 3] }
115
+ @search.limit_ids result
116
+ expect(result[PosableOne]).to eql [1, 2]
117
+ end
118
+ end
119
+
120
+ context 'without limit in query' do
121
+ it 'does nothing' do
122
+ @search = Search.new nil, nil
123
+ result = { PosableOne => [1, 2, 3] }
124
+ @search.limit_ids result
125
+ expect(result[PosableOne]).to eql [1, 2, 3]
126
+ end
127
+ end
128
+ end
129
+
130
+
131
+ describe :load_classes do
132
+
133
+ context 'when the user wants ids' do
134
+ it 'does nothing' do
135
+ search = Search.new nil, nil, result_type: :ids
136
+ result = { PosableOne => [1, 2] }
137
+ search.load_classes @result
138
+ expect(result[PosableOne]).to eql [1, 2]
139
+ end
140
+ end
141
+
142
+ context 'when the user wants classes' do
143
+ it 'loads the classes' do
144
+ object_1 = create :posable_one
145
+ object_2 = create :posable_one
146
+ result = { PosableOne => [1, 2] }
147
+ search = Search.new nil, nil
148
+ search.load_classes result
149
+ expect(result[PosableOne]).to eq [object_1, object_2]
150
+ end
151
+ end
152
+ end
153
+
154
+
155
+ describe :merge_search_result_word_matches do
156
+ context 'given a new class name' do
157
+
158
+ before :each do
159
+ @result = {}
160
+ end
161
+
162
+ it 'sets the given ids as the ids for this class name' do
163
+ subject.merge_search_result_word_matches @result, 'class1', [1, 2]
164
+ expect(@result).to eq({ 'class1' => [1, 2] })
165
+ end
166
+ end
167
+
168
+ context 'given a class name with already existing ids from another word' do
169
+
170
+ before :each do
171
+ @result = { 'class1' => [1, 2] }
172
+ end
173
+
174
+ it 'only keeps the ids that are included in both sets' do
175
+ subject.merge_search_result_word_matches @result, 'class1', [1, 3]
176
+ expect(@result).to eq({ 'class1' => [1] })
177
+ end
178
+ end
179
+
180
+ context 'with an existing empty result set from a previous query' do
181
+
182
+ before :each do
183
+ @result = { 'class1' => [] }
184
+ end
185
+
186
+ it 'returns an empty result set' do
187
+ subject.merge_search_result_word_matches @result, 'class1', [1, 3]
188
+ @result.should eq({ 'class1' => [] })
189
+ end
190
+ end
191
+
192
+ context 'with a new empty result set' do
193
+
194
+ before :each do
195
+ @result = { 'class1' => [1, 2] }
196
+ end
197
+
198
+ it 'returns an empty result set' do
199
+ subject.merge_search_result_word_matches @result, 'class1', []
200
+ @result.should eq({ 'class1' => [] })
201
+ end
202
+ end
203
+
204
+ context 'with a completely different result set' do
205
+
206
+ before :each do
207
+ @result = { 'class1' => [1, 2] }
208
+ end
209
+
210
+ it 'returns an empty result set' do
211
+ subject.merge_search_result_word_matches @result, 'class1', [3, 4]
212
+ @result.should eq({ 'class1' => [] })
213
+ end
214
+ end
215
+ end
216
+
217
+
218
+ describe :search do
219
+
220
+ it 'finds all matching instances of all classes' do
221
+ posable_one_1 = create :posable_one, text: 'foo bar'
222
+ posable_one_2 = create :posable_one, text: 'foo bar'
223
+ posable_one_3 = create :posable_one, text: 'foo'
224
+ posable_two_1 = create :posable_two, text: 'foo bar'
225
+ posable_two_2 = create :posable_two, text: 'bar'
226
+ search = Search.new [PosableOne, PosableTwo], 'foo bar'
227
+ result = search.search
228
+ expect(result[PosableOne]).to eq [posable_one_1, posable_one_2]
229
+ end
230
+
231
+ it 'searches through all given classes' do
232
+ posable_one = create :posable_one, text: 'foo'
233
+ posable_two = create :posable_two, text: 'foo'
234
+ search = Search.new [PosableOne, PosableTwo], 'foo'
235
+ result = search.search
236
+ expect(result[PosableOne]).to eq [posable_one]
237
+ expect(result[PosableTwo]).to eq [posable_two]
238
+ end
239
+
240
+ it 'searches through all given search words' do
241
+ posable_one_1 = create :posable_one, text: 'foo bar'
242
+ posable_one_2 = create :posable_one, text: 'foo'
243
+ posable_one_3 = create :posable_one, text: 'bar'
244
+ search = Search.new PosableOne, 'foo bar'
245
+ result = search.search
246
+ expect(result[PosableOne]).to eq [posable_one_1]
247
+ end
248
+
249
+ it 'limits the number of search results to the given limit' do
250
+ posable_one_1 = create :posable_one, text: 'foo'
251
+ posable_one_2 = create :posable_one, text: 'foo'
252
+ search = Search.new PosableOne, 'foo', limit: 1
253
+ result = search.search
254
+ expect(result[PosableOne]).to have(1).items
255
+ end
256
+
257
+ describe 'result types' do
258
+
259
+ it 'loads classes by default' do
260
+ posable_one = create :posable_one, text: 'foo'
261
+ search = Search.new PosableOne, 'foo'
262
+ result = search.search
263
+ expect(result[PosableOne]).to eq [posable_one]
264
+ end
265
+
266
+ context 'result_type: :ids parameter' do
267
+ it 'returns only the ids of the parameters' do
268
+ posable_one = create :posable_one, text: 'foo'
269
+ search = Search.new PosableOne, 'foo', result_type: :ids
270
+ result = search.search
271
+ expect(result[PosableOne]).to eql [posable_one.id]
272
+ end
273
+ end
274
+ end
275
+
276
+ context 'given joins and wheres' do
277
+ it 'limits the search by the given joins and wheres' do
278
+ user_1 = create :user, name: 'user one'
279
+ user_2 = create :user, name: 'user two'
280
+ posable_one_1 = create :posable_one, user: user_1, text: 'foo'
281
+ posable_one_2 = create :posable_one, user: user_2, text: 'foo'
282
+ search = Search.new PosableOne,
283
+ 'foo',
284
+ joins: [ PosableOne,
285
+ 'INNER JOIN users ON posable_ones.user_id=users.id' ],
286
+ where: ['users.name=?', 'user one']
287
+ result = search.search
288
+ expect(result[PosableOne]).to eq [posable_one_1]
289
+ end
290
+ end
291
+ end
292
+
293
+
294
+ describe :search_word do
295
+
296
+ context 'search results' do
297
+ it 'returns the ids of the matching instances for this class' do
298
+ posable_one_1 = create :posable_one, text: 'foo'
299
+ posable_one_2 = create :posable_one, text: 'foo'
300
+ search = Search.new PosableOne, nil
301
+ result = search.search_word 'foo'
302
+ expect(result['PosableOne']).to include posable_one_1.id, posable_one_2.id
303
+ end
304
+ end
305
+
306
+ context 'no search results' do
307
+ it 'returns an empty array for the class' do
308
+ search = Search.new PosableOne, nil
309
+ result = search.search_word 'foo'
310
+ expect(result['PosableOne']).to eql []
311
+ end
312
+ end
313
+
314
+ context 'multiple classes to search over' do
315
+ it 'returns results for all classes' do
316
+ posable_one_1 = create :posable_one, text: 'foo'
317
+ posable_two_1 = create :posable_two, text: 'foo'
318
+ search = Search.new [PosableOne, PosableTwo], nil
319
+ result = search.search_word 'foo'
320
+ expect(result['PosableOne']).to include posable_one_1.id
321
+ expect(result['PosableTwo']).to include posable_two_1.id
322
+ end
323
+ end
324
+ end
325
+
326
+
327
+ describe :search_words do
328
+
329
+ context 'search results' do
330
+ it 'returns the ids of all instances that match all query words' do
331
+ posable_one = create :posable_one, text: 'foo bar'
332
+ search = Search.new PosableOne, 'foo bar'
333
+ result = search.search_words
334
+ expect(result['PosableOne']).to eq [posable_one.id]
335
+ end
336
+ end
337
+
338
+ context 'instance matches only one query word' do
339
+ it 'does not return this instance' do
340
+ posable_one_1 = create :posable_one, text: 'foo'
341
+ posable_one_2 = create :posable_one, text: 'bar'
342
+ search = Search.new PosableOne, 'foo bar'
343
+ result = search.search_words
344
+ expect(result['PosableOne']).to eq []
345
+ end
346
+ end
347
+
348
+ context 'multiple classes to search over' do
349
+ it 'returns all matching instances from all classes' do
350
+ posable_one = create :posable_one, text: 'foo bar'
351
+ posable_two = create :posable_two, text: 'foo bar'
352
+ search = Search.new [PosableOne, PosableTwo], 'foo bar'
353
+ result = search.search_words
354
+ expect(result['PosableOne']).to eq [posable_one.id]
355
+ expect(result['PosableTwo']).to eq [posable_two.id]
356
+ end
357
+ end
358
+ end
359
+ end
360
+ end