jakewendt-active_record_sunspotter 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1cbf38085cf568de0799a1f8ce7ebb52545b26ff
4
- data.tar.gz: ce140ffcd58a91c4eb55e5a4b8a2861e723bb8f7
3
+ metadata.gz: 79f05bc56e701726f80ddfaae0e883a2681b9153
4
+ data.tar.gz: ab3caa50a2fec615bc482630e736a38e3df24b77
5
5
  SHA512:
6
- metadata.gz: 84df83b33a7dcd53314a4561054c45d46007b879dbcd7e2867f1fd2cf09cdc3ea3502decf9fdedf8d9d83bf2f808a0457b1be5d40b7d1ef2d8be0336fe090cff
7
- data.tar.gz: 47eba5dffe54913b9f5b99b5974f23a87622913f67f9a61e11f01f44ede4a8754ce2f4feb809fc3d625ef7f7936e6f4dd9e9ab101028ce6bb5b90134cdfee111
6
+ metadata.gz: f10cc1f7f4330ac4be8d6ba46fe5c2099c89ec807edaf1c095ad3c83875807dc4e0521733ac9b09af317869d8c7a94c9b3e1f44b95718aee72c6b13b2edbddbe
7
+ data.tar.gz: ab600a96bd3d2d3d073825b1c01c9b845f69ecb4483c796ac8561249afad172439adc247e27c7111ba094651ccf675e3d16800bc75ffee6eca3e2f25931dfc2f
data/README.rdoc CHANGED
@@ -7,6 +7,64 @@
7
7
 
8
8
 
9
9
 
10
+ == Modifications
11
+
12
+ I'm stuck using version 2.0.0. Seems to be issues with java. Anywho.
13
+ This file loads too early for me to override, so...
14
+
15
+ Need to edit ...
16
+
17
+ /opt/local/lib/ruby2.0/gems/2.0.0/gems/sunspot_rails-2.0.0/lib/sunspot_rails.rb
18
+
19
+ ... to require 'json' rather than 'to_json' for rails 4.1.0 and above like so.
20
+
21
+
22
+ if ::Rails.version >= '4.1'
23
+ require 'active_support/core_ext/object/json'
24
+ elsif ::Rails.version >= '3'
25
+ require 'active_support/core_ext/object/to_json'
26
+ end
27
+
28
+
29
+
30
+
31
+
32
+
33
+ And another mod... (I may be able to patch this one.)
34
+
35
+ sunspot_rails-2.0.0/lib/sunspot/rails/searchable.rb
36
+
37
+ Must comment out the :include option.
38
+
39
+ 251 find_in_batch_options = {
40
+ 252 # :include => options[:include],
41
+ 253 :batch_size => options[:batch_size],
42
+ 254 :start => options[:start]
43
+ 255 }
44
+
45
+
46
+ Don't know why now as it has been there for a while, but even looking back to 4.0.3
47
+ it hasn't been a valid key?
48
+
49
+ ArgumentError: Unknown key: :include. Valid keys are: :start, :batch_size
50
+ /my/ruby/gems/2.0/gems/activesupport-4.1.0/lib/active_support/core_ext/hash/keys.rb:71:in `block in assert_valid_keys'
51
+ /my/ruby/gems/2.0/gems/activesupport-4.1.0/lib/active_support/core_ext/hash/keys.rb:69:in `each_key'
52
+ /my/ruby/gems/2.0/gems/activesupport-4.1.0/lib/active_support/core_ext/hash/keys.rb:69:in `assert_valid_keys'
53
+ /my/ruby/gems/2.0/gems/activerecord-4.1.0/lib/active_record/relation/batches.rb:100:in `find_in_batches'
54
+ /my/ruby/gems/2.0/gems/activerecord-4.1.0/lib/active_record/querying.rb:9:in `find_in_batches'
55
+ /my/ruby/gems/2.0/gems/sunspot_rails-2.0.0/lib/sunspot/rails/searchable.rb:259:in `solr_index'
56
+
57
+
58
+
59
+
60
+ == Testing
61
+
62
+
63
+
64
+ sudo /opt/local/share/mariadb/support-files/mysql.server start
65
+
66
+ c ; bundle exec rake sunspot:solr:stop ; bundle exec rake sunspot:solr:stop RAILS_ENV=test ; bundle exec rake sunspot:solr:start ; bundle exec rake sunspot:solr:start RAILS_ENV=test ; bundle exec rake test
67
+
10
68
 
11
69
 
12
70
  == Gemified with Jeweler
@@ -3,6 +3,10 @@ module ActiveRecordSunspotter
3
3
  initializer 'add_helpers_to_actionview' do |app|
4
4
  ActiveSupport.on_load :action_view do
5
5
  ActionView::Base.send(:include, ActiveRecordSunspotter::SunspotHelper)
6
+ # :sunspot would require sunspot_helper.rb be in one of the magical load paths.
7
+ #ActionController::Base.helper :sunspot
8
+ # So much simpler to just pass the module name.
9
+ ActionController::Base.helper ActiveRecordSunspotter::SunspotHelper
6
10
  end
7
11
  end
8
12
  # rake_tasks do
@@ -184,4 +184,52 @@ module ActiveRecordSunspotter::SunspotHelper
184
184
  html_content.html_safe
185
185
  end
186
186
 
187
+
188
+ # ↑ and ↓
189
+ def sort_link(*args)
190
+ options = {
191
+ :image => true
192
+ }.merge(args.extract_options!)
193
+ column = args[0]
194
+ text = args[1]
195
+ # make local copy so mods to muck up real params which
196
+ # may still be references elsewhere.
197
+ local_params = params.dup
198
+
199
+ #
200
+ # May want to NOT flip dir for other columns. Only the current order.
201
+ # Will wait until someone else makes the suggestion.
202
+ #
203
+ order = column.to_s.downcase.gsub(/\s+/,'_')
204
+ dir = ( local_params[:dir] && local_params[:dir] == 'asc' ) ? 'desc' : 'asc'
205
+
206
+ local_params[:page] = nil
207
+ link_text = text||column
208
+ classes = ['sortable',order]
209
+ arrow = ''
210
+ if local_params[:order] && local_params[:order] == order
211
+ classes.push('sorted')
212
+ arrow = if dir == 'desc'
213
+ # if File.exists?( sort_down_image ) && options[:image]
214
+ # image_tag( File.basename(sort_down_image), :class => 'down arrow')
215
+ # else
216
+ "<span class='down arrow'>&darr;</span>"
217
+ # end
218
+ else
219
+ # if File.exists?( sort_up_image ) && options[:image]
220
+ # image_tag( File.basename(sort_up_image), :class => 'up arrow')
221
+ # else
222
+ "<span class='up arrow'>&uarr;</span>"
223
+ # end
224
+ end
225
+ end
226
+ s = "<div class='#{classes.join(' ')}'>"
227
+ s << link_to(link_text.html_safe,local_params.merge(:order => order,:dir => dir))
228
+ s << arrow unless arrow.blank?
229
+ s << "</div>"
230
+ s.html_safe
231
+ end
232
+
233
+
234
+
187
235
  end
@@ -0,0 +1,497 @@
1
+ module Sunspot #:nodoc:
2
+ module Rails #:nodoc:
3
+ #
4
+ # This module adds Sunspot functionality to ActiveRecord models. As well as
5
+ # providing class and instance methods, it optionally adds lifecycle hooks
6
+ # to automatically add and remove models from the Solr index as they are
7
+ # created and destroyed.
8
+ #
9
+ module Searchable
10
+ class <<self
11
+ def included(base) #:nodoc:
12
+ base.module_eval do
13
+ extend(ActsAsMethods)
14
+ end
15
+ end
16
+ end
17
+
18
+ module ActsAsMethods
19
+ #
20
+ # Makes a class searchable if it is not already, or adds search
21
+ # configuration if it is. Note that the options passed in are only used
22
+ # the first time this method is called for a particular class; so,
23
+ # search should be defined before activating any mixins that extend
24
+ # search configuration.
25
+ #
26
+ # The block passed into this method is evaluated by the
27
+ # <code>Sunspot.setup</code> method. See the Sunspot documentation for
28
+ # complete information on the functionality provided by that method.
29
+ #
30
+ # ==== Options (+options+)
31
+ #
32
+ # :auto_index<Boolean>::
33
+ # Automatically index models in Solr when they are saved.
34
+ # Default: true
35
+ # :auto_remove<Boolean>::
36
+ # Automatically remove models from the Solr index when they are
37
+ # destroyed. <b>Setting this option to +false+ is not recommended
38
+ # </b>(see the README).
39
+ # :if<Mixed>::
40
+ # Only index models in Solr if the method, proc or string evaluates
41
+ # to true (e.g. <code>:if => :should_index?</code> or <code>:if =>
42
+ # proc { |model| model.foo > 2 }</code>). Models that do not match
43
+ # the constraint will be removed from the index upon save. Multiple
44
+ # constraints can be specified by passing an array (e.g. <code>:if =>
45
+ # [:method1, :method2]</code>).
46
+ # :ignore_attribute_changes_of<Array>::
47
+ # Define attributes, that should not trigger a reindex of that
48
+ # object. Usual suspects are updated_at or counters.
49
+ # :only_reindex_attribute_changes_of<Array>::
50
+ # Define attributes, that are the only attributes that should
51
+ # trigger a reindex of that object. Useful if there are a small
52
+ # number of searchable attributes and a large number of attributes
53
+ # to ignore.
54
+ # :include<Mixed>::
55
+ # Define default ActiveRecord includes, set this to allow ActiveRecord
56
+ # to load required associations when indexing. See ActiveRecord's
57
+ # documentation on eager-loading for examples on how to set this
58
+ # Default: []
59
+ # :unless<Mixed>::
60
+ # Only index models in Solr if the method, proc or string evaluates
61
+ # to false (e.g. <code>:unless => :should_not_index?</code> or <code>
62
+ # :unless => proc { |model| model.foo <= 2 }</code>). Models that do
63
+ # not match the constraint will be removed from the index upon save.
64
+ # Multiple constraints can be specified by passing an array (e.g.
65
+ # <code>:unless => [:method1, :method2]</code>).
66
+ #
67
+ # ==== Example
68
+ #
69
+ # class Post < ActiveRecord::Base
70
+ # searchable do
71
+ # text :title, :body
72
+ # string :sort_title do
73
+ # title.downcase.sub(/^(an?|the)/, '')
74
+ # end
75
+ # integer :blog_id
76
+ # time :updated_at
77
+ # end
78
+ # end
79
+ #
80
+ def searchable(options = {}, &block)
81
+ Sunspot.setup(self, &block)
82
+
83
+ if searchable?
84
+ sunspot_options[:include].concat(Util::Array(options[:include]))
85
+ else
86
+ extend ClassMethods
87
+ include InstanceMethods
88
+
89
+ class_attribute :sunspot_options
90
+
91
+ unless options[:auto_index] == false
92
+ before_save :mark_for_auto_indexing_or_removal
93
+ after_save :perform_index_tasks
94
+ end
95
+
96
+ unless options[:auto_remove] == false
97
+ after_destroy do |searchable|
98
+ searchable.remove_from_index
99
+ end
100
+ end
101
+ options[:include] = Util::Array(options[:include])
102
+
103
+ self.sunspot_options = options
104
+ end
105
+ end
106
+
107
+ #
108
+ # This method is defined on all ActiveRecord::Base subclasses. It
109
+ # is false for classes on which #searchable has not been called, and
110
+ # true for classes on which #searchable has been called.
111
+ #
112
+ # ==== Returns
113
+ #
114
+ # +false+
115
+ #
116
+ def searchable?
117
+ false
118
+ end
119
+ end
120
+
121
+ module ClassMethods
122
+ def self.extended(base) #:nodoc:
123
+ class <<base
124
+ alias_method :search, :solr_search unless method_defined? :search
125
+ alias_method :search_ids, :solr_search_ids unless method_defined? :search_ids
126
+ alias_method :remove_all_from_index, :solr_remove_all_from_index unless method_defined? :remove_all_from_index
127
+ alias_method :remove_all_from_index!, :solr_remove_all_from_index! unless method_defined? :remove_all_from_index!
128
+ alias_method :reindex, :solr_reindex unless method_defined? :reindex
129
+ alias_method :index, :solr_index unless method_defined? :index
130
+ alias_method :index_orphans, :solr_index_orphans unless method_defined? :index_orphans
131
+ alias_method :clean_index_orphans, :solr_clean_index_orphans unless method_defined? :clean_index_orphans
132
+ end
133
+ end
134
+ #
135
+ # Search for instances of this class in Solr. The block is delegated to
136
+ # the Sunspot.search method - see the Sunspot documentation for the full
137
+ # API.
138
+ #
139
+ # ==== Example
140
+ #
141
+ # Post.search(:include => [:blog]) do
142
+ # keywords 'best pizza'
143
+ # with :blog_id, 1
144
+ # order :updated_at, :desc
145
+ # facet :category_ids
146
+ # end
147
+ #
148
+ # ==== Options
149
+ #
150
+ # :include:: Specify associations to eager load
151
+ # :select:: Specify columns to select from database when loading results
152
+ #
153
+ # ==== Returns
154
+ #
155
+ # Sunspot::Search:: Object containing results, totals, facets, etc.
156
+ #
157
+ def solr_search(options = {}, &block)
158
+ solr_execute_search(options) do
159
+ Sunspot.new_search(self, &block)
160
+ end
161
+ end
162
+
163
+ #
164
+ # Get IDs of matching results without loading the result objects from
165
+ # the database. This method may be useful if search is used as an
166
+ # intermediate step in a larger find operation. The block is the same
167
+ # as the block provided to the #search method.
168
+ #
169
+ # ==== Returns
170
+ #
171
+ # Array:: Array of IDs, in the order returned by the search
172
+ #
173
+ def solr_search_ids(&block)
174
+ solr_execute_search_ids do
175
+ solr_search(&block)
176
+ end
177
+ end
178
+
179
+ #
180
+ # Remove instances of this class from the Solr index.
181
+ #
182
+ def solr_remove_all_from_index
183
+ Sunspot.remove_all(self)
184
+ end
185
+
186
+ #
187
+ # Remove all instances of this class from the Solr index and immediately
188
+ # commit.
189
+ #
190
+ #
191
+ def solr_remove_all_from_index!
192
+ Sunspot.remove_all!(self)
193
+ end
194
+
195
+ #
196
+ # Completely rebuild the index for this class. First removes all
197
+ # instances from the index, then loads records and indexes them.
198
+ #
199
+ # See #index for information on options, etc.
200
+ #
201
+ def solr_reindex(options = {})
202
+ solr_remove_all_from_index
203
+ solr_index(options)
204
+ end
205
+
206
+ #
207
+ # Add/update all existing records in the Solr index. The
208
+ # +batch_size+ argument specifies how many records to load out of the
209
+ # database at a time. The default batch size is 50; if nil is passed,
210
+ # records will not be indexed in batches. By default, a commit is issued
211
+ # after each batch; passing +false+ for +batch_commit+ will disable
212
+ # this, and only issue a commit at the end of the process. If associated
213
+ # objects need to indexed also, you can specify +include+ in format
214
+ # accepted by ActiveRecord to improve your sql select performance
215
+ #
216
+ # ==== Options (passed as a hash)
217
+ #
218
+ # batch_size<Integer>:: Batch size with which to load records. Passing
219
+ # 'nil' will skip batches. Default is 50.
220
+ # batch_commit<Boolean>:: Flag signalling if a commit should be done after
221
+ # after each batch is indexed, default is 'true'
222
+ # include<Mixed>:: include option to be passed to the ActiveRecord find,
223
+ # used for including associated objects that need to be
224
+ # indexed with the parent object, accepts all formats
225
+ # ActiveRecord::Base.find does
226
+ # first_id:: The lowest possible ID for this class. Defaults to 0, which
227
+ # is fine for integer IDs; string primary keys will need to
228
+ # specify something reasonable here.
229
+ #
230
+ # ==== Examples
231
+ #
232
+ # # index in batches of 50, commit after each
233
+ # Post.index
234
+ #
235
+ # # index all rows at once, then commit
236
+ # Post.index(:batch_size => nil)
237
+ #
238
+ # # index in batches of 50, commit when all batches complete
239
+ # Post.index(:batch_commit => false)
240
+ #
241
+ # # include the associated +author+ object when loading to index
242
+ # Post.index(:include => :author)
243
+ #
244
+ def solr_index(opts={})
245
+ options = {
246
+ :batch_size => Sunspot.config.indexing.default_batch_size,
247
+ :batch_commit => true,
248
+ :include => self.sunspot_options[:include],
249
+ :start => opts.delete(:first_id)
250
+ }.merge(opts)
251
+
252
+ if options[:batch_size].to_i > 0
253
+ batch_counter = 0
254
+ self.includes(options[:include]).find_in_batches(options.slice(:batch_size, :start)) do |records|
255
+
256
+ solr_benchmark(options[:batch_size], batch_counter += 1) do
257
+ Sunspot.index(records.select { |model| model.indexable? })
258
+ Sunspot.commit if options[:batch_commit]
259
+ end
260
+
261
+ options[:progress_bar].increment!(records.length) if options[:progress_bar]
262
+ end
263
+ else
264
+ Sunspot.index! self.includes(options[:include]).select(&:indexable?)
265
+ end
266
+
267
+ # perform a final commit if not committing in batches
268
+ Sunspot.commit unless options[:batch_commit]
269
+ end
270
+
271
+ #
272
+ # Return the IDs of records of this class that are indexed in Solr but
273
+ # do not exist in the database. Under normal circumstances, this should
274
+ # never happen, but this method is provided in case something goes
275
+ # wrong. Usually you will want to rectify the situation by calling
276
+ # #clean_index_orphans or #reindex
277
+ #
278
+ # ==== Options (passed as a hash)
279
+ #
280
+ # batch_size<Integer>:: Batch size with which to load records. Passing
281
+ # Default is 1000 (from ActiveRecord).
282
+ #
283
+ # ==== Returns
284
+ #
285
+ # Array:: Collection of IDs that exist in Solr but not in the database
286
+ def solr_index_orphans(opts={})
287
+ batch_size = opts[:batch_size] || Sunspot.config.indexing.default_batch_size
288
+
289
+ solr_page = 0
290
+ solr_ids = []
291
+ while (solr_page = solr_page.next)
292
+ ids = solr_search_ids { paginate(:page => solr_page, :per_page => 1000) }.to_a
293
+ break if ids.empty?
294
+ solr_ids.concat ids
295
+ end
296
+
297
+ return solr_ids - self.connection.select_values("SELECT id FROM #{quoted_table_name}").collect(&:to_i)
298
+ end
299
+
300
+ #
301
+ # Find IDs of records of this class that are indexed in Solr but do not
302
+ # exist in the database, and remove them from Solr. Under normal
303
+ # circumstances, this should not be necessary; this method is provided
304
+ # in case something goes wrong.
305
+ #
306
+ # ==== Options (passed as a hash)
307
+ #
308
+ # batch_size<Integer>:: Batch size with which to load records
309
+ # Default is 50
310
+ #
311
+ def solr_clean_index_orphans(opts={})
312
+ solr_index_orphans(opts).each do |id|
313
+ new do |fake_instance|
314
+ fake_instance.id = id
315
+ end.solr_remove_from_index
316
+ end
317
+ end
318
+
319
+ #
320
+ # Classes that have been defined as searchable return +true+ for this
321
+ # method.
322
+ #
323
+ # ==== Returns
324
+ #
325
+ # +true+
326
+ #
327
+ def searchable?
328
+ true
329
+ end
330
+
331
+ def solr_execute_search(options = {})
332
+ options.assert_valid_keys(:include, :select)
333
+ search = yield
334
+ unless options.empty?
335
+ search.build do |query|
336
+ if options[:include]
337
+ query.data_accessor_for(self).include = options[:include]
338
+ end
339
+ if options[:select]
340
+ query.data_accessor_for(self).select = options[:select]
341
+ end
342
+ end
343
+ end
344
+ search.execute
345
+ end
346
+
347
+ def solr_execute_search_ids(options = {})
348
+ search = yield
349
+ search.raw_results.map { |raw_result| raw_result.primary_key.to_i }
350
+ end
351
+
352
+ protected
353
+
354
+ #
355
+ # Does some logging for benchmarking indexing performance
356
+ #
357
+ def solr_benchmark(batch_size, counter, &block)
358
+ start = Time.now
359
+ logger.info("[#{Time.now}] Start Indexing")
360
+ yield
361
+ elapsed = Time.now-start
362
+ logger.info("[#{Time.now}] Completed Indexing. Rows indexed #{counter * batch_size}. Rows/sec: #{batch_size/elapsed.to_f} (Elapsed: #{elapsed} sec.)")
363
+ end
364
+
365
+ end
366
+
367
+ module InstanceMethods
368
+ def self.included(base) #:nodoc:
369
+ base.module_eval do
370
+ alias_method :index, :solr_index unless method_defined? :index
371
+ alias_method :index!, :solr_index! unless method_defined? :index!
372
+ alias_method :remove_from_index, :solr_remove_from_index unless method_defined? :remove_from_index
373
+ alias_method :remove_from_index!, :solr_remove_from_index! unless method_defined? :remove_from_index!
374
+ alias_method :more_like_this, :solr_more_like_this unless method_defined? :more_like_this
375
+ alias_method :more_like_this_ids, :solr_more_like_this_ids unless method_defined? :more_like_this_ids
376
+ end
377
+ end
378
+ #
379
+ # Index the model in Solr. If the model is already indexed, it will be
380
+ # updated. Using the defaults, you will usually not need to call this
381
+ # method, as models are indexed automatically when they are created or
382
+ # updated. If you have disabled automatic indexing (see
383
+ # ClassMethods#searchable), this method allows you to manage indexing
384
+ # manually.
385
+ #
386
+ def solr_index
387
+ Sunspot.index(self)
388
+ end
389
+
390
+ #
391
+ # Index the model in Solr and immediately commit. See #index
392
+ #
393
+ def solr_index!
394
+ Sunspot.index!(self)
395
+ end
396
+
397
+ #
398
+ # Remove the model from the Solr index. Using the defaults, this should
399
+ # not be necessary, as models will automatically be removed from the
400
+ # index when they are destroyed. If you disable automatic removal
401
+ # (which is not recommended!), you can use this method to manage removal
402
+ # manually.
403
+ #
404
+ def solr_remove_from_index
405
+ Sunspot.remove(self)
406
+ end
407
+
408
+ #
409
+ # Remove the model from the Solr index and commit immediately. See
410
+ # #remove_from_index
411
+ #
412
+ def solr_remove_from_index!
413
+ Sunspot.remove!(self)
414
+ end
415
+
416
+ def solr_more_like_this(*args, &block)
417
+ options = args.extract_options!
418
+ self.class.solr_execute_search(options) do
419
+ Sunspot.new_more_like_this(self, *args, &block)
420
+ end
421
+ end
422
+
423
+ def solr_more_like_this_ids(&block)
424
+ self.class.solr_execute_search_ids do
425
+ solr_more_like_this(&block)
426
+ end
427
+ end
428
+
429
+ def indexable?
430
+ # options[:if] is not specified or they successfully pass
431
+ if_passes = self.class.sunspot_options[:if].nil? ||
432
+ constraint_passes?(self.class.sunspot_options[:if])
433
+
434
+ # options[:unless] is not specified or they successfully pass
435
+ unless_passes = self.class.sunspot_options[:unless].nil? ||
436
+ !constraint_passes?(self.class.sunspot_options[:unless])
437
+
438
+ if_passes and unless_passes
439
+ end
440
+
441
+ private
442
+
443
+ def constraint_passes?(constraint)
444
+ case constraint
445
+ when Symbol
446
+ self.__send__(constraint)
447
+ when String
448
+ self.__send__(constraint.to_sym)
449
+ when Enumerable
450
+ # All constraints must pass
451
+ constraint.all? { |inner_constraint| constraint_passes?(inner_constraint) }
452
+ else
453
+ if constraint.respond_to?(:call) # could be a Proc or anything else that responds to call
454
+ constraint.call(self)
455
+ else
456
+ raise ArgumentError, "Unknown constraint type: #{constraint} (#{constraint.class})"
457
+ end
458
+ end
459
+ end
460
+
461
+ def mark_for_auto_indexing_or_removal
462
+ if indexable?
463
+ # :if/:unless constraints pass or were not present
464
+
465
+ @marked_for_auto_indexing =
466
+ if !new_record? && ignore_attributes = self.class.sunspot_options[:ignore_attribute_changes_of]
467
+ !(changed.map { |attr| attr.to_sym } - ignore_attributes).blank?
468
+ elsif !new_record? && only_attributes = self.class.sunspot_options[:only_reindex_attribute_changes_of]
469
+ !(changed.map { |attr| attr.to_sym } & only_attributes).blank?
470
+ else
471
+ true
472
+ end
473
+
474
+ @marked_for_auto_removal = false
475
+ else
476
+ # :if/:unless constraints did not pass; do not auto index and
477
+ # actually go one step further by removing it from the index
478
+ @marked_for_auto_indexing = false
479
+ @marked_for_auto_removal = true
480
+ end
481
+
482
+ true
483
+ end
484
+
485
+ def perform_index_tasks
486
+ if @marked_for_auto_indexing
487
+ solr_index
488
+ remove_instance_variable(:@marked_for_auto_indexing)
489
+ elsif @marked_for_auto_removal
490
+ solr_remove_from_index
491
+ remove_instance_variable(:@marked_for_auto_removal)
492
+ end
493
+ end
494
+ end
495
+ end
496
+ end
497
+ end
@@ -15,6 +15,19 @@ require 'active_record_sunspotter/sunspot_helper'
15
15
  # copied in this 1 file
16
16
  require 'active_record_sunspotter/sunspot_rails_2.1.0_sunspot_rails_adapters'
17
17
 
18
+ # for some reason, the :include key will inspire ...
19
+ # ArgumentError: Unknown key: :include. Valid keys are: :start, :batch_size
20
+ # Tasks: TOP => sunspot:solr:reindex => sunspot:reindex
21
+ # Seems to have been this way for some time, but now it errors.
22
+ # Using 2.1.0's version makes everyone happy?
23
+ require 'active_record_sunspotter/sunspot_rails_2.1.0_sunspot_rails_searchable'
24
+ # Somehow this requires the presence of a new file solr/solr.xml
25
+
26
+
27
+ # Really would just prefer to install 2.1.0, but it just won't work for me.
28
+ # Still wasting my time investigating though.
29
+ # Seems to be a java problem. Surprised?
30
+
18
31
 
19
32
  if defined?(Rails)
20
33
  require 'active_record_sunspotter/rails/engine'
@@ -0,0 +1,214 @@
1
+ #namespace :app do
2
+ # task :import => :environment do
3
+ # f = File.open('TheKingJamesBible.txt','r')
4
+ # {} until( ( line = f.gets ) =~ /^The First Book of Moses: Called Genesis\s*$/ )
5
+ # puts line
6
+ # f.close # File.open('TheKingJamesBible.txt','r')
7
+ # end # task :import => :environment do
8
+ #end # namespace :app do
9
+ namespace :app do
10
+ task :import => :environment do
11
+ File.open('data/TheKingJamesBible.txt','r') do |f|
12
+ until ( line = f.gets ).match(/^\*\*\*/)
13
+ # skip
14
+ end
15
+ while ( line = f.gets ).match(/^\s*$/)
16
+ # skip
17
+ end
18
+ puts line
19
+ # => The Old Testament of the King James Version of the Bible
20
+
21
+ chapter_num = verse_num = book = chapter = verse = nil
22
+ new_line_counter = 0
23
+ book_counter = 0
24
+ buffer = ''
25
+
26
+
27
+ # basic expectations ...
28
+ #
29
+ # book ends with >4 new lines but can include new lines (<=2 only)
30
+ # first verse is after >2 new lines
31
+
32
+ while cval = f.getc
33
+ next if cval == "\r" #13
34
+
35
+ if cval == "\n" #10
36
+ new_line_counter += 1
37
+ buffer << ' '
38
+ next
39
+ end
40
+
41
+
42
+ if new_line_counter > 4 && book && chapter && verse && !buffer.blank?
43
+ # last verse of book
44
+ puts "-- CH:#{chapter_num}:V:#{verse_num}:#{buffer}"
45
+ verse.body = buffer.squish
46
+ verse.save
47
+ buffer = ''
48
+ chapter_num = verse_num = book = chapter = verse = nil
49
+ end
50
+
51
+ # 2 new lines isn't just for new books
52
+ # some chapters are separated by 2 new lines
53
+ # so need more somehow. Psalms is causing the problem with the extra new line between chapters
54
+ # manually removed them
55
+ if new_line_counter > 2 && !buffer.blank?
56
+ puts "\n\nLooks like a new book is here:#{buffer.squish}:\n"
57
+ book_counter += 1
58
+ #book = buffer.squish
59
+ book = Book.create(:title => buffer.squish)
60
+ buffer = ''
61
+ end
62
+
63
+ buffer << cval #.chr
64
+
65
+ if buffer.match(/^([\D]*)(\d+):(\d+)\s+/) #or ( buffer =~ /^([\D]*)End of the Project Gutenberg EBook/ )
66
+ text = $1 # previous verse
67
+ if chapter_num && verse_num && text
68
+ puts "CH:#{chapter_num}:V:#{verse_num}:#{text}"
69
+ verse.body = text.squish
70
+ verse.save
71
+ end
72
+ #chapter = $2.squish #if $2
73
+ chapter = book.chapters.find_or_create_by(:position => $2.to_i)
74
+ chapter_num = $2.squish #if $2
75
+ ## I guess that the verse number is just going to be the position?
76
+ ## relax self! just a demo!
77
+ #verse = $3.squish #if $3
78
+ verse = chapter.verses.new(:position => $3.to_i) #create(:body => $3)
79
+ verse_num = $3.squish #if $3
80
+ buffer= ''
81
+ end
82
+
83
+ break if buffer =~ /End of the Project Gutenberg EBook/
84
+
85
+ # reset counter (perhaps way too often)
86
+ new_line_counter = 0 if cval != "\n" # 10
87
+ end
88
+ puts book_counter
89
+ end # File
90
+ end # task
91
+
92
+ end # namespace
93
+
94
+ __END__
95
+
96
+
97
+ 40:38 For the cloud of the LORD was upon the tabernacle by day, and
98
+ fire was on it by night, in the sight of all the house of Israel,
99
+ throughout all their journeys.
100
+
101
+
102
+
103
+
104
+ The Third Book of Moses: Called Leviticus
105
+
106
+
107
+ 1:1 And the LORD called unto Moses, and spake unto him out of the
108
+ tabernacle of the congregation, saying, 1:2 Speak unto the children of
109
+ Israel, and say unto them, If any man of you bring an offering unto
110
+ the LORD, ye shall bring your offering of the cattle, even of the
111
+ herd, and of the flock.
112
+
113
+
114
+
115
+ CH:40:V:37:But if the cloud were not taken up, then they journeyed not till the day that it was taken up.
116
+ create new book with title:For the cloud of the LORD was upon the tabernacle by day, and fire was on it by night, in the sight of all the house of Israel, throughout all their journeys. :
117
+ create new book with title: The Third Book of Moses: Called Leviticus :
118
+ CH:1:V:1:And the LORD called unto Moses, and spake unto him out of the tabernacle of the congregation, saying,
119
+ CH:1:V:2:Speak unto the children of Israel, and
120
+
121
+
122
+ The First Book of Moses: Called Genesis
123
+
124
+
125
+ 1:1 In the beginning God created the heaven and the earth.
126
+
127
+ 1:2 And the earth was without form, and void; and darkness was upon
128
+ the face of the deep. And the Spirit of God moved upon the face of the
129
+ waters.
130
+
131
+ FYI, some verses actually have multiple "paragraphs" .
132
+
133
+ Also, some verses are merged on the same line?
134
+
135
+ 3:1 Now the serpent was more subtil than any beast of the field which
136
+ the LORD God had made. And he said unto the woman, Yea, hath God said,
137
+ Ye shall not eat of every tree of the garden? 3:2 And the woman said
138
+ unto the serpent, We may eat of the fruit of the trees of the garden:
139
+ 3:3 But of the fruit of the tree which is in the midst of the garden,
140
+ God hath said, Ye shall not eat of it, neither shall ye touch it, lest
141
+ ye die.
142
+
143
+
144
+
145
+
146
+ 50:26 So Joseph died, being an hundred and ten years old: and they
147
+ embalmed him, and he was put in a coffin in Egypt.
148
+
149
+
150
+
151
+
152
+ The Second Book of Moses: Called Exodus
153
+
154
+
155
+ 1:1 Now these are the names of the children of Israel, which came
156
+ into Egypt; every man and his household came with Jacob.
157
+
158
+ 1:2 Reuben, Simeon, Levi, and Judah, 1:3 Issachar, Zebulun, and
159
+ Benjamin, 1:4 Dan, and Naphtali, Gad, and Asher.
160
+
161
+ 1:5 And all the souls that came out of the loins of Jacob were seventy
162
+ souls: for Joseph was in Egypt already.
163
+
164
+ 1:6 And Joseph died, and all his brethren, and all that generation.
165
+
166
+ 1:7 And the children of Israel were fruitful, and increased
167
+ abundantly, and multiplied, and waxed exceeding mighty; and the land
168
+ was filled with them.
169
+
170
+ 1:8 Now there arose up a new king over Egypt, which knew not Joseph.
171
+
172
+ 1:9 And he said unto his people, Behold, the people of the children of
173
+ Israel are more and mightier than we: 1:10 Come on, let us deal wisely
174
+ with them; lest they multiply, and it come to pass, that, when there
175
+ falleth out any war, they join also unto our enemies, and fight
176
+ against us, and so get them up out of the land.
177
+
178
+ 1:11 Therefore they did set over them taskmasters to afflict them with
179
+ their burdens. And they built for Pharaoh treasure cities, Pithom and
180
+ Raamses.
181
+
182
+ 1:12 But the more they afflicted them, the more they multiplied and
183
+ grew.
184
+
185
+ And they were grieved because of the children of Israel.
186
+
187
+
188
+
189
+
190
+
191
+
192
+ 4:5 Behold, I will send you Elijah the prophet before the coming of
193
+ the great and dreadful day of the LORD: 4:6 And he shall turn the
194
+ heart of the fathers to the children, and the heart of the children to
195
+ their fathers, lest I come and smite the earth with a curse.
196
+
197
+
198
+ ***
199
+
200
+
201
+
202
+
203
+ The New Testament of the King James Bible
204
+
205
+
206
+
207
+
208
+ The Gospel According to Saint Matthew
209
+
210
+
211
+ 1:1 The book of the generation of Jesus Christ, the son of David, the
212
+ son of Abraham.
213
+
214
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jakewendt-active_record_sunspotter
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - George 'Jake' Wendt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-18 00:00:00.000000000 Z
11
+ date: 2014-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sunspot_rails
@@ -42,14 +42,154 @@ dependencies:
42
42
  name: progress_bar
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: will_paginate
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '4.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sass-rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 4.0.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 4.0.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: uglifier
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: 1.3.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: 1.3.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: turbolinks
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: jbuilder
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ~>
144
+ - !ruby/object:Gem::Version
145
+ version: '1.2'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ~>
151
+ - !ruby/object:Gem::Version
152
+ version: '1.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: american_date
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: acts_as_list
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: jeweler
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - '>='
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - '>='
53
193
  - !ruby/object:Gem::Version
54
194
  version: '0'
55
195
  description: active_record_sunspotter
@@ -66,9 +206,11 @@ files:
66
206
  - lib/active_record_sunspotter/sunspot_column.rb
67
207
  - lib/active_record_sunspotter/sunspot_helper.rb
68
208
  - lib/active_record_sunspotter/sunspot_rails_2.1.0_sunspot_rails_adapters.rb
209
+ - lib/active_record_sunspotter/sunspot_rails_2.1.0_sunspot_rails_searchable.rb
69
210
  - lib/active_record_sunspotter/sunspot_rails_server.rb
70
211
  - lib/active_record_sunspotter/sunspotability.rb
71
212
  - lib/jakewendt-active_record_sunspotter.rb
213
+ - lib/tasks/application.rake
72
214
  - vendor/assets/javascripts/sunspot.js
73
215
  - vendor/assets/stylesheets/sunspot.css.scss
74
216
  - vendor/views/layouts/_footer.html.erb
@@ -94,12 +236,12 @@ require_paths:
94
236
  - lib
95
237
  required_ruby_version: !ruby/object:Gem::Requirement
96
238
  requirements:
97
- - - ">="
239
+ - - '>='
98
240
  - !ruby/object:Gem::Version
99
241
  version: '0'
100
242
  required_rubygems_version: !ruby/object:Gem::Requirement
101
243
  requirements:
102
- - - ">="
244
+ - - '>='
103
245
  - !ruby/object:Gem::Version
104
246
  version: '0'
105
247
  requirements: []