dezi-client 1.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.
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
+