dezi-client 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/lib/dezi/client.rb +262 -0
  2. data/lib/dezi/doc.rb +69 -0
  3. data/lib/dezi/response.rb +100 -0
  4. metadata +124 -0
@@ -0,0 +1,262 @@
1
+ # DeziClient is a Ruby client for the Dezi search platform.
2
+ #
3
+ # Copyright 2013 by Peter Karman
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ # dependencies
24
+ require 'rubygems'
25
+ require 'rest_client'
26
+ require 'uri'
27
+ require 'json'
28
+ require 'pathname'
29
+ require 'mime/types'
30
+
31
+ # related classes
32
+ require File.dirname(__FILE__) + '/response'
33
+ require File.dirname(__FILE__) + '/doc'
34
+
35
+ # DeziClient is a Ruby client for indexing and searching documents
36
+ # with the Dezi REST search platform. See http://dezi.org/ for details
37
+ # on the server.
38
+ #
39
+ # See the test/test_dezi_client.rb for full example.
40
+ #
41
+ # Usage:
42
+ #
43
+ # client = DeziClient.new(
44
+ # :server => 'http://localhost:5000',
45
+ # :username => 'foo',
46
+ # :password => 'secret',
47
+ # )
48
+ #
49
+ # doc = 'some/path/file.html'
50
+ # response = client.add(doc) # DeziResponse returned
51
+ # if !response.is_success
52
+ # raise "Failed to add #{doc} to server"
53
+ # end
54
+ #
55
+ # # if Dezi server has auto_commit==false
56
+ # # then must call commit()
57
+ # client.commit()
58
+ #
59
+ # response = client.search('q' => 'search string') # DeziResponse returned
60
+ # if !response.is_success
61
+ # raise "Failed to search"
62
+ # end
63
+ #
64
+ # response.results.each |result|
65
+ # puts "result: #{result.uri}"
66
+ # end
67
+ #
68
+ # Related classes: DeziResponse and DeziDoc
69
+ #
70
+
71
+ class DeziClient
72
+
73
+ # attributes
74
+ attr_accessor :server
75
+ attr_accessor :about_server
76
+ attr_accessor :search_uri
77
+ attr_accessor :index_uri
78
+ attr_accessor :commit_uri
79
+ attr_accessor :rollback_uri
80
+ attr_accessor :fields
81
+ attr_accessor :facets
82
+ attr_accessor :last_response
83
+ attr_accessor :debug
84
+ attr_accessor :user_agent
85
+
86
+ def version
87
+ return '1.0.0'
88
+ end
89
+
90
+ def initialize(args)
91
+ @debug = ENV['DEZI_DEBUG']
92
+
93
+ if (args.has_key? :server)
94
+ @server = args[:server]
95
+ else
96
+ @server = 'http://localhost:5000'
97
+ end
98
+
99
+ # sanity check
100
+ begin
101
+ uri = URI.parse(@server)
102
+ rescue URI::InvalidURIError => err
103
+ raise "Bad :server value " + err
104
+ end
105
+ if (!uri.host || !uri.port)
106
+ raise "Bad :server value " + @server
107
+ end
108
+
109
+ if (args.has_key? :username and args.has_key? :password)
110
+ @un = args[:username]
111
+ @pw = args[:password]
112
+ end
113
+
114
+ if (args.has_key? :user_agent)
115
+ @user_agent = args[:user_agent]
116
+ else
117
+ @user_agent = 'dezi-client-ruby/'+version()
118
+ end
119
+
120
+ if (args.has_key? :search and args.has_key? :index)
121
+ @search_uri = @server + args[:search]
122
+ @index_uri = @server + args[:index]
123
+ else
124
+ response = RestClient.get @server, :accept => :json, :user_agent => @user_agent
125
+
126
+ if response.code != 200
127
+ raise "Bad about response from server #{@server}: " . response.to_str
128
+ end
129
+
130
+ @about_server = JSON.parse(response.to_str)
131
+ if @debug
132
+ #puts @about_server.inspect
133
+ end
134
+
135
+ @search_uri = @about_server['search']
136
+ @index_uri = @about_server['index']
137
+ @commit_uri = @about_server['commit']
138
+ @rollback_uri = @about_server['rollback']
139
+ @fields = @about_server['fields']
140
+ @facets = @about_server['facets']
141
+ end
142
+
143
+ @searcher = RestClient::Resource.new( @search_uri )
144
+
145
+ end
146
+
147
+ private
148
+
149
+ def _put_doc(doc, uri=nil, content_type=nil)
150
+ body_buf = ""
151
+
152
+ if (doc.is_a?(DeziDoc))
153
+ body_buf = doc.as_string()
154
+ if (uri == nil)
155
+ uri = doc.uri
156
+ end
157
+ if (content_type == nil)
158
+ content_type = doc.mime_type
159
+ end
160
+
161
+ elsif (Pathname.new(doc).exist?)
162
+ file = File.new(doc, 'r')
163
+ body_buf = file.read()
164
+ if (uri == nil)
165
+ uri = doc
166
+ end
167
+
168
+ else
169
+ body_buf = doc
170
+ if (uri == nil)
171
+ raise "uri required"
172
+ end
173
+
174
+ end
175
+
176
+ if (!content_type or !content_type.length)
177
+ content_type = MIME::Types.type_for(uri)[0]
178
+ end
179
+
180
+ server_uri = '/' + uri
181
+ if (@debug)
182
+ puts "uri=#{uri}"
183
+ puts "body=#{body_buf}"
184
+ puts "content_type="#{content_type}"
185
+ end
186
+
187
+ resource = RestClient::Resource.new(@index_uri + server_uri, @un, @pw)
188
+ resp = resource.post( body_buf,
189
+ :accept => :json,
190
+ :content_type => content_type,
191
+ :user_agent => @user_agent
192
+ )
193
+
194
+ return DeziResponse.new(resp)
195
+ end
196
+
197
+ public
198
+
199
+ # add() takes an initial argument of "doc" which can be a DeziDoc object,
200
+ # a string representing a Pathname, or a string representing the content of a document.
201
+ # If "doc" represents the content of a document, additional arguments
202
+ # "uri" and "content_type" are required.
203
+
204
+ def add(doc, uri=nil, content_type=nil)
205
+ return _put_doc(doc, uri, content_type)
206
+ end
207
+
208
+ # update() takes an initial argument of "doc" which can be a DeziDoc object,
209
+ # a string representing a Pathname, or a string representing the content of a document.
210
+ # If "doc" represents the content of a document, additional arguments
211
+ # "uri" and "content_type" are required.
212
+
213
+ def update(doc, uri=nil, content_type=nil)
214
+ return _put_doc(doc, uri, content_type)
215
+ end
216
+
217
+ def delete(uri)
218
+ doc_uri = @index_uri + '/' + uri
219
+ resource = RestClient::Resource.new(doc_uri, @un, @pw)
220
+ resp = resource.delete(:accept => :json, :user_agent => @user_agent)
221
+ return DeziResponse.new(resp)
222
+ end
223
+
224
+ # commit() and rollback() are only relevant if the Dezi server
225
+ # has "auto_commit" turned off.
226
+
227
+ def commit()
228
+ ua = RestClient::Resource.new( @commit_uri, @un, @pw )
229
+ resp = ua.post('/', :accept => :json, :user_agent => @user_agent)
230
+ return DeziResponse.new(resp)
231
+ end
232
+
233
+ # commit() and rollback() are only relevant if the Dezi server
234
+ # has "auto_commit" turned off.
235
+
236
+ def rollback()
237
+ ua = RestClient::Resource.new( @rollback_uri, @un, @pw )
238
+ resp = ua.post('/', :accept => :json, :user_agent => @user_agent)
239
+ return DeziResponse.new(resp)
240
+ end
241
+
242
+ def search(params)
243
+ if (!params.has_key?("q"))
244
+ raise "'q' param required"
245
+ end
246
+
247
+ resp = @searcher.get(
248
+ :params => params,
249
+ :accept => :json,
250
+ :user_agent => @user_agent
251
+ )
252
+ dr = DeziResponse.new(resp)
253
+ if (!dr.is_success())
254
+ @last_response = dr
255
+ return false
256
+ else
257
+ return dr
258
+ end
259
+
260
+ end
261
+
262
+ end
@@ -0,0 +1,69 @@
1
+ # DeziDoc is part of a Ruby client for the Dezi search platform.
2
+ #
3
+ # Copyright 2013 by Peter Karman
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'rubygems'
24
+ require 'xmlsimple'
25
+
26
+ class DeziDoc
27
+
28
+ attr_accessor :mime_type
29
+ attr_accessor :summary
30
+ attr_accessor :title
31
+ attr_accessor :content
32
+ attr_accessor :uri
33
+ attr_accessor :mtime
34
+ attr_accessor :size
35
+ attr_accessor :score
36
+ attr_accessor :fields
37
+
38
+ def initialize(args)
39
+ @fields = {}
40
+ args.each {|k,v| send("#{k}=",v)}
41
+ end
42
+
43
+ def set_field(args)
44
+ args.each {|k,v| @fields[k] = v}
45
+ @mime_type = 'application/xml'
46
+ end
47
+
48
+ def get_field(fname)
49
+ if @fields.has_key?(fname)
50
+ return @fields[fname]
51
+ else
52
+ return nil
53
+ end
54
+ end
55
+
56
+ def as_string()
57
+ #puts "fields.length=" + @fields.length.to_s
58
+ if @fields.length > 0
59
+ return self.as_xml()
60
+ else
61
+ return @content
62
+ end
63
+ end
64
+
65
+ def as_xml()
66
+ return XmlSimple.xml_out(@fields, {'rootname' => 'doc', 'noattr' => true})
67
+ end
68
+
69
+ end
@@ -0,0 +1,100 @@
1
+ # DeziResponse is part of a Ruby client for the Dezi search platform.
2
+ #
3
+ # Copyright 2013 by Peter Karman
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'rubygems'
24
+ require 'json'
25
+
26
+ class DeziResponse
27
+
28
+ # most attributes are assigned dynamically in initialize().
29
+ # Try:
30
+ #
31
+ # puts response.inspect
32
+ #
33
+ # to see them.
34
+
35
+ attr_accessor :results
36
+
37
+ def initialize(http_resp)
38
+ @http_resp = http_resp
39
+
40
+ #warn http_resp.headers.inspect
41
+ #warn "code=" + http_resp.code.to_s
42
+
43
+ @is_ok = false
44
+ if (http_resp.code.to_s =~ /^2\d\d/)
45
+ @is_ok = true
46
+ end
47
+
48
+ if (!@is_ok)
49
+ return
50
+ end
51
+
52
+ #warn "is_ok=#{@is_ok}"
53
+
54
+ body = JSON.parse(http_resp.to_s)
55
+
56
+ #warn body.inspect
57
+
58
+ # set body keys as attributes in the object
59
+ body.each {|k,v|
60
+
61
+ # results are special
62
+ if k == 'results'
63
+ next
64
+ end
65
+
66
+ # create the attribute
67
+ self.instance_eval { class << self; self end }.send(:attr_accessor, k)
68
+
69
+ # assign the value
70
+ send("#{k}=",v)
71
+ }
72
+
73
+ if !body.has_key?('results')
74
+ return
75
+ end
76
+
77
+ # make each result Hash into a DeziDoc object
78
+ @results = []
79
+ body['results'].each {|r|
80
+ result = r
81
+ result['fields'] = {}
82
+ @fields.each {|f|
83
+ result['fields'][f] = r.delete(f)
84
+ }
85
+
86
+ doc = DeziDoc.new(result)
87
+ @results.push(doc)
88
+ }
89
+
90
+ end
91
+
92
+ def status()
93
+ return @http_resp.code.to_s
94
+ end
95
+
96
+ def is_success()
97
+ return @is_ok
98
+ end
99
+
100
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dezi-client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Peter Karman
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-01-08 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rest-client
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: json
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: mime-types
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: xml-simple
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :runtime
76
+ version_requirements: *id004
77
+ description: Ruby client for the Dezi search engine. See http://dezi.org/
78
+ email: karpet@dezi.org
79
+ executables: []
80
+
81
+ extensions: []
82
+
83
+ extra_rdoc_files: []
84
+
85
+ files:
86
+ - lib/dezi/client.rb
87
+ - lib/dezi/doc.rb
88
+ - lib/dezi/response.rb
89
+ has_rdoc: true
90
+ homepage: https://github.com/karpet/dezi-client-ruby
91
+ licenses: []
92
+
93
+ post_install_message:
94
+ rdoc_options: []
95
+
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ requirements: []
117
+
118
+ rubyforge_project: nowarning
119
+ rubygems_version: 1.3.7
120
+ signing_key:
121
+ specification_version: 3
122
+ summary: Ruby client for the Dezi search engine
123
+ test_files: []
124
+