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 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