picky-client 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile ADDED
@@ -0,0 +1,3 @@
1
+ h1. Search engine client.
2
+
3
+ # TODO Usage etc.
@@ -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