woodwing_elvis 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ module WoodWing
2
+ class Elvis
3
+ module Rest
4
+
5
+
6
+ # https://elvis.tenderapp.com/kb/api/rest-create_relation
7
+ def create_relation(options={})
8
+ url = base_url + "create_relation"
9
+ response = get_response(url, options)
10
+ end # create_relation
11
+
12
+
13
+ # https://elvis.tenderapp.com/kb/api/rest-remove_relation
14
+ def remove_relation(options={})
15
+ url = base_url + "remove_relation"
16
+ response = get_response(url, options)
17
+ end # remove_relation
18
+
19
+ alias :delete_relation :remove_relation
20
+
21
+
22
+ end # module Rest
23
+ end # class Elvis
24
+ end # module WoodWing
@@ -0,0 +1,156 @@
1
+ module WoodWing
2
+ class Elvis
3
+ module Rest
4
+
5
+
6
+ # https://elvis.tenderapp.com/kb/api/rest-search
7
+ # Search assets in Elvis using all of the powerful search functions provided
8
+ # by the Elvis search engine. You can execute all possible queries and even
9
+ # use faceted search.
10
+ #
11
+ # Returned information can be formatted as JSON, XML or HTML to support any
12
+ # kind of environment for clients.
13
+ #
14
+ # Apart from all sorts of metadata about the assets, the results returned
15
+ # by a search call also contain ready-to-use URLs to the thumbnail, preview
16
+ # and original file. This makes it extremely easy to display rich visual results.
17
+ #
18
+ # http://yourserver.com/services/search
19
+ # ?q=<query>
20
+ # &start=<first result>
21
+ # &num=<max result hits to return>
22
+ # &sort=<comma-delimited sort fields>
23
+ # &metadataToReturn=<comma-delimited fields>
24
+ # &facets=<comma-delimited fields>
25
+ # &facet.<field>.selection=<comma-delimited values>
26
+ # &format=<json|xml|html>
27
+ # &appendRequestSecret=<true|false>
28
+ #
29
+ # Options
30
+ # q (Required) The query to search for, see the query syntax guide
31
+ # for details. https://elvis.tenderapp.com/kb/technical/query-syntax
32
+ # Recap: supports wildcards: *? logical: AND && OR ||
33
+ # prefix terms with + to require - to remove
34
+ # suffix terms with ~ to include similar (eg. spelling errors)
35
+ # terms seperated by spaces default to an AND condition
36
+ # use "double quotes" to search for phrases.
37
+ # All searches are case insensitive.
38
+ #
39
+ # start First hit to be returned. Starting at 0 for the first hit. Used
40
+ # to skip hits to return 'paged' results. Optional. Default is 0.
41
+ #
42
+ # num Number of hits to return. Specify 0 to return no hits, this can be
43
+ # useful if you only want to fetch facets data. Optional. Default is 50.
44
+ #
45
+ # sort The sort order of returned hits. Comma-delimited list of fields to
46
+ # sort on. By default, date/time fields and number fields are sorted
47
+ # descending. All other fields are sorted ascending. To explicitly
48
+ # specify sort order, append "-desc" or "-asc" to the field.
49
+ # Some examples:
50
+ # sort=name
51
+ # sort=rating
52
+ # sort=fileSize-asc
53
+ # sort=status,assetModified-asc
54
+ # A special sort case is "relevance". This lets the search engine
55
+ # determine sorting based on the relevance of the asset against
56
+ # the search query. Relevance results are always returned descending.
57
+ # Optional. Default is assetCreated-desc.
58
+ #
59
+ # metadataToReturn Comma-delimited list of metadata fields to return in hits.
60
+ # It is good practice to always specify just the metadata
61
+ # fields that you need. This will make the searches faster
62
+ # because less data needs to be transferred over the network.
63
+ # Example: metadataToReturn=name,rating,assetCreated
64
+ # Specify "all", or omit to return all available metadata.
65
+ # Example: metadataToReturn=all
66
+ # metadataToReturn=
67
+ # Optional. Default returns all fields.
68
+ #
69
+ # facets Comma-delimited list fields to return facet for.
70
+ # Example: facets=tags,assetDomain
71
+ # Selected values for a facet must be specified with a
72
+ # "facet.<field>.selection" parameter. Do not add selected items to
73
+ # the query since that will cause incorrect facet filtering.
74
+ # Note: Only fields that are un_tokenized or tokenized with
75
+ # pureLowerCase analyzer can be used for faceted search
76
+ # Optional. Default returns no facets.
77
+ #
78
+ # facet.<field>.selection Comma-delimited list of values that should
79
+ # be 'selected' for a given facet.
80
+ # Example: facet.tags.selection=beach
81
+ # facet.assetDomain.selection=image,video
82
+ # Optional.
83
+ #
84
+ # format Response format to return, either json, xml or html.
85
+ # json format is lightweight and very suitable for consumption
86
+ # using AJAX and JavaScript.
87
+ # html format is the easiest way to embed results in HTML pages,
88
+ # but is heavier and less flexible than using a HitRenderer
89
+ # from our open-source JavaScript library.
90
+ # xml format is the same as returned by the Elvis SOAP webservice
91
+ # search operation. This format is suitable for environments
92
+ # that do not support JSON parsing and work better with XML.
93
+ # When you use format=xml, error responses will also be returned
94
+ # in xml format.
95
+ # Optional. Default is json.
96
+ #
97
+ # appendRequestSecret When set to true will append an encrypted code to
98
+ # the thumbnail, preview and original URLs. This is
99
+ # useful when the search is transformed to HTML by an
100
+ # intermediary (like a PHP or XSLT) and is then served
101
+ # to a web browser that is not authenticated against
102
+ # the server.
103
+ # Optional. Default is false.
104
+ #
105
+ # RETURNED VALUE
106
+ # ==============
107
+ #
108
+ # An array of hits in JSON, XML or HTML format. Each item in the array has
109
+ # the following properties.
110
+ #
111
+ # firstResult Index of the first result that is returned.
112
+ # maxResultHits Maximum number of hits that are returned.
113
+ # totalHits Total hits found by the search.
114
+ #
115
+ # hits
116
+ #
117
+ # id Unique ID of the asset in Elvis.
118
+ # permissions String that indicates the permissions the current user has
119
+ # for the asset.
120
+ # thumbnailUrl A ready to use URL to display the thumbnail of an asset.
121
+ # Only available for assets that have a thumbnail.
122
+ # previewUrl A ready to use URL to display the default preview of an
123
+ # asset. The type of preview depends on the asset type.
124
+ # Only available for assets that have a preview.
125
+ # originalUrl A ready to use URL to download the original asset.
126
+ # This URL will only work if the user has the 'use original'
127
+ # permission for this asset. This can be checked with the
128
+ # 'permissions' property.
129
+ # metadata An object with metadata that was requested to be returned.
130
+ # Some metadata will always be returned.
131
+ #
132
+ # Fields that have date or datetime values and the field fileSize contain
133
+ # both the actual numerical value and a formatted value.
134
+
135
+ def search(options={})
136
+
137
+ Utilities.demand_required_options!( :search, options )
138
+ url = base_url + "search"
139
+
140
+ # NOTE: One element of metadata is 'textContent' for books and
141
+ # large articles that is a LOT of text. The following
142
+ # line changes the default from 'all' to 'status,name'.
143
+ # If you want all metadata then you have to request
144
+ # 'all' in your options.
145
+
146
+ options = { metadataToReturn: 'status,name' }.merge(options)
147
+ response = get_response(url, options)
148
+
149
+ end # search
150
+
151
+ alias :find :search
152
+
153
+
154
+ end # module Rest
155
+ end # class Elvis
156
+ end # module WoodWing
@@ -0,0 +1,11 @@
1
+ module WoodWing
2
+ class Elvis
3
+ module Rest
4
+
5
+
6
+ def stub(); end
7
+
8
+
9
+ end # module Rest
10
+ end # class Elvis
11
+ end # module WoodWing
@@ -0,0 +1,18 @@
1
+ ###################################################
2
+ ###
3
+ ## File: soap.rb
4
+ ## Desc: SOAP API definitions for WoodWing's Elvis
5
+ #
6
+
7
+ module WoodWing
8
+ class Elvis
9
+ module Soap
10
+
11
+ require_relative 'soap/stub'
12
+
13
+ end # module Soap
14
+
15
+ include Soap
16
+
17
+ end # class Elvis
18
+ end # module WoodWing
@@ -0,0 +1,11 @@
1
+ module WoodWing
2
+ class Elvis
3
+ module Soap
4
+
5
+
6
+ def stub(); end
7
+
8
+
9
+ end # module Soap
10
+ end # class Elvis
11
+ end # module WoodWing
@@ -0,0 +1,80 @@
1
+ ###################################################
2
+ ###
3
+ ## File: utilities.rb
4
+ ## Desc: Utilitie methods for working with the REST API
5
+ ## for WoodWing's Elvis product
6
+ #
7
+
8
+ require_relative 'utilities/pmask'
9
+
10
+ module WoodWing
11
+ class Elvis
12
+ class Utilities
13
+ class << self
14
+
15
+ =begin
16
+ # SMELL: Is this really necessary with RestClient ?
17
+ def url_encode_options(options)
18
+ raise "Invalid parameter class: expected Hash" unless Hash == options.class
19
+ a_string = ''
20
+ first_one = true
21
+ options.each_pair do |k, v|
22
+ if first_one
23
+ a_string += '?'
24
+ first_one = false
25
+ else
26
+ a_string += '&'
27
+ end
28
+ # a_string += "#{k}=#{String == v.class ? v.gsub(' ','%20') : v}"
29
+ a_string += "#{k}=#{URI::encode(v)}"
30
+ end # options.each_pair
31
+ #debug_me{:a_string} if debug?
32
+ return a_string
33
+ end # url_encode_options
34
+
35
+ =end
36
+
37
+ # encode the username and password for use on the URL for login
38
+
39
+ # SMELL: This is not necessary with a session-based logon/off system
40
+ # HOWEVER, it might still be useful for some cases. Can this
41
+ # scheme and a session management scheme work together?
42
+
43
+ def encode_login(username='guest', password='guest')
44
+
45
+ {
46
+ authcred: UrlSafeBase64.encode64("#{username}:#{password}"),
47
+ authpersist: 'true',
48
+ authclient: 'api_ruby'
49
+ }
50
+
51
+ end # def encode_login(username='guest', password='guest')
52
+
53
+
54
+ # raise ArgumentError if required options are not present
55
+
56
+ def demand_required_options!(command, options)
57
+
58
+ raise ArgumentError unless Symbol == command.class
59
+ raise ArgumentError unless Hash == options.class
60
+ raise ArgumentError unless WW::Elvis::COMMANDS.include?(command)
61
+
62
+ required_options = WW::Elvis::COMMANDS[command][1]
63
+
64
+ answer = true
65
+
66
+ return(answer) if required_options.empty?
67
+
68
+ required_options.each do |ro|
69
+ answer &&= options.include?(ro)
70
+ end
71
+
72
+ raise "ArgumentError: #{caller.first.split().last} requires #{required_options.join(', ')}" unless answer
73
+
74
+ end # def demand_required_options!(command, options)
75
+
76
+ end # eigenclass
77
+ end # class Utilities
78
+ end # class Elvis
79
+ end # module WoodWing
80
+
@@ -0,0 +1,52 @@
1
+ ###################################################
2
+ ###
3
+ ## File: pmask.rb
4
+ ## Desc: Utility class to check permissions 'mask' for available permissions
5
+ #
6
+
7
+ module WoodWing
8
+ class Elvis
9
+ class Utilities
10
+
11
+ # Utility class to check permissions 'mask' for available permissions.
12
+ # The permissions mask consists of a string with one character for
13
+ # every permission available in Elvis: VPUMERXCD
14
+
15
+ class Pmask
16
+
17
+ PERMISSIONS = {
18
+ 'V' => 'VIEW',
19
+ 'P' => 'VIEW_PREVIEW',
20
+ 'U' => 'USE_ORIGINAL',
21
+ 'M' => 'EDIT_METADATA',
22
+ 'E' => 'EDIT',
23
+ 'R' => 'RENAME',
24
+ 'X' => 'MOVE',
25
+ 'C' => 'CREATE',
26
+ 'D' => 'DELETE',
27
+ }
28
+
29
+ def initialize(pmask='')
30
+ @pmask = pmask
31
+ end
32
+
33
+ def verbose
34
+ v=[]
35
+ @pmask.each_char{|c| v<<PERMISSIONS[c]}
36
+ return v.join(', ')
37
+ end
38
+
39
+ define_method('can_view?') { @pmask.include? 'V' }
40
+ define_method('can_view_preview?') { @pmask.include? 'P' }
41
+ define_method('can_use_original?') { @pmask.include? 'U' }
42
+ define_method('can_edit_metadata?') { @pmask.include? 'M' }
43
+ define_method('can_edit?') { @pmask.include? 'E' }
44
+ define_method('can_rename?') { @pmask.include? 'R' }
45
+ define_method('can_move?') { @pmask.include? 'X' }
46
+ define_method('can_create?') { @pmask.include? 'C' }
47
+ define_method('can_delete?') { @pmask.include? 'D' }
48
+
49
+ end # class Pmask
50
+ end # class Utilities
51
+ end # class Elvis
52
+ end # module WoodWing
@@ -0,0 +1,5 @@
1
+ # TODO: indicate the version of the API
2
+
3
+ module WoodWing
4
+ VERSION = "0.0.1" # This is just the version of this gem.
5
+ end # module WoodWing
@@ -0,0 +1,416 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ ##########################################################
4
+ ###
5
+ ## File: elvis_search.rb
6
+ ## Desc: Search Elvis for stuff
7
+ ## can produce an XML file for use with Carrot2 clustering
8
+ ## By: Dewayne VanHoozer (dvanhoozer@gmail.com)
9
+ #
10
+
11
+ require 'debug_me'
12
+ include DebugMe
13
+
14
+ require 'pathname'
15
+ require_relative '../lib/woodwing'
16
+
17
+
18
+ me = Pathname.new(__FILE__).realpath
19
+ my_dir = me.parent
20
+ my_name = me.basename.to_s
21
+
22
+ $options = {
23
+ verbose: false,
24
+ debug: false,
25
+ show_text: false,
26
+ show_dates: false,
27
+ cluster_results: false,
28
+ cluster_filename: nil,
29
+ cluster_file: nil,
30
+ elvis_api_url: ENV['ELVIS_API_URL'] || 'http://localhost:8080/services/',
31
+ elvis_user: ENV['ELVIS_USER'] || 'guest',
32
+ elvis_pass: ENV['ELVIS_PASS'] || 'guest',
33
+ meta_fields: '',
34
+ query: '' # syntax identical to Elvis UI search box
35
+ }
36
+
37
+ def verbose?
38
+ $options[:verbose]
39
+ end
40
+
41
+ def debug?
42
+ $options[:debug]
43
+ end
44
+
45
+ def show_text?
46
+ $options[:show_text]
47
+ end
48
+
49
+ def show_dates?
50
+ $options[:show_dates]
51
+ end
52
+
53
+ def cluster_results?
54
+ $options[:cluster_results]
55
+ end
56
+
57
+ $KNOWN_MFIELDS = %w[ assetCreator
58
+ assetDomain
59
+ assetFileModifier
60
+ assetModifier
61
+ assetPath
62
+ assetPropertyETag
63
+ assetType
64
+ basicDataETag
65
+ cf_PrayerFocus
66
+ cf_Theme
67
+ cf_TFTD
68
+ cf_LongReading
69
+ cf_Citation
70
+ contentETag
71
+ extension
72
+ filename
73
+ fileSize
74
+ fileType
75
+ folderPath
76
+ indexRevision
77
+ metadataComplete
78
+ mimeType
79
+ name
80
+ previewETag
81
+ previewState
82
+ sceArchived
83
+ sceUsed
84
+ status
85
+ textContent
86
+ versionETag
87
+ versionNumber ]
88
+
89
+ usage = <<EOS
90
+
91
+ Search Elvis for stuff
92
+
93
+ Usage: #{my_name} [options] 'query'
94
+
95
+ Where:
96
+
97
+ options Do This
98
+ -h or --help Display this message
99
+ -v or --verbose Display progress
100
+ -d or --debug Sets $DEBUG
101
+ -m or --meta Display these metadata fields
102
+ field_names+ one of more metadata field
103
+ names seperated by commas
104
+ --dates Shows creation and modification
105
+ dates and users
106
+ --text Shows text around the search term(s)
107
+ for the first "hit" in the document
108
+
109
+ --cluster User document clustering
110
+ out_filename filename into which the search
111
+ results are stored
112
+
113
+ 'query' The search query constrained by
114
+ single quotes.
115
+
116
+ NOTE:
117
+
118
+ The single quotes around the search query are required to
119
+ defeat the command line file glob/wildcard facility.
120
+
121
+ The '-m or --meta' option can be used many times as needed.
122
+ The following list contains the known (case-SENSITIVE)
123
+ metadata fields:
124
+
125
+ #{$KNOWN_MFIELDS.join(', ')}
126
+
127
+ EOS
128
+
129
+ # Check command line for Problems with Parameters
130
+ $errors = []
131
+ $warnings = []
132
+
133
+
134
+ # Get the next ARGV parameter after param_index
135
+ def get_next_parameter(param_index)
136
+ unless Fixnum == param_index.class
137
+ param_index = ARGV.find_index(param_index)
138
+ end
139
+ next_parameter = nil
140
+ if param_index+1 >= ARGV.size
141
+ $errors << "#{ARGV[param_index]} specified without parameter"
142
+ else
143
+ next_parameter = ARGV[param_index+1]
144
+ ARGV[param_index+1] = nil
145
+ end
146
+ ARGV[param_index] = nil
147
+ return next_parameter
148
+ end # def get_next_parameter(param_index)
149
+
150
+
151
+ # Get $options[:out_filename]
152
+ def get_out_filename(param_index)
153
+ filename_str = get_next_parameter(param_index)
154
+ $options[:out_filename] = Pathname.new( filename_str ) unless filename_str.nil?
155
+ end # def get_out_filename(param_index)
156
+
157
+
158
+ # Display global warnings and errors arrays and exit if necessary
159
+ def abort_if_errors
160
+ unless $warnings.empty?
161
+ STDERR.puts
162
+ STDERR.puts "The following warnings were generated:"
163
+ STDERR.puts
164
+ $warnings.each do |w|
165
+ STDERR.puts "\tWarning: #{w}"
166
+ end
167
+ STDERR.print "\nAbort program? (y/N) "
168
+ answer = (gets).chomp.strip.downcase
169
+ $errors << "Aborted by user" if answer.size>0 && 'y' == answer[0]
170
+ end
171
+ unless $errors.empty?
172
+ STDERR.puts
173
+ STDERR.puts "Correct the following errors and try again:"
174
+ STDERR.puts
175
+ $errors.each do |e|
176
+ STDERR.puts "\t#{e}"
177
+ end
178
+ STDERR.puts
179
+ exit(-1)
180
+ end
181
+ end # def abort_if_errors
182
+
183
+
184
+ # Display the usage info
185
+ if ARGV.empty? ||
186
+ ARGV.include?('-h') ||
187
+ ARGV.include?('--help')
188
+ puts usage
189
+ exit
190
+ end
191
+
192
+ %w[ -v --verbose ].each do |param|
193
+ if ARGV.include? param
194
+ $options[:verbose] = true
195
+ ARGV[ ARGV.index(param) ] = nil
196
+ end
197
+ end
198
+
199
+ %w[ -d --debug ].each do |param|
200
+ if ARGV.include? param
201
+ $options[:debug] = true
202
+ $DEBUG = true
203
+ ARGV[ ARGV.index(param) ] = nil
204
+ end
205
+ end
206
+
207
+ %w[ -m --meta ].each do |param|
208
+ while ARGV.include?(param) do
209
+ $options[:meta_fields] += ',' unless $options[:meta_fields].empty?
210
+ $options[:meta_fields] += get_next_parameter(ARGV.index(param))
211
+ end
212
+ end
213
+
214
+ %w[ --dates ].each do |param|
215
+ if ARGV.include? param
216
+ $options[:show_dates] = true
217
+ $options[:meta_fields] += ',' unless $options[:meta_fields].empty?
218
+ $options[:meta_fields] += "assetCreated,assetCreator,assetModified,assetModifier,versionNumber"
219
+ ARGV[ ARGV.index(param) ] = nil
220
+ end
221
+ end
222
+
223
+ %w[ --text ].each do |param|
224
+ if ARGV.include? param
225
+ $options[:show_text] = true
226
+ ARGV[ ARGV.index(param) ] = nil
227
+ end
228
+ end
229
+
230
+ %w[ --cluster ].each do |param|
231
+ if ARGV.include? param
232
+ $options[:cluster_results] = true
233
+ next_param = get_next_parameter(param)
234
+ unless next_param.nil?
235
+ $options[:cluster_filename] = Pathname.new(next_param)
236
+ $warnings << "File already exists: #{$options[:cluster_filename].realpath}" if $options[:cluster_filename].exist?
237
+ end
238
+ end
239
+ end
240
+
241
+
242
+ ARGV.compact!
243
+
244
+ debug_me(){ :ARGV }
245
+
246
+
247
+ if ARGV.empty?
248
+ $errors << "No search query was specified."
249
+ end
250
+
251
+ $options[:query] = ARGV.shift
252
+
253
+ unless ARGV.empty?
254
+ $errors << "The search query is malformed - may not be enclosed in quotes."
255
+ end
256
+
257
+ abort_if_errors
258
+
259
+ max_mfield_size = 0
260
+
261
+ unless $options[:meta_fields].empty?
262
+ $options[:meta_fields] = $options[:meta_fields].split(',')
263
+ $options[:meta_fields].each do |mf|
264
+ max_mfield_size = mf.size if mf.size > max_mfield_size
265
+ end
266
+ max_mfield_size += 2
267
+ end
268
+
269
+
270
+ if cluster_results?
271
+ $options[:cluster_file] = File.new($options[:cluster_filename],'w')
272
+ end
273
+
274
+
275
+ ######################################################
276
+ # Local methods
277
+
278
+
279
+
280
+
281
+ ######################################################
282
+ # Main
283
+
284
+ at_exit do
285
+ begin
286
+ $elvis.logout
287
+ rescue
288
+ # eat it
289
+ end
290
+ puts
291
+ puts "Done."
292
+ puts
293
+ end
294
+
295
+ $elvis = WoodWing::Elvis.new
296
+ $elvis.login
297
+
298
+ if debug?
299
+ puts
300
+ pp $options
301
+ puts
302
+ pp $elvis
303
+ puts
304
+ end
305
+
306
+ options = {
307
+ q: $options[:query],
308
+ appendRequestSecret: 'true'
309
+ }
310
+
311
+ options[:metadataToReturn] = $options[:meta_fields].join(',') unless $options[:meta_fields].empty?
312
+
313
+
314
+ response = $elvis.search options
315
+
316
+ if debug?
317
+ puts "======= Full Response ======="
318
+ pp response
319
+ end
320
+
321
+ puts
322
+
323
+ unless response.include?(:totalHits)
324
+ puts "ERROR: response does not include :totalHits"
325
+ exit
326
+ end
327
+
328
+ puts
329
+ puts "Total Hits: #{response[:totalHits]}"
330
+ puts "First Result: #{response[:firstResult]}"
331
+ puts "Max. Results: #{response[:maxResultHits]}"
332
+ puts
333
+
334
+ if cluster_results?
335
+ $options[:cluster_file].puts <<ENDXML
336
+ <?xml version="1.0" encoding="UTF-8"?>
337
+ <searchresult>
338
+ <query>#{$options[:query]}</query>
339
+ ENDXML
340
+
341
+ end
342
+
343
+ if response[:totalHits] > 0
344
+ result_number = 0
345
+ response[:hits].each do |hit|
346
+
347
+ $options[:cluster_file].puts '<document>' if cluster_results?
348
+
349
+ metadata = hit[:metadata]
350
+ puts
351
+ puts "="*45
352
+ puts "== Result # #{result_number+=1} ID: #{hit[:id]}"
353
+ puts
354
+ puts "originalUrl: #{hit[:originalUrl]}"
355
+ puts "Asset Path: #{metadata[:assetPath]}"
356
+ puts "Status: #{metadata[:status]}"
357
+
358
+ unless $options[:meta_fields].empty?
359
+ puts
360
+ $options[:meta_fields].each do |mf|
361
+ mf_label = "#{mf}:" + ' '*(max_mfield_size-mf.size)
362
+ puts "#{mf_label} #{metadata[mf.to_sym]}"
363
+ end
364
+ end
365
+
366
+ if show_dates?
367
+ puts
368
+ puts "Created on: #{metadata[:assetCreated][:formatted]} by: #{metadata[:assetCreator]}"
369
+ puts "Modified on: #{metadata[:assetModified][:formatted]} by: #{metadata[:assetModifier]} Version Number # #{metadata[:versionNumber]}"
370
+ end
371
+
372
+ if show_text?
373
+ puts
374
+ puts "highlightedText: #{hit[:highlightedText]}"
375
+ end
376
+
377
+ puts
378
+
379
+ if cluster_results?
380
+ $options[:cluster_file].puts <<ENDXML
381
+ <title>#{metadata[:assetPath]}</title>
382
+ <snippet>#{hit[:highlightedText].gsub('<B>','').gsub('</B>','').gsub('<','').gsub('>','')}</snippet>
383
+ <url>http://localhost#{metadata[:assetPath]}</url>
384
+ </document>
385
+ ENDXML
386
+
387
+ end # if cluster_results?
388
+
389
+ end # response[:hits].each do |hit|
390
+ end # if response[:totalHits] > 0
391
+
392
+
393
+ if cluster_results?
394
+ $options[:cluster_file].puts "</searchresult>"
395
+ $options[:cluster_file].close
396
+ # TODO: invokl carrot2 CLI
397
+ # TODO: retrieve carrot2 generated XML file
398
+ # TODO: display document clusters
399
+ end
400
+
401
+ __END__
402
+
403
+ # To interface with Carrot2 document clustering workbench this kind of xml
404
+ # file needs to be generated with 1 document entry for each 'hit' of
405
+ # the query.
406
+
407
+ <?xml version="1.0" encoding="UTF-8"?>
408
+ <searchresult>
409
+ <query>seattle</query>
410
+ <document>
411
+ <title>City of Seattle</title>
412
+ <snippet>Official site featuring a guide to living in Seattle and information on doing business, city services, and visitor's resources.</snippet>
413
+ <url>http://www.seattle.gov/</url>
414
+ </document>
415
+ </searchresult>
416
+