picky-client 0.0.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.
- data/README.textile +3 -0
- data/lib/search-engine.rb +10 -0
- data/lib/search/convenience.rb +37 -0
- data/lib/search/engine.rb +96 -0
- data/lib/search/serializer.rb +25 -0
- data/spec/search/convenience_spec.rb +113 -0
- data/spec/search/engine_spec.rb +184 -0
- data/spec/search/serializer_spec.rb +39 -0
- metadata +73 -0
data/README.textile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
$KCODE = 'UTF-8' unless RUBY_VERSION > '1.8.7'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
require 'active_support'
|
6
|
+
|
7
|
+
this = File.dirname __FILE__
|
8
|
+
require File.join(this, '/search/engine')
|
9
|
+
require File.join(this, '/search/serializer')
|
10
|
+
require File.join(this, '/search/convenience')
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Search
|
2
|
+
# Use this class to extend the hash the serializer returns.
|
3
|
+
#
|
4
|
+
module Convenience
|
5
|
+
|
6
|
+
# Are there any allocations?
|
7
|
+
#
|
8
|
+
def empty?
|
9
|
+
allocations.empty?
|
10
|
+
end
|
11
|
+
# Returns the topmost limit results.
|
12
|
+
#
|
13
|
+
def ids limit = 20
|
14
|
+
ids = []
|
15
|
+
allocations.each { |allocation| allocation[4].each { |id| break if ids.size > limit; ids << id } }
|
16
|
+
ids
|
17
|
+
end
|
18
|
+
# Removes the ids from each allocation.
|
19
|
+
#
|
20
|
+
def clear_ids
|
21
|
+
allocations.each { |allocation| allocation[4].clear }
|
22
|
+
end
|
23
|
+
|
24
|
+
# Caching readers.
|
25
|
+
#
|
26
|
+
def allocations
|
27
|
+
@allocations || @allocations = self[:allocations]
|
28
|
+
end
|
29
|
+
def allocations_size
|
30
|
+
@allocations_size || @allocations_size = allocations.size
|
31
|
+
end
|
32
|
+
def total
|
33
|
+
@total || @total = self[:total]
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Search
|
4
|
+
# Frontend for the search client.
|
5
|
+
#
|
6
|
+
# Configure a search by passing the options in the initializer:
|
7
|
+
# * host
|
8
|
+
# * port
|
9
|
+
# * path
|
10
|
+
#
|
11
|
+
# TODO Rewrite such that instead of an http request we connect through tcp.
|
12
|
+
# Or use EventMachine.
|
13
|
+
#
|
14
|
+
module Engine
|
15
|
+
|
16
|
+
class Base
|
17
|
+
|
18
|
+
attr_accessor :host, :port, :path
|
19
|
+
|
20
|
+
def initialize options = {}
|
21
|
+
options = default_configuration.merge options
|
22
|
+
|
23
|
+
@host = options[:host]
|
24
|
+
@port = options[:port]
|
25
|
+
@path = options[:path]
|
26
|
+
end
|
27
|
+
def default_configuration
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
def self.default_configuration options = {}
|
31
|
+
define_method :default_configuration do
|
32
|
+
options
|
33
|
+
end
|
34
|
+
end
|
35
|
+
def default_params
|
36
|
+
{}
|
37
|
+
end
|
38
|
+
def self.default_params options = {}
|
39
|
+
options.stringify_keys! if options.respond_to?(:stringify_keys!)
|
40
|
+
define_method :default_params do
|
41
|
+
options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Merges the given params, overriding the defaults.
|
46
|
+
#
|
47
|
+
def defaultize params = {}
|
48
|
+
default_params.merge params
|
49
|
+
end
|
50
|
+
|
51
|
+
# Searches the index. Use this method.
|
52
|
+
#
|
53
|
+
# Returns a hash. Extend with Convenience.
|
54
|
+
#
|
55
|
+
def search params = {}
|
56
|
+
return {} if params[:query].blank?
|
57
|
+
|
58
|
+
send_search params
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sends a search to the configured address.
|
62
|
+
#
|
63
|
+
def send_search params = {}
|
64
|
+
params = defaultize params
|
65
|
+
Net::HTTP.get self.host, "#{self.path}?#{params.to_query}", self.port
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
class Full < Base
|
71
|
+
default_configuration :host => 'localhost', :port => 4000, :path => '/searches/full'
|
72
|
+
|
73
|
+
# Full needs to deserialize the results.
|
74
|
+
#
|
75
|
+
def send_search params = {}
|
76
|
+
Serializer.deserialize super(params)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
class Live < Base
|
82
|
+
default_configuration :host => 'localhost', :port => 4000, :path => '/searches/live'
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Extend hash with to_query method.
|
89
|
+
#
|
90
|
+
class Hash
|
91
|
+
def to_query namespace = nil
|
92
|
+
collect do |key, value|
|
93
|
+
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
|
94
|
+
end.sort * '&'
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Search
|
2
|
+
|
3
|
+
# This class handles serialization and deserialization.
|
4
|
+
#
|
5
|
+
class Serializer
|
6
|
+
|
7
|
+
# Serialize the Results.
|
8
|
+
#
|
9
|
+
# Note: This code is executed on the search engine side.
|
10
|
+
#
|
11
|
+
def self.serialize serializable_results
|
12
|
+
Marshal.dump serializable_results.serialize
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create new search results from serialized ones.
|
16
|
+
#
|
17
|
+
# Note: This code is executed on the client side.
|
18
|
+
#
|
19
|
+
def self.deserialize serialized_results
|
20
|
+
Marshal.load serialized_results
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Search::Convenience do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@convenience = {
|
7
|
+
:allocations => [[nil, nil, nil, nil, [1,2,3,4,5,6,7,8]],
|
8
|
+
[nil, nil, nil, nil, [9,10,11,12,13,14,15,16]],
|
9
|
+
[nil, nil, nil, nil, [17,18,19,20,21,22,23]]],
|
10
|
+
:offset => 123,
|
11
|
+
:total => 12345,
|
12
|
+
:duration => 0.12345
|
13
|
+
}.extend Search::Convenience
|
14
|
+
end
|
15
|
+
|
16
|
+
# describe 'replace_ids_with' do
|
17
|
+
# before(:each) do
|
18
|
+
# @results = Search::Results.new [
|
19
|
+
# [nil, nil, nil, [1,2,3,4,5,6,7,8]],
|
20
|
+
# [nil, nil, nil, [9,10,11,12,13,14,15,16]],
|
21
|
+
# [nil, nil, nil, [17,18,19,20,21,22,23]]
|
22
|
+
# ], [], nil, 123, true, true, 0.123, 1234
|
23
|
+
# end
|
24
|
+
# it 'should replace the ids' do
|
25
|
+
# new_ids = (11..31).to_a # +10
|
26
|
+
# @results.replace_ids_with new_ids
|
27
|
+
# @results.ids.should == (11..31).to_a
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
|
31
|
+
describe 'clear_ids' do
|
32
|
+
it 'should clear all ids' do
|
33
|
+
@convenience.clear_ids
|
34
|
+
|
35
|
+
@convenience.ids.should == []
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'ids' do
|
40
|
+
it 'should return the top default ids' do
|
41
|
+
@convenience.ids.should == (1..21).to_a
|
42
|
+
end
|
43
|
+
it 'should return the top limit entries' do
|
44
|
+
@convenience.ids(7).should == (1..8).to_a
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'allocations_size' do
|
49
|
+
it 'should just add up the allocations of both types' do
|
50
|
+
@convenience.allocations_size.should == 3
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# describe 'render?' do
|
55
|
+
# context 'no ids' do
|
56
|
+
# before(:each) do
|
57
|
+
# @convenience.stub! :empty? => true
|
58
|
+
# end
|
59
|
+
# it 'should not render' do
|
60
|
+
# @convenience.render?.should == false
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
# context 'less results than the treshold' do
|
64
|
+
# before(:each) do
|
65
|
+
# @convenience.stub! :empty? => false
|
66
|
+
# @convenience.stub! :total => 7
|
67
|
+
# end
|
68
|
+
# it 'should render' do
|
69
|
+
# @convenience.render?.should == true
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
# context 'too many, but just in one allocation' do
|
73
|
+
# before(:each) do
|
74
|
+
# @convenience.stub! :empty? => false
|
75
|
+
# @convenience.stub! :total => 100
|
76
|
+
# @convenience.stub! :allocations_size => 1
|
77
|
+
# end
|
78
|
+
# it 'should render' do
|
79
|
+
# @convenience.render?.should == true
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# context 'too many' do
|
83
|
+
# before(:each) do
|
84
|
+
# @convenience.stub! :empty? => false
|
85
|
+
# @convenience.stub! :total => 100
|
86
|
+
# @convenience.stub! :allocations_size => 2
|
87
|
+
# end
|
88
|
+
# it 'should not render' do
|
89
|
+
# @convenience.render?.should == false
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
|
94
|
+
describe 'empty?' do
|
95
|
+
context 'allocations empty' do
|
96
|
+
before(:each) do
|
97
|
+
@convenience.stub! :allocations => stub(:allocations, :empty? => true)
|
98
|
+
end
|
99
|
+
it 'should be true' do
|
100
|
+
@convenience.empty?.should == true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
context 'allocations not empty' do
|
104
|
+
before(:each) do
|
105
|
+
@convenience.stub! :allocations => stub(:allocations, :empty? => false)
|
106
|
+
end
|
107
|
+
it 'should be false' do
|
108
|
+
@convenience.empty?.should == false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Search::Engine do
|
4
|
+
|
5
|
+
describe 'defaultize' do
|
6
|
+
context 'no default params' do
|
7
|
+
before(:each) do
|
8
|
+
@base = Search::Engine::Base.new
|
9
|
+
end
|
10
|
+
it 'should return unchanged' do
|
11
|
+
@base.defaultize( :a => :b ).should == { :a => :b }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
context 'default params' do
|
15
|
+
before(:each) do
|
16
|
+
Search::Engine::Base.default_params 'c' => 'd'
|
17
|
+
@base = Search::Engine::Base.new
|
18
|
+
end
|
19
|
+
after(:each) do
|
20
|
+
Search::Engine::Base.default_params
|
21
|
+
end
|
22
|
+
it 'should return changed' do
|
23
|
+
@base.defaultize( 'a' => 'b' ).should == { 'a' => 'b', 'c' => 'd' }
|
24
|
+
end
|
25
|
+
it 'should override the default' do
|
26
|
+
@base.defaultize( 'c' => 'b' ).should == { 'c' => 'b' }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'Base' do
|
32
|
+
before(:each) do
|
33
|
+
@base = Search::Engine::Base.new
|
34
|
+
end
|
35
|
+
it 'should have a default_configuration method' do
|
36
|
+
lambda { @base.default_configuration }.should_not raise_error
|
37
|
+
end
|
38
|
+
it 'should return an empty configuration hash' do
|
39
|
+
@base.default_configuration.should == {}
|
40
|
+
end
|
41
|
+
it 'should have a default_params method' do
|
42
|
+
lambda { @base.default_params }.should_not raise_error
|
43
|
+
end
|
44
|
+
it 'should return an empty params hash' do
|
45
|
+
@base.default_params.should == {}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "Full" do
|
50
|
+
before(:each) do
|
51
|
+
@full = Search::Engine::Full.new
|
52
|
+
end
|
53
|
+
describe "defaults" do
|
54
|
+
it "should set host to 'localhost'" do
|
55
|
+
@full.host.should == 'localhost'
|
56
|
+
end
|
57
|
+
it "should set port to 4000" do
|
58
|
+
@full.port.should == 4000
|
59
|
+
end
|
60
|
+
it "should set path to '/searches/full'" do
|
61
|
+
@full.path.should == '/searches/full'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "cattr_accessors" do
|
66
|
+
before(:each) do
|
67
|
+
@full = Search::Engine::Full.new :host => :some_host, :port => :some_port, :path => :some_path
|
68
|
+
end
|
69
|
+
it "should have a writer for the host" do
|
70
|
+
@full.host = :some_host
|
71
|
+
@full.host.should == :some_host
|
72
|
+
end
|
73
|
+
it "should have a writer for the port" do
|
74
|
+
@full.port = :some_port
|
75
|
+
@full.port.should == :some_port
|
76
|
+
end
|
77
|
+
it "should have a writer for the path" do
|
78
|
+
@full.path = :some_path
|
79
|
+
@full.path.should == :some_path
|
80
|
+
end
|
81
|
+
it "should have a reader for the host" do
|
82
|
+
lambda { @full.host }.should_not raise_error
|
83
|
+
end
|
84
|
+
it "should have a reader for the port" do
|
85
|
+
lambda { @full.port }.should_not raise_error
|
86
|
+
end
|
87
|
+
it "should have a reader for the path" do
|
88
|
+
lambda { @full.path }.should_not raise_error
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "search" do
|
93
|
+
describe "with nil as search term" do
|
94
|
+
before(:each) do
|
95
|
+
@query = nil
|
96
|
+
end
|
97
|
+
it "should return a Search::Results for company" do
|
98
|
+
@full.search(:query => @query).should be_kind_of(Hash)
|
99
|
+
end
|
100
|
+
it "should return an empty Search::Results" do
|
101
|
+
@full.search(:query => @query).should be_empty
|
102
|
+
end
|
103
|
+
end
|
104
|
+
describe "with '' as search term" do
|
105
|
+
before(:each) do
|
106
|
+
@query = ''
|
107
|
+
end
|
108
|
+
it "should return a Search::Results for company" do
|
109
|
+
@full.search(:query => @query).should be_kind_of(Hash)
|
110
|
+
end
|
111
|
+
it "should return an empty Search::Results" do
|
112
|
+
@full.search(:query => @query).should be_empty
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "Live" do
|
119
|
+
before(:each) do
|
120
|
+
@live = Search::Engine::Live.new
|
121
|
+
end
|
122
|
+
describe "defaults" do
|
123
|
+
it "should set host to 'localhost'" do
|
124
|
+
@live.host.should == 'localhost'
|
125
|
+
end
|
126
|
+
it "should set port to 4000" do
|
127
|
+
@live.port.should == 4000
|
128
|
+
end
|
129
|
+
it "should set path to '/searches/live'" do
|
130
|
+
@live.path.should == '/searches/live'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "cattr_accessors" do
|
135
|
+
it "should have a writer for the host" do
|
136
|
+
@live.host = :some_host
|
137
|
+
@live.host.should == :some_host
|
138
|
+
end
|
139
|
+
it "should have a writer for the port" do
|
140
|
+
@live.port = :some_port
|
141
|
+
@live.port.should == :some_port
|
142
|
+
end
|
143
|
+
it "should have a writer for the path" do
|
144
|
+
@live.path = :some_path
|
145
|
+
@live.path.should == :some_path
|
146
|
+
end
|
147
|
+
it "should have a reader for the host" do
|
148
|
+
lambda { @live.host }.should_not raise_error
|
149
|
+
end
|
150
|
+
it "should have a reader for the port" do
|
151
|
+
lambda { @live.port }.should_not raise_error
|
152
|
+
end
|
153
|
+
it "should have a reader for the path" do
|
154
|
+
lambda { @live.path }.should_not raise_error
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "search" do
|
159
|
+
describe "with nil as search term" do
|
160
|
+
before(:each) do
|
161
|
+
@query = nil
|
162
|
+
end
|
163
|
+
it "should return a Search::Results" do
|
164
|
+
@live.search(:query => @query).should be_kind_of(Hash)
|
165
|
+
end
|
166
|
+
it "should return an empty Search::Results" do
|
167
|
+
@live.search(:query => @query).should be_empty
|
168
|
+
end
|
169
|
+
end
|
170
|
+
describe "with '' as search term" do
|
171
|
+
before(:each) do
|
172
|
+
@query = ''
|
173
|
+
end
|
174
|
+
it "should return a Search::Results" do
|
175
|
+
@live.search(:query => @query).should be_kind_of(Hash)
|
176
|
+
end
|
177
|
+
it "should return an empty Search::Results" do
|
178
|
+
@live.search(:query => @query).should be_empty
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Search::Serializer do
|
4
|
+
|
5
|
+
describe "serialize-deserialize" do
|
6
|
+
it "should serialize and deserialize certain values" do
|
7
|
+
results = stub :results
|
8
|
+
results.stub! :serialize => {}
|
9
|
+
|
10
|
+
deserialized = Search::Serializer.deserialize Search::Serializer.serialize(results)
|
11
|
+
|
12
|
+
deserialized.should == {}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "serialize" do
|
17
|
+
it "should serialize" do
|
18
|
+
results = stub :results, :serialize => {
|
19
|
+
:allocations => [[nil, nil, nil, [1,2,3,4,5,6,7,8]],
|
20
|
+
[nil, nil, nil, [9,10,11,12,13,14,15,16]],
|
21
|
+
[nil, nil, nil, [17,18,19,20,21,22,23]]],
|
22
|
+
:offset => 123,
|
23
|
+
:total => 12345,
|
24
|
+
:duration => 0.12345
|
25
|
+
}
|
26
|
+
|
27
|
+
Search::Serializer.serialize(results).should == "\x04\b{\t:\x10allocations[\b[\t000[\ri\x06i\ai\bi\ti\ni\vi\fi\r[\t000[\ri\x0Ei\x0Fi\x10i\x11i\x12i\x13i\x14i\x15[\t000[\fi\x16i\x17i\x18i\x19i\x1Ai\ei\x1C:\voffseti\x01{:\ntotali\x0290:\rdurationf\x0F0.12345\x00\xF2|"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "deserialize" do
|
32
|
+
it "should deserialize" do
|
33
|
+
results = Search::Serializer.deserialize "\x04\b{\t:\x10allocations[\b[\t000[\ri\x06i\ai\bi\ti\ni\vi\fi\r[\t000[\ri\x0Ei\x0Fi\x10i\x11i\x12i\x13i\x14i\x15[\t000[\fi\x16i\x17i\x18i\x19i\x1Ai\ei\x1C:\voffseti\x01{:\ntotali\x0290:\rdurationf\x0F0.12345\x00\xF2|"
|
34
|
+
|
35
|
+
results.should be_kind_of(Hash)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: picky-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 0.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Florian Hanke
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-08-10 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: florian.hanke+picky-client@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.textile
|
29
|
+
files:
|
30
|
+
- lib/search/convenience.rb
|
31
|
+
- lib/search/engine.rb
|
32
|
+
- lib/search/serializer.rb
|
33
|
+
- lib/search-engine.rb
|
34
|
+
- spec/search/convenience_spec.rb
|
35
|
+
- spec/search/engine_spec.rb
|
36
|
+
- spec/search/serializer_spec.rb
|
37
|
+
- README.textile
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://floere.github.com/picky
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.3.7
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: picky Search Engine Client
|
70
|
+
test_files:
|
71
|
+
- spec/search/convenience_spec.rb
|
72
|
+
- spec/search/engine_spec.rb
|
73
|
+
- spec/search/serializer_spec.rb
|