picky 3.4.3 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/aux/picky/cli.rb +1 -1
  2. data/lib/picky/backends/memory/json.rb +1 -1
  3. data/lib/picky/backends/memory/text.rb +2 -2
  4. data/lib/picky/backends/redis/string.rb +6 -0
  5. data/lib/picky/bundle.rb +0 -1
  6. data/lib/picky/bundle_indexing.rb +11 -107
  7. data/lib/picky/bundle_realtime.rb +16 -8
  8. data/lib/picky/calculations/location.rb +18 -14
  9. data/lib/picky/categories.rb +1 -1
  10. data/lib/picky/category.rb +7 -1
  11. data/lib/picky/category_indexed.rb +1 -0
  12. data/lib/picky/category_indexing.rb +17 -17
  13. data/lib/picky/category_realtime.rb +23 -11
  14. data/lib/picky/deployment.rb +33 -33
  15. data/lib/picky/generators/partial/substring.rb +0 -2
  16. data/lib/picky/generators/similarity/double_metaphone.rb +1 -1
  17. data/lib/picky/generators/similarity/metaphone.rb +1 -1
  18. data/lib/picky/generators/similarity/soundex.rb +1 -1
  19. data/lib/picky/index.rb +22 -5
  20. data/lib/picky/index_indexing.rb +3 -15
  21. data/lib/picky/indexers/base.rb +7 -3
  22. data/lib/picky/indexers/parallel.rb +1 -10
  23. data/lib/picky/indexers/serial.rb +1 -10
  24. data/lib/picky/indexes.rb +1 -1
  25. data/lib/picky/loader.rb +2 -6
  26. data/lib/picky/query/qualifier_category_mapper.rb +2 -2
  27. data/lib/picky/query/token.rb +1 -2
  28. data/lib/picky/query/tokens.rb +6 -0
  29. data/lib/picky/search.rb +1 -0
  30. data/lib/picky/sources/couch.rb +1 -1
  31. data/lib/picky/sources/csv.rb +1 -1
  32. data/lib/picky/sources/mongo.rb +1 -1
  33. data/lib/picky/wrappers/bundle/calculation.rb +8 -8
  34. data/lib/picky/wrappers/bundle/delegators.rb +4 -1
  35. data/lib/picky/wrappers/bundle/exact_partial.rb +1 -1
  36. data/lib/picky/wrappers/bundle/location.rb +30 -13
  37. data/lib/picky/wrappers/category/location.rb +14 -9
  38. data/lib/tasks/try.rb +2 -2
  39. data/spec/lib/backends/memory/text_spec.rb +6 -6
  40. data/spec/lib/bundle_spec.rb +4 -4
  41. data/spec/lib/calculations/location_spec.rb +27 -29
  42. data/spec/lib/category_indexed_spec.rb +1 -0
  43. data/spec/lib/category_indexing_spec.rb +23 -36
  44. data/spec/lib/category_spec.rb +2 -0
  45. data/spec/lib/extensions/string_spec.rb +1 -1
  46. data/spec/lib/generators/partial/infix_spec.rb +2 -2
  47. data/spec/lib/index_indexing_spec.rb +5 -3
  48. data/spec/lib/indexed/bundle_spec.rb +2 -2
  49. data/spec/lib/indexers/base_spec.rb +2 -4
  50. data/spec/lib/indexers/serial_spec.rb +3 -19
  51. data/spec/lib/indexing/bundle_partial_generation_speed_spec.rb +42 -42
  52. data/spec/lib/indexing/bundle_spec.rb +4 -133
  53. data/spec/lib/query/combination_spec.rb +6 -6
  54. data/spec/lib/query/token_spec.rb +32 -19
  55. data/spec/lib/query/tokens_spec.rb +23 -10
  56. metadata +27 -34
  57. data/lib/picky/no_source_specified_exception.rb +0 -7
  58. data/lib/picky/wrappers/sources/base.rb +0 -35
  59. data/lib/picky/wrappers/sources/location.rb +0 -56
  60. data/spec/lib/sources/wrappers/base_spec.rb +0 -38
  61. data/spec/lib/sources/wrappers/location_spec.rb +0 -55
@@ -2,14 +2,14 @@ require File.expand_path '../constants', __FILE__
2
2
 
3
3
  module Picky # :nodoc:
4
4
  module Capistrano # :nodoc:all
5
-
6
- # Include all
5
+
6
+ # Include all
7
7
  #
8
8
  module All
9
9
  def self.extended cap_config
10
-
10
+
11
11
  cap_config.instance_eval do
12
-
12
+
13
13
  # Executes a rake task on the server.
14
14
  #
15
15
  # Options:
@@ -21,56 +21,56 @@ module Picky # :nodoc:
21
21
  env = env == false ? '' : "PICKY_ENV=#{env || 'production'}"
22
22
  run "cd #{current_path}; rake #{name} #{env}", options, &block
23
23
  end
24
-
24
+
25
25
  end
26
-
26
+
27
27
  cap_config.extend Standard
28
28
  cap_config.extend Deploy
29
29
  cap_config.extend Caching
30
30
  cap_config.extend Overrides
31
-
31
+
32
32
  end
33
33
  end
34
-
34
+
35
35
  # Removes unneeded Rails defaults.
36
36
  #
37
37
  module Overrides
38
38
  def self.extended cap_config
39
39
  cap_config.instance_eval do
40
-
40
+
41
41
  namespace :deploy do
42
42
  tasks.delete :check
43
43
  tasks.delete :cold
44
44
  tasks.delete :migrations
45
45
  tasks.delete :migrate
46
46
  tasks.delete :upload
47
-
47
+
48
48
  namespace :web do
49
49
  tasks.delete :enable
50
50
  tasks.delete :disable
51
51
  end
52
52
  end
53
-
53
+
54
54
  end
55
55
  end
56
56
  end
57
-
57
+
58
58
  module Standard
59
59
  def self.extended cap_config
60
60
  cap_config.load 'standard'
61
61
  cap_config.load 'deploy'
62
62
  end
63
63
  end
64
-
64
+
65
65
  module Deploy
66
-
66
+
67
67
  def self.extended cap_config
68
68
  cap_config.instance_eval do
69
-
69
+
70
70
  namespace :deploy do
71
71
  %w(start stop).each do |action|
72
72
  desc "#{action} the Servers"
73
- task action.to_sym, :roles => :app do
73
+ task action.intern, :roles => :app do
74
74
  execute_rake_task "server:#{action}"
75
75
  end
76
76
  end
@@ -80,13 +80,13 @@ module Picky # :nodoc:
80
80
  execute_rake_task "server:restart", :hosts => server.host
81
81
  end
82
82
  end
83
-
83
+
84
84
  desc 'Hot deploy the code'
85
85
  task 'hot', :roles => :app do
86
86
  update
87
87
  execute_rake_task 'server:usr1', :env => false # No env needed.
88
88
  end
89
-
89
+
90
90
  desc "Setup a GitHub-style deployment."
91
91
  task :setup, :roles => :app do
92
92
  cmd = "git clone #{repository} #{current_path}-clone-cache &&" +
@@ -94,13 +94,13 @@ module Picky # :nodoc:
94
94
  "mv #{current_path}-clone-cache #{current_path}"
95
95
  run cmd
96
96
  end
97
-
97
+
98
98
  desc "Deploy"
99
99
  task :default, :roles => :app do
100
100
  update
101
101
  restart
102
102
  end
103
-
103
+
104
104
  desc "Update the deployed code."
105
105
  task :update_code do # code needs to be updated with all servers
106
106
  puts "updating code to branch #{branch}"
@@ -112,12 +112,12 @@ module Picky # :nodoc:
112
112
  run cmd
113
113
  symlink
114
114
  end
115
-
115
+
116
116
  desc "Cleans up the git checkout"
117
117
  task :cleanup, :roles => :app do
118
118
  run "cd #{current_path} && git gc --aggressive"
119
119
  end
120
-
120
+
121
121
  desc "create the symlinks to the shared dirs"
122
122
  task :symlink do
123
123
  set :user, 'deploy'
@@ -128,7 +128,7 @@ module Picky # :nodoc:
128
128
  # link unicorn.ru
129
129
  run "ln -sf #{shared_path}/unicorn.ru #{current_path}/unicorn.ru"
130
130
  end
131
-
131
+
132
132
  namespace :rollback do
133
133
  desc "Rollback to last release."
134
134
  task :default, :roles => :app do
@@ -136,20 +136,20 @@ module Picky # :nodoc:
136
136
  puts "rolling back to branch #{branch}"
137
137
  deploy.update_code
138
138
  end
139
-
139
+
140
140
  task :code, :roles => :app do
141
141
  # implicit
142
142
  end
143
143
  end
144
144
  end
145
-
145
+
146
146
  end
147
147
  end
148
-
148
+
149
149
  end
150
-
150
+
151
151
  module Caching
152
-
152
+
153
153
  def self.extended cap_config
154
154
  cap_config.instance_eval do
155
155
  namespace :cache do
@@ -180,11 +180,11 @@ module Picky # :nodoc:
180
180
  end
181
181
  end
182
182
  end
183
-
183
+
184
184
  end
185
-
185
+
186
186
  module Statistics
187
-
187
+
188
188
  def self.extended cap_config
189
189
  namespace :statistics do
190
190
  desc 'Start the statistics server'
@@ -204,8 +204,8 @@ module Picky # :nodoc:
204
204
  end
205
205
  end
206
206
  end
207
-
207
+
208
208
  end
209
-
209
+
210
210
  end
211
211
  end
@@ -21,12 +21,10 @@ module Picky
21
21
  if @from < 0 && @to < 0
22
22
  def each_subtoken token, &block
23
23
  token.each_subtoken @from - @to - 1, (0..@to), &block
24
- # token[0..@to].intern.each_subtoken @from - @to - 1, &block # TODO to_sym
25
24
  end
26
25
  else
27
26
  def each_subtoken token, &block
28
27
  token.each_subtoken @from, (0..@to), &block
29
- # token[0..@to].intern.each_subtoken @from, &block # TODO to_sym
30
28
  end
31
29
  end
32
30
  end
@@ -20,7 +20,7 @@ module Picky
20
20
  #
21
21
  def encoded sym
22
22
  codes = Text::Metaphone.double_metaphone sym.to_s
23
- codes.first.to_sym unless codes.empty?
23
+ codes.first.intern unless codes.empty?
24
24
  end
25
25
 
26
26
  end
@@ -20,7 +20,7 @@ module Picky
20
20
  #
21
21
  def encoded sym
22
22
  code = Text::Metaphone.metaphone sym.to_s
23
- code.to_sym if code
23
+ code.intern if code
24
24
  end
25
25
 
26
26
  end
@@ -20,7 +20,7 @@ module Picky
20
20
  #
21
21
  def encoded sym
22
22
  code = Text::Soundex.soundex sym.to_s
23
- code.to_sym if code
23
+ code.intern if code
24
24
  end
25
25
 
26
26
  end
data/lib/picky/index.rb CHANGED
@@ -115,7 +115,7 @@ module Picky
115
115
  # end
116
116
  #
117
117
  def initialize name
118
- @name = name.to_sym
118
+ @name = name.intern
119
119
  @categories = Categories.new
120
120
 
121
121
  # Centralized registry.
@@ -138,6 +138,21 @@ module Picky
138
138
  end
139
139
  end
140
140
 
141
+ # TODO Symbols.
142
+ #
143
+ # # API method.
144
+ # #
145
+ # # Tells Picky to use Symbols internally.
146
+ # #
147
+ # def use_symbols
148
+ # @symbols = true
149
+ # end
150
+ # def use_symbols?
151
+ # @symbols
152
+ # end
153
+
154
+ # API method.
155
+ #
141
156
  # Defines a searchable category on the index.
142
157
  #
143
158
  # === Parameters
@@ -152,7 +167,7 @@ module Picky
152
167
  # * from: Take the data from the data category with this name. Example: You have a source Sources::CSV.new(:title, file:'some_file.csv') but you want the category to be called differently. The you use from: define_category(:similar_title, :from => :title).
153
168
  #
154
169
  def category category_name, options = {}
155
- new_category = Category.new category_name.to_sym, self, options
170
+ new_category = Category.new category_name.intern, self, options
156
171
  categories << new_category
157
172
 
158
173
  new_category = yield new_category if block_given?
@@ -222,17 +237,19 @@ module Picky
222
237
  #
223
238
  # === Options
224
239
  # * precision: Default is 1 (20% error margin, very fast), up to 5 (5% error margin, slower) makes sense.
240
+ # * anchor: Where to anchor the geo grid.
225
241
  # * ... all options of #define_category.
226
242
  #
227
243
  def ranged_category category_name, range, options = {}
228
- precision = options[:precision] || 1 # THINK options.delete?
244
+ precision = options.delete(:precision) || 1
245
+ anchor = options.delete(:anchor) || 0.0
229
246
 
230
247
  # Note: :key_format => :to_f ?
231
248
  #
232
249
  options = { partial: Partial::None.new }.merge options
233
250
 
234
251
  define_category category_name, options do |category|
235
- Wrappers::Category::Location.wrap category, range, precision
252
+ Wrappers::Category::Location.wrap category, range, precision, anchor
236
253
  end
237
254
  end
238
255
  alias define_ranged_category ranged_category
@@ -312,7 +329,7 @@ INDEX
312
329
  # Identifier used for technical output.
313
330
  #
314
331
  def identifier
315
- "#{PICKY_ENVIRONMENT}:#{name}"
332
+ name
316
333
  end
317
334
 
318
335
  #
@@ -93,7 +93,7 @@ module Picky
93
93
  #
94
94
  def source some_source = nil, &block
95
95
  some_source ||= block
96
- some_source ? define_source(some_source) : (@source && extract_source || raise_no_source)
96
+ some_source ? define_source(some_source) : (@source && extract_source || warn_no_source)
97
97
  end
98
98
  # Extract the actual source if it is wrapped in a time
99
99
  # capsule, i.e. a block/lambda.
@@ -107,20 +107,8 @@ module Picky
107
107
  check_source source
108
108
  @source = source
109
109
  end
110
- def raise_no_source
111
- raise NoSourceSpecifiedException.new(<<-NO_SOURCE
112
-
113
-
114
- No source given for index #{name}. An index needs a source.
115
- Example:
116
- Index.new(:with_source) do
117
- source Sources::CSV.new(:title, file: 'data/books.csv')
118
- category :title
119
- category :author
120
- end
121
-
122
- NO_SOURCE
123
- )
110
+ def warn_no_source
111
+ warn "No source given for index #{name}."
124
112
  end
125
113
  def check_source source # :nodoc:
126
114
  raise ArgumentError.new(<<-SOURCE
@@ -19,9 +19,13 @@ module Picky
19
19
  # Starts the indexing process.
20
20
  #
21
21
  def index categories
22
- start_indexing_message
23
- process categories
24
- finish_indexing_message
22
+ process categories do |file|
23
+ notify_finished file
24
+ end
25
+ end
26
+
27
+ def notify_finished file
28
+ timed_exclaim %Q{"#{@index_or_category.identifier}": Tokenized -> #{file.path.gsub("#{PICKY_ROOT}/", '')}.}
25
29
  end
26
30
 
27
31
  end
@@ -60,7 +60,7 @@ module Picky
60
60
  end
61
61
  flush combined
62
62
  combined.each do |_, _, file, _|
63
- timed_exclaim %Q{"#{@index_or_category.identifier}": => #{file.path}.}
63
+ yield file
64
64
  file.close
65
65
  end
66
66
  end
@@ -73,15 +73,6 @@ module Picky
73
73
  end
74
74
  end
75
75
 
76
- #
77
- #
78
- def start_indexing_message # :nodoc:
79
- timed_exclaim %Q{"#{@index_or_category.identifier}": Starting parallel data preparation.}
80
- end
81
- def finish_indexing_message # :nodoc:
82
- timed_exclaim %Q{"#{@index_or_category.identifier}": Finished parallel data preparation.}
83
- end
84
-
85
76
  end
86
77
 
87
78
  end
@@ -36,7 +36,7 @@ module Picky
36
36
  file.write(result.join) && result.clear if result.size > 100_000
37
37
  end
38
38
 
39
- timed_exclaim %Q{"#{@index_or_category.identifier}": => #{file.path}.}
39
+ yield file
40
40
 
41
41
  file.write result.join
42
42
  end
@@ -45,15 +45,6 @@ module Picky
45
45
 
46
46
  end
47
47
 
48
- #
49
- #
50
- def start_indexing_message # :nodoc:
51
- timed_exclaim %Q{"#{@index_or_category.identifier}": Starting serial data preparation.}
52
- end
53
- def finish_indexing_message # :nodoc:
54
- timed_exclaim %Q{"#{@index_or_category.identifier}": Finished serial data preparation.}
55
- end
56
-
57
48
  end
58
49
  end
59
50
 
data/lib/picky/indexes.rb CHANGED
@@ -61,7 +61,7 @@ module Picky
61
61
  # Extracts an index, given its identifier.
62
62
  #
63
63
  def [] identifier
64
- index_name = identifier.to_sym
64
+ index_name = identifier.intern
65
65
  index_mapping[index_name] || raise_not_found(index_name)
66
66
  end
67
67
 
data/lib/picky/loader.rb CHANGED
@@ -143,8 +143,8 @@ module Picky
143
143
  load_relative 'wrappers/bundle/location'
144
144
  load_relative 'wrappers/bundle/exact_partial'
145
145
 
146
- load_relative 'wrappers/sources/base'
147
- load_relative 'wrappers/sources/location'
146
+ # load_relative 'wrappers/sources/base'
147
+ # load_relative 'wrappers/sources/location'
148
148
 
149
149
  # Tokens.
150
150
  #
@@ -188,10 +188,6 @@ module Picky
188
188
  #
189
189
  load_relative 'rack/harakiri'
190
190
 
191
- # Errors.
192
- #
193
- load_relative 'no_source_specified_exception'
194
-
195
191
  # Load analyzer.
196
192
  #
197
193
  load_relative 'analyzer'
@@ -20,7 +20,7 @@ module Picky
20
20
  #
21
21
  def add category
22
22
  category.qualifiers.each do |qualifier|
23
- sym_qualifier = qualifier.to_sym
23
+ sym_qualifier = qualifier.intern
24
24
  warn %Q{Warning: Qualifier "#{qualifier}" already mapped to category #{mapping[sym_qualifier].identifier} (ambiguous qualifier mapping).} if mapping.has_key? sym_qualifier
25
25
  mapping[sym_qualifier] = category
26
26
  end
@@ -33,7 +33,7 @@ module Picky
33
33
  def map qualifier
34
34
  return nil if qualifier.empty?
35
35
 
36
- @mapping[qualifier.to_sym]
36
+ @mapping[qualifier.intern]
37
37
  end
38
38
 
39
39
  end
@@ -37,13 +37,12 @@ module Picky
37
37
  partialize # TODO Should this operate on the original?
38
38
  similarize # TODO Should this operate on the original?
39
39
  remove_illegals # TODO Remove?
40
- symbolize # TODO to_sym
41
40
  self
42
41
  end
43
42
 
44
43
  #
45
44
  #
46
- def symbolize
45
+ def symbolize!
47
46
  @text = @text.to_sym
48
47
  end
49
48
 
@@ -61,6 +61,12 @@ module Picky
61
61
  end
62
62
  end
63
63
 
64
+ # Symbolizes each of the tokens.
65
+ #
66
+ def symbolize
67
+ @tokens.each &:symbolize!
68
+ end
69
+
64
70
  # Makes the last of the tokens partial.
65
71
  #
66
72
  def partialize_last
data/lib/picky/search.rb CHANGED
@@ -175,6 +175,7 @@ module Picky
175
175
  def tokenized text
176
176
  tokens, originals = tokenizer.tokenize text
177
177
  tokens = Query::Tokens.processed tokens, originals || tokens, @ignore_unassigned
178
+ # tokens.symbolize # TODO Symbols.
178
179
  tokens.partialize_last # Note: In the standard Picky search, the last token is always partial.
179
180
  tokens
180
181
  end
@@ -32,7 +32,7 @@ module Picky
32
32
  @db = RestClient::Resource.new options.delete(:url), options
33
33
 
34
34
  key_format = options.delete :key_format
35
- @key_format = key_format && key_format.to_sym || :to_sym
35
+ @key_format = key_format && key_format.intern || :to_sym
36
36
  end
37
37
 
38
38
  def to_s
@@ -42,7 +42,7 @@ module Picky
42
42
  @file_name = @csv_options.delete(:file) || raise_no_file_given(category_names)
43
43
 
44
44
  key_format = options.delete :key_format
45
- @key_format = key_format && key_format.to_sym || :to_i
45
+ @key_format = key_format && key_format.intern || :to_i
46
46
  end
47
47
 
48
48
  def to_s
@@ -37,7 +37,7 @@ module Picky
37
37
 
38
38
  @db = RestClient::Resource.new options.delete(:url), options
39
39
  @database = options.delete(:db)
40
- @key_format = options[:key_format] && options[:key_format].to_sym || :to_sym
40
+ @key_format = options[:key_format] && options[:key_format].intern || :to_sym
41
41
  end
42
42
 
43
43
  # Tries to require the rest_client gem.
@@ -18,22 +18,22 @@ module Picky
18
18
  # API.
19
19
  #
20
20
  # By default, a calculation does not
21
- # recalculate anything.
21
+ # calculate anything.
22
22
  #
23
- def recalculate float
23
+ def calculate float
24
24
  float
25
25
  end
26
26
 
27
+ # TODO Symbols.
27
28
  #
28
- #
29
- def ids float_as_sym
30
- @bundle.ids recalculate(float_as_sym.to_s.to_f).to_s.to_sym
29
+ def ids float_str
30
+ @bundle.ids calculate(float_str.to_f).to_s
31
31
  end
32
32
 
33
+ # TODO Symbols.
33
34
  #
34
- #
35
- def weight float_as_sym
36
- @bundle.weight recalculate(float_as_sym.to_s.to_f).to_s.to_sym
35
+ def weight float_str
36
+ @bundle.weight calculate(float_str.to_f).to_s
37
37
  end
38
38
 
39
39
  end
@@ -6,7 +6,10 @@ module Picky
6
6
 
7
7
  module Delegator
8
8
 
9
- delegate :inverted,
9
+ delegate :add,
10
+ :clear_realtime_mapping,
11
+
12
+ :inverted,
10
13
  :weights,
11
14
  :similarity,
12
15
  :configuration,
@@ -23,7 +23,7 @@ module Picky
23
23
 
24
24
  def clear; end
25
25
  def dump; end
26
- def empty_configuration; end
26
+ def empty; end
27
27
  def generate_caches_from_memory; end
28
28
  def generate_partial_from arg; end
29
29
  def index; end
@@ -11,32 +11,49 @@ module Picky
11
11
  def initialize bundle, options = {}
12
12
  super bundle
13
13
 
14
+ user_grid = options[:grid] || raise("Gridsize needs to be given for location #{bundle.identifier}.")
15
+ anchor = options[:anchor] || 0.0
14
16
  precision = options[:precision] || 1
15
- user_grid = options[:grid] || raise("Gridsize needs to be given for location #{bundle.identifier}.")
16
17
 
17
- @calculation = Calculations::Location.new user_grid, precision
18
+ @calculation = Calculations::Location.new user_grid, anchor, precision
18
19
  end
19
20
 
20
21
  #
21
22
  #
22
- def recalculate float
23
- @calculation.recalculate float
23
+ def calculate float
24
+ @calculation.calculate float
24
25
  end
25
26
 
27
+ # Recalculates the added location.
26
28
  #
27
- #
28
- def load
29
- # Load first the bundle, then extract the config.
30
- #
31
- bundle.load
32
- minimum = bundle[:location_minimum] && bundle[:location_minimum].to_f || raise("Configuration :location_minimum for #{bundle.identifier} missing. Did you run rake index already?")
33
- @calculation.minimum = minimum
29
+ def add id, location, where = :unshift
30
+ @calculation.calculated_range(location.to_s.to_f).each do |new_location|
31
+ bundle.add id, new_location.to_s, where
32
+ end
34
33
  end
35
34
 
36
35
  # Do not generate a partial.
37
36
  #
38
- def generate_partial_from unimportant
39
- # Nothing.
37
+ def add_partialized does_not, matter, at_all
38
+ # Nothing
39
+ end
40
+
41
+ # Save the config, then dump normally.
42
+ #
43
+ def dump
44
+ bundle[:location_anchor] = @calculation.anchor
45
+
46
+ bundle.dump
47
+ end
48
+
49
+ # Load first the bundle, then extract the config.
50
+ #
51
+ def load
52
+ bundle.load
53
+
54
+ # TODO Symbols (of the location_anchor!!!).
55
+ #
56
+ @calculation.anchor = bundle['location_anchor'] && bundle['location_anchor'].to_f || raise("Configuration 'location_anchor' for #{bundle.identifier} missing. Did you run rake index already?")
40
57
  end
41
58
 
42
59
  end