lucid_works 0.6.29 → 0.7.1

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 (55) hide show
  1. data/.rvmrc +1 -1
  2. data/Rakefile +25 -0
  3. data/config/locales/en.yml +171 -83
  4. data/lib/lucid_works/associations/has_many.rb +2 -2
  5. data/lib/lucid_works/associations/has_one.rb +1 -1
  6. data/lib/lucid_works/associations/proxy.rb +3 -3
  7. data/lib/lucid_works/associations.rb +2 -2
  8. data/lib/lucid_works/base.rb +21 -48
  9. data/lib/lucid_works/collection/click.rb +17 -0
  10. data/lib/lucid_works/collection/settings.rb +0 -1
  11. data/lib/lucid_works/collection.rb +22 -3
  12. data/lib/lucid_works/crawler.rb +13 -0
  13. data/lib/lucid_works/datasource/history.rb +5 -9
  14. data/lib/lucid_works/datasource/status.rb +8 -11
  15. data/lib/lucid_works/datasource.rb +67 -32
  16. data/lib/lucid_works/datasource_property.rb +18 -0
  17. data/lib/lucid_works/datasource_type.rb +23 -0
  18. data/lib/lucid_works/exceptions.rb +1 -0
  19. data/lib/lucid_works/field.rb +43 -2
  20. data/lib/lucid_works/fieldtype.rb +28 -0
  21. data/lib/lucid_works/gem_version.rb +1 -1
  22. data/lib/lucid_works/jdbcdriver.rb +30 -0
  23. data/lib/lucid_works/role.rb +59 -0
  24. data/lib/lucid_works/schema/attribute.rb +86 -0
  25. data/lib/lucid_works/schema/boolean_attribute.rb +34 -0
  26. data/lib/lucid_works/schema/custom_attribute.rb +15 -0
  27. data/lib/lucid_works/schema/integer_attribute.rb +32 -0
  28. data/lib/lucid_works/schema/iso8601_attribute.rb +31 -0
  29. data/lib/lucid_works/schema/string_attribute.rb +22 -0
  30. data/lib/lucid_works/schema.rb +66 -97
  31. data/lib/lucid_works/server.rb +14 -0
  32. data/lib/lucid_works.rb +12 -0
  33. data/spec/fixtures/fake_file_ds_to_be_deleted/.gitkeep +0 -0
  34. data/spec/fixtures/fake_file_ds_to_be_updated/.gitkeep +0 -0
  35. data/spec/fixtures/fake_file_ds_to_get_index_of/.gitkeep +0 -0
  36. data/spec/fixtures/fake_file_ds_to_get_schedule_of/.gitkeep +0 -0
  37. data/spec/fixtures/fake_file_ds_to_get_status_of/.gitkeep +0 -0
  38. data/spec/fixtures/fake_file_ds_to_mess_with_job_of/.gitkeep +0 -0
  39. data/spec/fixtures/fake_file_ds_to_test_progress/.gitkeep +0 -0
  40. data/spec/lib/lucid_works/associations/has_many_spec.rb +4 -3
  41. data/spec/lib/lucid_works/associations/has_one_spec.rb +4 -3
  42. data/spec/lib/lucid_works/base_spec.rb +110 -62
  43. data/spec/lib/lucid_works/collection/activity/history_spec.rb +1 -1
  44. data/spec/lib/lucid_works/collection_spec.rb +17 -17
  45. data/spec/lib/lucid_works/datasource/history_spec.rb +4 -4
  46. data/spec/lib/lucid_works/datasource/status_spec.rb +7 -7
  47. data/spec/lib/lucid_works/datasource_spec.rb +9 -8
  48. data/spec/lib/lucid_works/field_spec.rb +101 -2
  49. data/spec/lib/lucid_works/fieldtype_spec.rb +156 -0
  50. data/spec/lib/lucid_works/schema/attribute_spec.rb +136 -0
  51. data/spec/lib/lucid_works/schema_spec.rb +53 -27
  52. data/spec/spec_helper.rb +3 -50
  53. data/spec/support/active_model_lint.rb +21 -0
  54. data/spec/support/lucid_works.rb +52 -0
  55. metadata +36 -2
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm use 1.9.2-p180@lucidworks
1
+ rvm use 1.9.2-p180@lucidworks --create
data/Rakefile CHANGED
@@ -11,3 +11,28 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
11
11
  rdoc.rdoc_files.include('README.rdoc')
12
12
  rdoc.rdoc_files.include('lib/**/*.rb')
13
13
  end
14
+
15
+ class Hash
16
+ def recursively_sort
17
+ raise "Hash#recursively_sort requires Ruby 1.9" if RUBY_VERSION < "1.9"
18
+ sorted_array = self.sort
19
+ sorted_array.map! do |kv|
20
+ k, v = kv
21
+ v = v.recursively_sort if v.is_a?(Hash)
22
+ [k,v]
23
+ end
24
+ Hash[sorted_array]
25
+ end
26
+ end
27
+
28
+ namespace :l10n do
29
+
30
+ desc "Sort the EN locale file"
31
+ task :sort do
32
+ en_path = File.join(File.dirname(__FILE__), 'config', 'locales', "en.yml")
33
+ translations = YAML.load_file(en_path)
34
+ File.open(en_path, 'w') do |f|
35
+ YAML.dump translations.recursively_sort, f
36
+ end
37
+ end
38
+ end
@@ -1,51 +1,13 @@
1
1
  ---
2
2
  en:
3
3
  activemodel:
4
- models:
5
- lucid_works:
6
- activity:
7
- one: Activity
8
- other: Activities
9
- type:
10
- autocomplete: Generate autocomplete index
11
- click: Process click logs
12
- optimize: Optimize index
13
- spelling: Generate spellcheck index
14
- collection:
15
- one: Collection
16
- other: Collections
17
- settings:
18
- one: Settings
19
- other: Settings
20
- de_duplication:
21
- 'off': 'Off'
22
- overwrite: Overwrite
23
- tag: Tag
24
- datasource:
25
- one: Data source
26
- other: Data sources
27
- status:
28
- crawlState:
29
- ABORTED: Aborted
30
- ABORTING: Aborting
31
- EXCEPTION: Exception
32
- FINISHED: Finished
33
- IDLE: Idle
34
- RUNNING: Running
35
- STOPPED: Stopped
36
- STOPPING: Stopping
37
- type:
38
- external: External
39
- file: Local Filesystem
40
- jdbc: Database
41
- lucidworkslogs: LucidWorks Solr Logs
42
- sharepoint: Sharepoint
43
- solrxml: Solr XML
44
- web: Web Site
4
+ #
5
+ # This section is standard ActiveModel
6
+ # and is used by human_attribute_name
7
+ #
45
8
  attributes:
46
9
  lucid_works:
47
10
  collection:
48
- name: Name
49
11
  info:
50
12
  collection_name: Collection name
51
13
  data_dir: Data directory
@@ -65,15 +27,16 @@ en:
65
27
  root_dir: Root directory
66
28
  total_disk_bytes: Total disk bytes
67
29
  total_disk_space: Total disk space
30
+ name: Name
68
31
  settings:
69
32
  auto_complete: Auto complete
70
- boosts: Boosts
71
33
  boost_recent: Boost recent
34
+ boosts: Boosts
72
35
  click_boost_data: Click boost data
73
36
  click_boost_field: Click boost field
74
37
  click_enabled: Click scoring enabled
75
- default_sort: Default sort
76
38
  de_duplication: De-duplication
39
+ default_sort: Default sort
77
40
  display_facets: Display facets
78
41
  elevations: elevations
79
42
  index_time_stopwords: Exclude stop words from index
@@ -91,47 +54,172 @@ en:
91
54
  unsupervised_feedback_emphasis: Unsupervised feedback emphasis
92
55
  update_server_list: Update server list
93
56
  datasource:
94
- type: Type
95
- commitWithin: Commit within
96
- commit_within_min: "Commit within (minutes)"
97
- deleteAfter: Delete logs after
57
+ aliases: Site Aliases Mappings
58
+ auth: Authentication credentials
59
+ authorization: Authorization
98
60
  bounds: Constrain to
99
- max_bytes: Skip files larger than (bytes)
61
+ commit_on_finish: Commit when crawl finishes
62
+ commit_within: Commit within
63
+ commit_within_min: Commit within (minutes)
64
+ connector_type: Connector Type
65
+ deleteAfter: Delete logs after
66
+ domain: Domain
67
+ excluded_urls: Excluded URLs
68
+ fail_unsupported_file_types: Fail unsupported file types
100
69
  history:
101
- crawlStarted: Started
102
- crawlStopped: Stopped
103
- crawlState: State
104
- numNew: New
105
- numUpdated: Updated
106
- numDeleted: Deleted
107
- numUnchanged: Unchanged
108
- numFailed: Failed
70
+ crawl_started: Started
71
+ crawl_state: State
72
+ crawl_stopped: Stopped
73
+ num_deleted: Deleted
74
+ num_failed: Failed
75
+ num_new: New
76
+ num_unchanged: Unchanged
77
+ num_updated: Updated
78
+ host: Domain Name
79
+ ignore_robots: Ignore robots.txt
80
+ include_datasource_metadata: Include data source metadata
81
+ included_urls: Included URLs
82
+ kdcserver: Kerberos KDC server
83
+ log_extra_detail: Log extra detail
84
+ max_bytes: Skip files larger than (bytes)
85
+ my_site_base_url: MySite URL
86
+ no_duplicates: Suppress duplicates
87
+ password: Password
88
+ proxy_host: Proxy host
89
+ proxy_password: Proxy password
90
+ proxy_port: Proxy port
91
+ proxy_username: Proxy user name
92
+ realm: Realm
93
+ sharepoint_url: SharePoint URL
109
94
  status:
110
- crawlStarted: Last crawl started
111
- crawlStopped: Last crawl stopped
112
- crawlState: State
95
+ crawl_started: Last crawl started
96
+ crawl_state: State
97
+ crawl_stopped: Last crawl stopped
113
98
  doc_count: Documents indexed
114
- jobId: Job ID
115
- numNew: New docs
116
- numUpdated: Updated docs
117
- numDeleted: Deleted docs
118
- numUnchanged: Unchanged docs
119
- numFailed: Failed docs
120
- numTotal: Total docs
121
- sharepointUrl: SharePoint URL
122
- connectorType: Connector Type
123
- authorization: Authorization
99
+ job_id: Job ID
100
+ num_deleted: Deleted docs
101
+ num_failed: Failed docs
102
+ num_new: New docs
103
+ num_total: Total docs
104
+ num_unchanged: Unchanged docs
105
+ num_updated: Updated docs
106
+ type: Type
107
+ url: URL
108
+ use_sp_search_visibility: Use SP Search Visibility
124
109
  username: Username
125
- password: Password
126
- domain: Domain
127
- mySiteBaseURL: MySite URL
128
- includedURls: Included URLs
129
- excludedURls: Excluded URLs
130
- kdcserver: Kerberos KDC server
131
- useSPSearchVisibility: Use SP Search Visibility
132
- aliases: Site Aliases Mappings
133
- # errors:
134
- # models:
135
- # lucid_works:
136
- # collection:
137
- # exclusion: is reserved
110
+ warn_unknown_mime_types: Log warnings for unknown mime types
111
+ windowsdomain: Windows domain
112
+ field:
113
+ copy_fields: Copy this field to fields
114
+ default_boost: Default boost
115
+ default_value: Default value
116
+ dynamic_base: Dynamically generated from
117
+ editable: Editable
118
+ facet: Facet
119
+ field_type: Field type
120
+ highlight: Highlight
121
+ include_in_results: Include in results
122
+ index_for_autocomplete: Index for autocomplete
123
+ index_for_spellcheck: Index for spell checking
124
+ index_term_freq_and_pos: Index term frequencies and positions
125
+ indexed: Indexed
126
+ multi_valued: Multi-valued
127
+ name: Name
128
+ omit_positions: Omit positions
129
+ omit_tf: Omit term frequencies and positions
130
+ query_time_stopword_handling: Enable stopword handling
131
+ search_by_default: Search by default
132
+ short_field_boost: Short field boost
133
+ stored: Stored
134
+ synonym_expasion: Enable synonym expansion
135
+ term_vectors: Term vectors
136
+ use_for_deduplication: Use for de-duplication
137
+ use_in_find_similar: Use in 'find similar'
138
+ fieldtype:
139
+ name: Name
140
+ _class: Class
141
+ #
142
+ # This section containts two things:
143
+ # Model names wich support ActiveModel <model>.model_name.human
144
+ # Translations for attribute values. This is our own invention,
145
+ # accessed with LucidWorks::Base#human_attribute_value(attribute)
146
+ # or from class LucidWorks::Base.human_attribute_value(attribute, value)
147
+ #
148
+ models:
149
+ lucid_works:
150
+ activity:
151
+ one: Activity
152
+ other: Activities
153
+ type:
154
+ autocomplete: Generate autocomplete index
155
+ click: Process click logs
156
+ optimize: Optimize index
157
+ spelling: Generate spellcheck index
158
+ collection:
159
+ one: Collection
160
+ other: Collections
161
+ settings:
162
+ de_duplication:
163
+ 'off': 'Off'
164
+ overwrite: Overwrite
165
+ tag: Tag
166
+ one: Settings
167
+ other: Settings
168
+ datasource:
169
+ one: Data source
170
+ other: Data sources
171
+ status:
172
+ crawl_state:
173
+ ABORTED: Aborted
174
+ ABORTING: Aborting
175
+ EXCEPTION: Exception
176
+ FINISHED: Finished
177
+ IDLE: Idle
178
+ RUNNING: Running
179
+ STOPPED: Stopped
180
+ STOPPING: Stopping
181
+ type:
182
+ external: External
183
+ file: File system
184
+ ftp: FTP
185
+ hdfs: Hadoop file system
186
+ jdbc: Database
187
+ kfs: Kosmos file system
188
+ lucidworkslogs: LucidWorks Solr Logs
189
+ s3: Hadoop S3 Block FS
190
+ s3n: Hadoop S3 Native FS
191
+ sharepoint: SharePoint
192
+ smb: Windows Share
193
+ solrxml: Solr XML
194
+ web: Web site
195
+ field:
196
+ one: Field
197
+ other: Fields
198
+ index_term_freq_and_pos:
199
+ document_only: none
200
+ document_termfreq: term frequencies
201
+ document_termfreq_termpos: term frequencies and positions
202
+ fieldtype:
203
+ one: Field type
204
+ other: Field types
205
+ jdbcdriver:
206
+ one: JDBC driver
207
+ other: JDBC drivers
208
+ #
209
+ # These hints appear next to fields in SimpleForm forms
210
+ #
211
+ simple_form:
212
+ hints:
213
+ collection:
214
+ name: ! 'Collection names may use the characters: A-Z, a-z, 0-9, dash and
215
+ underscore'
216
+ datasource:
217
+ crawl_depth: Set to -1 to crawl with no depth limit.
218
+ exclude_paths: A list of regular expressions, one per line, e.g. .*\.pdf will
219
+ ignore filenames ending in .pdf.
220
+ include_paths: A list of regular expressions, one per line, e.g. http://example\.com/.*
221
+ will match everything within the site only.
222
+ max_bytes: Default = 10 MiB. Set to -1 to indicate no file size limit.
223
+ url: e.g. http://cnn.com. Please include protocol (http/https).
224
+ synonym:
225
+ mapping: ! 'Example: car, automobile, auto'
@@ -18,7 +18,7 @@ module LucidWorks
18
18
  if target.save
19
19
  target
20
20
  else
21
- raise target.errors.full_messages
21
+ raise LucidWorks::RecordInvalid.new(target.errors.full_messages)
22
22
  end
23
23
  end
24
24
 
@@ -40,7 +40,7 @@ module LucidWorks
40
40
  #
41
41
  # Interestingly for us the cost difference is marginal between the two forms of
42
42
  # the call. Should we just grab all of them and return the one they want?
43
- # Probably not. Not every elegant and there is some cost to creating models
43
+ # Probably not. Not very elegant and there is some cost to creating models
44
44
  # on our end.
45
45
  #
46
46
  # Okay for now we will just not cache .find()
@@ -17,7 +17,7 @@ module LucidWorks
17
17
  if @target.save
18
18
  @target
19
19
  else
20
- raise @target.errors.full_messages
20
+ raise LucidWorks::RecordInvalid.new(@target.errors.full_messages)
21
21
  end
22
22
  end
23
23
 
@@ -25,9 +25,9 @@ module LucidWorks
25
25
  !!@target
26
26
  end
27
27
 
28
- # Can targets be retrieved for all owners if this type, in one step using owner/all/target
29
- def supports_all?
30
- @options[:supports_all]
28
+ # Can targets be retrieved for all owners of this type, in one step using owner/all/target
29
+ def retrieveable_en_masse?
30
+ @options[:retrieveable_en_masse]
31
31
  end
32
32
 
33
33
  def reload!
@@ -113,7 +113,7 @@ module LucidWorks
113
113
 
114
114
  class_eval <<-EOF, __FILE__, __LINE__ + 1
115
115
  def #{resource}
116
- @#{resource}_association ||= Associations::HasOne.new(self, #{resource_class_name}, #{options.to_s})
116
+ @#{resource}_association ||= Associations::HasOne.new(self, #{resource_class_name}, #{options.inspect})
117
117
  end
118
118
 
119
119
  def #{resource}!
@@ -137,7 +137,7 @@ module LucidWorks
137
137
 
138
138
  class_eval <<-EOF, __FILE__, __LINE__ + 1
139
139
  def #{resources}(options={})
140
- @#{resources}_association ||= Associations::HasMany.new(self, #{resource_class_name}, #{options.to_s})
140
+ @#{resources}_association ||= Associations::HasMany.new(self, #{resource_class_name}, #{options.inspect})
141
141
  @#{resources}_association.remember_find_options(options) unless options.empty?
142
142
  @#{resources}_association
143
143
  end
@@ -45,8 +45,6 @@ module LucidWorks
45
45
  define_model_callbacks :save, :only => [:before, :after]
46
46
 
47
47
  class << self
48
- include ActionView::Helpers::NumberHelper rescue nil
49
-
50
48
  attr_accessor :collection_name # :nodoc:
51
49
  attr_accessor_with_default :singleton, false
52
50
 
@@ -66,7 +64,7 @@ module LucidWorks
66
64
  # end
67
65
 
68
66
  def schema(&block)
69
- @schema ||= LucidWorks::Schema.new
67
+ @schema ||= LucidWorks::Schema.new(self)
70
68
  if block_given?
71
69
  @schema.instance_eval(&block)
72
70
  @schema.create_accessors_for_attributes(self)
@@ -177,7 +175,7 @@ module LucidWorks
177
175
  target_class = class_eval(association_info[:class_name]) # get scoping right
178
176
  target_name = association_info[:class_name].underscore
179
177
 
180
- if kind_of_find == :all && association_info[:supports_all]
178
+ if kind_of_find == :all && association_info[:retrieveable_en_masse]
181
179
  all_targets_path = "#{collection_url(parent)}/all/#{target_name}"
182
180
  raw_response = ActiveSupport::Notifications.instrument("lucid_works.request") do |payload|
183
181
  begin
@@ -205,9 +203,7 @@ module LucidWorks
205
203
  # [{"history":[...history_models...],"id":372},{"history":[...history_models...],"id":371}]
206
204
  JSON.parse(raw_response).each do |group_of_targets|
207
205
  owner_id = group_of_targets['id']
208
- # Note: to_i in the next line is because most REST API interfaces return ids a integers
209
- # but one returns them as strings. There is no plan to fix this brokeness (FOCUS-2359).
210
- owner = results_array.detect { |result| result.id == owner_id.to_i }
206
+ owner = results_array.detect { |result| result.id == owner_id }
211
207
  targets = group_of_targets[target_name].collect do |target_attrs|
212
208
  target_class.new(target_attrs.merge(:parent => owner, :persisted => true))
213
209
  end
@@ -215,7 +211,7 @@ module LucidWorks
215
211
  association_proxy.target = targets
216
212
  end
217
213
  end
218
- else # kind_of_find != :all || !supports_all
214
+ else # kind_of_find != :all || !retrieveable_en_masse
219
215
  results_array.each do |result|
220
216
  result.send("#{association_name}!")
221
217
  end
@@ -250,31 +246,14 @@ module LucidWorks
250
246
  # If the attributes is listed in the schema as having :values =>, it will be translated.
251
247
 
252
248
  def human_attribute_value(attribute, value)
253
- if schema[attribute][:values]
254
- l10n_scope = %w{activemodel models} + self.name.underscore.split('/') + [attribute]
255
- return I18n.t(value, :scope => l10n_scope, :default => value)
256
- end
257
-
258
- case schema[attribute][:type]
259
- when :boolean
260
- value.to_yesno
261
- when :integer
262
- number_with_delimiter(value)
263
- else
264
- value.to_s
265
- end
266
- rescue
267
- value.to_s
249
+ schema[attribute].human_value(value)
268
250
  end
269
251
 
270
252
  # For attributes listed in the schema as having :values, this will create an array-of-arrays
271
253
  # suitable for use as options_for_select.
272
254
 
273
255
  def to_select(attribute)
274
- raise "Can't to_select for #{attribute} as it has no values" unless schema[attribute][:values]
275
- schema[attribute][:values].map do |value|
276
- [human_attribute_value(attribute, value), value]
277
- end
256
+ schema[attribute].to_select
278
257
  end
279
258
 
280
259
  def collection_name # :nodoc:
@@ -332,7 +311,7 @@ module LucidWorks
332
311
  rescue RestClient::Conflict, # 409
333
312
  RestClient::UnprocessableEntity, # 422
334
313
  RestClient::InternalServerError => e # 500
335
- payload[:exceptionion] = e
314
+ payload[:exception] = e
336
315
  attach_errors_to_model(e.response)
337
316
  false
338
317
  rescue RestClient::Exception => exception
@@ -358,6 +337,10 @@ module LucidWorks
358
337
  payload[:uri] = member_url
359
338
  payload[:options] = options
360
339
  payload[:repsonse] = RestClient.delete(member_url, options)
340
+ rescue RestClient::Conflict => e
341
+ payload[:exception] = e
342
+ attach_errors_to_model(e.response)
343
+ false
361
344
  rescue RestClient::Exception => exception
362
345
  # Tack on what we were doing when we got the exception, then send it on up
363
346
  exception.message = "#{exception.message} while performing #{payload[:method]} #{payload[:uri]}"
@@ -409,6 +392,10 @@ module LucidWorks
409
392
 
410
393
  private
411
394
 
395
+ def schema
396
+ self.class.schema
397
+ end
398
+
412
399
  def singleton? # :nodoc:
413
400
  self.class.singleton
414
401
  end
@@ -418,20 +405,12 @@ module LucidWorks
418
405
  end
419
406
 
420
407
  def encode # :nodoc:
421
- omit_attrs = [ 'id' ]
422
- omit_attrs += self.class.schema.attrs_to_omit_during_update if persisted?
423
- attrs_as_json = @attributes.inject({}) do |memo, kv|
408
+ attrs_as_json = @attributes.inject({}) do |encoded_attrs, kv|
424
409
  attr, value = kv
425
- unless (value.blank? && self.class.schema[attr][:omit_when_blank]) ||
426
- omit_attrs.include?(attr.to_s)
427
- case self.class.schema[attr][:type]
428
- when :iso8601
429
- memo[attr] = value.iso8601 rescue value
430
- else
431
- memo[attr] = value
432
- end
410
+ unless attr.to_s == 'id'
411
+ schema[attr].encode_and_insert(value, encoded_attrs, persisted?)
433
412
  end
434
- memo
413
+ encoded_attrs
435
414
  end
436
415
  attrs_as_json.to_json
437
416
  end
@@ -445,14 +424,8 @@ module LucidWorks
445
424
  elsif self.class.respond_to?(:belongs_to_association_name) && attr.to_sym == self.class.belongs_to_association_name
446
425
  next # Dont overwrite our connection to our parent
447
426
  end
448
- unless self.class.schema.has_attribute?(attr)
449
- if self.class.schema.dynamic_attributes?
450
- self.class.schema.add_attribute(self.class, attr, :string)
451
- else
452
- raise "unknown attribute: \"#{attr}\""
453
- end
454
- end
455
- send "#{self.class.schema.sanitize_identifier(attr)}=", value
427
+ attribute = schema.find_or_create_attribute(attr)
428
+ send "#{attribute.name}=", value
456
429
  end
457
430
  end
458
431