picky 2.6.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/lib/picky/analyzer.rb +4 -4
  2. data/lib/picky/application.rb +6 -7
  3. data/lib/picky/backend/{backend.rb → base.rb} +31 -14
  4. data/lib/picky/backend/file/basic.rb +12 -4
  5. data/lib/picky/backend/file/json.rb +5 -5
  6. data/lib/picky/backend/file/text.rb +1 -1
  7. data/lib/picky/backend/files.rb +3 -9
  8. data/lib/picky/backend/redis/basic.rb +8 -0
  9. data/lib/picky/backend/redis/list_hash.rb +5 -5
  10. data/lib/picky/backend/redis/string_hash.rb +5 -5
  11. data/lib/picky/backend/redis.rb +5 -5
  12. data/lib/picky/bundle.rb +62 -0
  13. data/lib/picky/categories.rb +10 -9
  14. data/lib/picky/categories_indexed.rb +12 -7
  15. data/lib/picky/categories_indexing.rb +7 -9
  16. data/lib/picky/category.rb +38 -26
  17. data/lib/picky/category_indexed.rb +4 -20
  18. data/lib/picky/category_indexing.rb +71 -68
  19. data/lib/picky/generators/base.rb +6 -6
  20. data/lib/picky/generators/partial/substring.rb +28 -26
  21. data/lib/picky/generators/partial_generator.rb +3 -3
  22. data/lib/picky/generators/similarity/phonetic.rb +5 -5
  23. data/lib/picky/generators/similarity_generator.rb +2 -2
  24. data/lib/picky/generators/weights/logarithmic.rb +3 -3
  25. data/lib/picky/generators/weights_generator.rb +2 -2
  26. data/lib/picky/index/base.rb +13 -10
  27. data/lib/picky/index/base_indexed.rb +2 -0
  28. data/lib/picky/index/base_indexing.rb +65 -57
  29. data/lib/picky/indexed/bundle/base.rb +21 -86
  30. data/lib/picky/indexed/bundle/memory.rb +5 -12
  31. data/lib/picky/indexed/bundle/redis.rb +42 -0
  32. data/lib/picky/indexed/wrappers/bundle/wrapper.rb +3 -3
  33. data/lib/picky/indexers/base.rb +20 -3
  34. data/lib/picky/indexers/parallel.rb +32 -14
  35. data/lib/picky/indexers/serial.rb +29 -26
  36. data/lib/picky/indexes.rb +5 -3
  37. data/lib/picky/indexes_indexed.rb +3 -15
  38. data/lib/picky/indexes_indexing.rb +18 -21
  39. data/lib/picky/indexing/bundle/base.rb +64 -45
  40. data/lib/picky/indexing/bundle/memory.rb +0 -4
  41. data/lib/picky/loader.rb +7 -6
  42. data/lib/picky/query/allocation.rb +3 -3
  43. data/lib/picky/query/token.rb +5 -1
  44. data/lib/picky/search.rb +5 -0
  45. data/lib/picky/sources/base.rb +21 -2
  46. data/lib/picky/sources/db.rb +0 -7
  47. data/lib/picky/statistics.rb +9 -12
  48. data/lib/picky/tokenizers/location.rb +1 -1
  49. data/lib/tasks/checks.rake +8 -6
  50. data/lib/tasks/index.rake +14 -20
  51. data/lib/tasks/server.rake +18 -2
  52. data/lib/tasks/statistics.rake +27 -14
  53. data/lib/tasks/todo.rake +2 -2
  54. data/lib/tasks/try.rake +12 -27
  55. data/spec/lib/application_spec.rb +1 -1
  56. data/spec/lib/backend/file/basic_spec.rb +6 -6
  57. data/spec/lib/backend/file/json_spec.rb +11 -6
  58. data/spec/lib/backend/file/marshal_spec.rb +11 -6
  59. data/spec/lib/backend/files_spec.rb +21 -7
  60. data/spec/lib/backend/redis/basic_spec.rb +6 -0
  61. data/spec/lib/backend/redis/list_hash_spec.rb +9 -3
  62. data/spec/lib/backend/redis/string_hash_spec.rb +7 -1
  63. data/spec/lib/backend/redis_spec.rb +22 -12
  64. data/spec/lib/categories_indexed_spec.rb +2 -2
  65. data/spec/lib/category_indexing_spec.rb +12 -33
  66. data/spec/lib/category_spec.rb +22 -0
  67. data/spec/lib/index/base_indexing_spec.rb +30 -0
  68. data/spec/lib/indexed/bundle/memory_spec.rb +13 -20
  69. data/spec/lib/indexers/base_spec.rb +39 -4
  70. data/spec/lib/indexers/parallel_spec.rb +2 -10
  71. data/spec/lib/indexers/serial_spec.rb +11 -26
  72. data/spec/lib/indexes_class_spec.rb +4 -4
  73. data/spec/lib/indexes_indexed_spec.rb +2 -2
  74. data/spec/lib/indexes_indexing_spec.rb +6 -10
  75. data/spec/lib/indexes_spec.rb +3 -3
  76. data/spec/lib/indexing/bundle/{super_base_spec.rb → base_spec.rb} +2 -2
  77. data/spec/lib/indexing/bundle/memory_partial_generation_speed_spec.rb +3 -3
  78. data/spec/lib/indexing/bundle/memory_spec.rb +16 -14
  79. data/spec/lib/indexing/bundle/redis_spec.rb +18 -16
  80. data/spec/lib/query/allocation_spec.rb +1 -1
  81. data/spec/lib/query/token_spec.rb +5 -7
  82. data/spec/lib/sources/base_spec.rb +53 -0
  83. data/spec/lib/sources/db_spec.rb +0 -7
  84. metadata +11 -12
  85. data/lib/picky/indexers/solr.rb +0 -56
  86. data/lib/picky/indexing/bundle/super_base.rb +0 -61
  87. data/lib/picky/solr/schema_generator.rb +0 -74
  88. data/lib/tasks/search.rake +0 -9
  89. data/lib/tasks/shortcuts.rake +0 -32
  90. data/lib/tasks/solr.rake +0 -36
@@ -1,7 +1,6 @@
1
1
  class Category
2
2
 
3
- attr_reader :name,
4
- :index
3
+ attr_reader :name
5
4
 
6
5
  # Mandatory params:
7
6
  # * name: Category name to use as identifier and file names.
@@ -31,12 +30,12 @@ class Category
31
30
 
32
31
  # TODO Push into Bundle. At least the weights.
33
32
  #
34
- partial = options[:partial] || Generators::Partial::Default
35
33
  weights = options[:weights] || Generators::Weights::Default
34
+ partial = options[:partial] || Generators::Partial::Default
36
35
  similarity = options[:similarity] || Generators::Similarity::Default
37
36
 
38
- @indexing_exact = index.indexing_bundle_class.new(:exact, self, similarity, Generators::Partial::None.new, weights)
39
- @indexing_partial = index.indexing_bundle_class.new(:partial, self, Generators::Similarity::None.new, partial, weights)
37
+ @indexing_exact = index.indexing_bundle_class.new(:exact, self, weights, Generators::Partial::None.new, similarity)
38
+ @indexing_partial = index.indexing_bundle_class.new(:partial, self, weights, partial, Generators::Similarity::None.new)
40
39
 
41
40
  # Indexed.
42
41
  #
@@ -55,6 +54,12 @@ class Category
55
54
  Query::Qualifiers.add(name, generate_qualifiers_from(options) || [name])
56
55
  end
57
56
 
57
+ # TODO Move to Index.
58
+ #
59
+ def generate_qualifiers_from options
60
+ options[:qualifiers] || options[:qualifier] && [options[:qualifier]]
61
+ end
62
+
58
63
  # Indexes and reloads the category.
59
64
  #
60
65
  def reindex
@@ -74,10 +79,10 @@ class Category
74
79
  @index.name
75
80
  end
76
81
 
77
- # Path and partial filename of a specific index on this category.
82
+ # The category itself just yields itself.
78
83
  #
79
- def index_path bundle_name, type
80
- "#{index_directory}/#{name}_#{bundle_name}_#{type}"
84
+ def each_category
85
+ yield self
81
86
  end
82
87
 
83
88
  # Path and partial filename of the prepared index on this category.
@@ -85,9 +90,20 @@ class Category
85
90
  def prepared_index_path
86
91
  @prepared_index_path ||= "#{index_directory}/prepared_#{name}_index"
87
92
  end
93
+ # Get an opened index file.
94
+ #
95
+ # Note: If you don't use it with the block, do not forget to close it.
96
+ #
88
97
  def prepared_index_file &block
89
98
  @prepared_index_file ||= Backend::File::Text.new prepared_index_path
90
- @prepared_index_file.open_for_indexing &block
99
+ @prepared_index_file.open &block
100
+ end
101
+ # Creates the index directory including all necessary paths above it.
102
+ #
103
+ # Note: Interface method called by any indexers.
104
+ #
105
+ def prepare_index_directory
106
+ FileUtils.mkdir_p index_directory
91
107
  end
92
108
 
93
109
  # The index directory for this category.
@@ -96,30 +112,26 @@ class Category
96
112
  @index_directory ||= "#{PICKY_ROOT}/index/#{PICKY_ENVIRONMENT}/#{@index.name}"
97
113
  end
98
114
 
99
- # Creates the index directory including all necessary paths above it.
115
+ # Path and partial filename of a specific subindex on this category.
100
116
  #
101
- def prepare_index_directory
102
- FileUtils.mkdir_p index_directory
117
+ # Subindexes are:
118
+ # * inverted index
119
+ # * weights index
120
+ # * partial index
121
+ # * similarity index
122
+ #
123
+ def index_path bundle_name, type
124
+ "#{index_directory}/#{name}_#{bundle_name}_#{type}"
103
125
  end
104
126
 
105
- # Identifier for internal use.
106
- #
107
- # TODO What internal use?
127
+ # Identifier for technical output.
108
128
  #
109
129
  def identifier
110
- @identifier ||= "#{@index.name}:#{name}"
111
- end
112
-
113
- def to_info
114
- <<-CATEGORY
115
- Category(#{name}):
116
- Exact:
117
- #{exact.indented_to_s(4)}
118
- Partial:
119
- #{partial.indented_to_s(4)}
120
- CATEGORY
130
+ @identifier ||= "#{PICKY_ENVIRONMENT}:#{index_name}:#{name}"
121
131
  end
122
132
 
133
+ #
134
+ #
123
135
  def to_s
124
136
  "Category(#{name})"
125
137
  end
@@ -4,12 +4,6 @@ class Category
4
4
 
5
5
  attr_reader :indexed_exact
6
6
 
7
- # TODO Move to Index.
8
- #
9
- def generate_qualifiers_from options
10
- options[:qualifiers] || options[:qualifier] && [options[:qualifier]]
11
- end
12
-
13
7
  # Loads the index from cache.
14
8
  #
15
9
  def load_from_cache
@@ -19,18 +13,6 @@ class Category
19
13
  end
20
14
  alias reload load_from_cache
21
15
 
22
- # Loads, analyzes, and clears the index.
23
- #
24
- # Note: The idea is not to run this while the search engine is running.
25
- #
26
- def analyze collector
27
- collector[identifier] = {
28
- :exact => Analyzer.new.analyze(indexed_exact),
29
- :partial => Analyzer.new.analyze(indexed_partial)
30
- }
31
- collector
32
- end
33
-
34
16
  # Gets the weight for this token's text.
35
17
  #
36
18
  def weight token
@@ -49,13 +31,15 @@ class Category
49
31
  token.partial? ? indexed_partial : indexed_exact
50
32
  end
51
33
 
52
- # The partial strategy defines whether to really use the partial index.
34
+ # The partial strategy defines whether to
35
+ # really use the partial index.
53
36
  #
54
37
  def indexed_partial
55
38
  @partial_strategy.use_exact_for_partial? ? @indexed_exact : @indexed_partial
56
39
  end
57
40
 
58
- #
41
+ # Returns a combination for the token,
42
+ # or nil, if there is none.
59
43
  #
60
44
  def combination_for token
61
45
  weight(token) && Query::Combination.new(token, self)
@@ -14,8 +14,56 @@ class Category
14
14
  cache
15
15
  end
16
16
 
17
+ # Indexes, creates the "prepared_..." file.
18
+ #
19
+ def prepare
20
+ with_data_snapshot do
21
+ indexer.index [self]
22
+ end
23
+ end
24
+
25
+ # Take a data snapshot if the source offers it.
26
+ #
27
+ def with_data_snapshot
28
+ if source.respond_to? :with_snapshot
29
+ source.with_snapshot(@index) do
30
+ yield
31
+ end
32
+ else
33
+ yield
34
+ end
35
+ end
36
+
37
+ # Generates all caches for this category.
38
+ #
39
+ def cache
40
+ configure
41
+ generate_caches_from_source
42
+ generate_partial
43
+ generate_caches_from_memory
44
+ dump_caches
45
+ timed_exclaim %Q{"#{identifier}": Caching finished.}
46
+ end
47
+ # Generate the cache data.
48
+ #
49
+ def generate_caches_from_source
50
+ indexing_exact.generate_caches_from_source
51
+ end
52
+ def generate_partial
53
+ indexing_partial.generate_partial_from indexing_exact.inverted
54
+ end
55
+ def generate_caches_from_memory
56
+ indexing_partial.generate_caches_from_memory
57
+ end
58
+ def dump_caches
59
+ indexing_exact.dump
60
+ indexing_partial.dump
61
+ end
62
+
17
63
  # Return an appropriate source.
18
64
  #
65
+ # If we have no explicit source, we'll check the index for one.
66
+ #
19
67
  def source
20
68
  @source || @index.source
21
69
  end
@@ -39,45 +87,33 @@ class Category
39
87
 
40
88
  # The indexer is lazily generated and cached.
41
89
  #
90
+ # TODO Really cache?
91
+ #
42
92
  def indexer
43
93
  @indexer ||= source.respond_to?(:each) ? Indexers::Parallel.new(self) : Indexers::Serial.new(self)
44
94
  end
45
95
 
46
- # TODO This is a hack to get the parallel indexer working.
47
- #
48
- def categories
49
- [self]
50
- end
51
-
52
96
  # Returns an appropriate tokenizer.
53
97
  # If one isn't set on this category, will try the index,
54
98
  # and finally the default index tokenizer.
55
99
  #
56
100
  def tokenizer
57
- @tokenizer || @index.tokenizer || Tokenizers::Index.default
101
+ @tokenizer || @index.tokenizer
58
102
  end
59
103
 
60
- # Backup the caches.
61
- # (Revert with restore_caches)
104
+ # We need to set what formatting method should be used.
105
+ # Uses the one defined in the indexer.
62
106
  #
63
- def backup_caches
64
- timed_exclaim "Backing up #{identifier}."
65
- indexing_exact.backup
66
- indexing_partial.backup
67
- end
68
-
69
- # Restore the caches.
70
- # (Revert with backup_caches)
107
+ # TODO Make this more dynamic.
71
108
  #
72
- def restore_caches
73
- timed_exclaim "Restoring #{identifier}."
74
- indexing_exact.restore
75
- indexing_partial.restore
109
+ def configure
110
+ indexing_exact[:key_format] = self.key_format
111
+ indexing_partial[:key_format] = self.key_format
76
112
  end
77
113
 
78
114
  # Checks the caches for existence.
79
115
  #
80
- def check_caches
116
+ def check
81
117
  timed_exclaim "Checking #{identifier}."
82
118
  indexing_exact.raise_unless_cache_exists
83
119
  indexing_partial.raise_unless_cache_exists
@@ -85,61 +121,28 @@ class Category
85
121
 
86
122
  # Deletes the caches.
87
123
  #
88
- def clear_caches
124
+ def clear
89
125
  timed_exclaim "Deleting #{identifier}."
90
126
  indexing_exact.delete
91
127
  indexing_partial.delete
92
128
  end
93
129
 
94
- # We need to set what formatting method should be used.
95
- # Uses the one defined in the indexer.
96
- #
97
- # TODO Make this more dynamic.
98
- #
99
- def configure
100
- indexing_exact[:key_format] = self.key_format
101
- indexing_partial[:key_format] = self.key_format
102
- end
103
-
104
- # Indexes, creates the "prepared_..." file.
105
- #
106
- # TODO This step could already prepare the id (if a
107
- # per category key_format is not really needed).
108
- #
109
- def prepare
110
- prepare_index_directory
111
- indexer.index
112
- end
113
-
114
- # Generates all caches for this category.
130
+ # Backup the caches.
131
+ # (Revert with restore_caches)
115
132
  #
116
- def cache
117
- prepare_index_directory
118
- generate_caches
133
+ def backup
134
+ timed_exclaim "Backing up #{identifier}."
135
+ indexing_exact.backup
136
+ indexing_partial.backup
119
137
  end
120
138
 
121
- # Generate the cache data.
139
+ # Restore the caches.
140
+ # (Revert with backup_caches)
122
141
  #
123
- def generate_caches
124
- configure
125
- generate_caches_from_source
126
- generate_partial
127
- generate_caches_from_memory
128
- dump_caches
129
- timed_exclaim %Q{"#{identifier}": Caching finished.}
130
- end
131
- def generate_caches_from_source
132
- indexing_exact.generate_caches_from_source
133
- end
134
- def generate_partial
135
- indexing_partial.generate_partial_from indexing_exact.index
136
- end
137
- def generate_caches_from_memory
138
- indexing_partial.generate_caches_from_memory
139
- end
140
- def dump_caches
141
- indexing_exact.dump
142
- indexing_partial.dump
142
+ def restore
143
+ timed_exclaim "Restoring #{identifier}."
144
+ indexing_exact.restore
145
+ indexing_partial.restore
143
146
  end
144
147
 
145
148
  end
@@ -3,13 +3,13 @@ module Generators # :nodoc:all
3
3
  # A cache generator holds an index.
4
4
  #
5
5
  class Base
6
-
7
- attr_reader :index
8
-
9
- def initialize index
10
- @index = index
6
+
7
+ attr_reader :inverted
8
+
9
+ def initialize inverted
10
+ @inverted = inverted
11
11
  end
12
-
12
+
13
13
  end
14
14
 
15
15
  end
@@ -1,16 +1,16 @@
1
1
  module Generators
2
2
 
3
3
  module Partial
4
-
4
+
5
5
  # Generates the right substrings for use in the substring strategy.
6
6
  #
7
7
  class SubstringGenerator
8
-
8
+
9
9
  attr_reader :from, :to
10
-
10
+
11
11
  def initialize from, to
12
12
  @from, @to = from, to
13
-
13
+
14
14
  if @to.zero?
15
15
  def each_subtoken token, &block
16
16
  token.each_subtoken @from, &block
@@ -20,11 +20,11 @@ module Generators
20
20
  token[0..@to].intern.each_subtoken @from, &block
21
21
  end
22
22
  end
23
-
23
+
24
24
  end
25
-
25
+
26
26
  end
27
-
27
+
28
28
  # The subtoken partial strategy.
29
29
  #
30
30
  # If given "florian"
@@ -32,7 +32,7 @@ module Generators
32
32
  # (Depending on what the given from value is, the example is with option from: 1)
33
33
  #
34
34
  class Substring < Strategy
35
-
35
+
36
36
  # The from option signifies where in the symbol it
37
37
  # will start in generating the subtokens.
38
38
  #
@@ -51,48 +51,50 @@ module Generators
51
51
  to = options[:to] || -1
52
52
  @generator = SubstringGenerator.new from, to
53
53
  end
54
-
54
+
55
55
  # Delegator to generator#from.
56
56
  #
57
57
  def from
58
58
  @generator.from
59
59
  end
60
-
60
+
61
61
  # Delegator to generator#to.
62
62
  #
63
63
  def to
64
64
  @generator.to
65
65
  end
66
-
67
- # Generates a partial index from the given index.
66
+
67
+ # Generates a partial index from the given inverted index.
68
68
  #
69
- def generate_from index
69
+ def generate_from inverted
70
70
  result = {}
71
-
71
+
72
72
  # Generate for each key token the subtokens.
73
73
  #
74
74
  i = 0
75
- index.each_key do |token|
75
+ j = 0
76
+ inverted.each_key do |token|
76
77
  i += 1
77
78
  if i == 5000
78
- timed_exclaim "Generating partial tokens for token #{token}. This appears every 5000 tokens."
79
+ j += 1
80
+ timed_exclaim %Q{#{"%8i" % (i*j)} generated (current token: "#{token}").}
79
81
  i = 0
80
82
  end
81
- generate_for token, index, result
83
+ generate_for token, inverted, result
82
84
  end
83
-
85
+
84
86
  # Remove duplicate ids.
85
87
  #
86
88
  # THINK If it is unique for a subtoken, it is
87
89
  # unique for all derived longer tokens.
88
90
  #
89
91
  result.each_value &:uniq!
90
-
92
+
91
93
  result
92
94
  end
93
-
95
+
94
96
  private
95
-
97
+
96
98
  # To each shortened token of :test
97
99
  # :test, :tes, :te, :t
98
100
  # add all ids of :test
@@ -101,18 +103,18 @@ module Generators
101
103
  #
102
104
  # THINK Could be improved by appending the aforegoing ids?
103
105
  #
104
- def generate_for token, index, result
106
+ def generate_for token, inverted, result
105
107
  @generator.each_subtoken(token) do |subtoken|
106
108
  if result[subtoken]
107
- result[subtoken] += index[token] # unique
109
+ result[subtoken] += inverted[token] # unique
108
110
  else
109
- result[subtoken] = index[token].dup
111
+ result[subtoken] = inverted[token].dup
110
112
  end
111
113
  end
112
114
  end
113
-
115
+
114
116
  end
115
-
117
+
116
118
  end
117
119
 
118
120
  end
@@ -3,11 +3,11 @@ module Generators
3
3
  # The partial generator uses a subtoken(downto:1) generator as default.
4
4
  #
5
5
  class PartialGenerator < Base
6
-
7
- # Generate a partial index based on the given index.
6
+
7
+ # Generate a partial index based on the given inverted index.
8
8
  #
9
9
  def generate strategy = Partial::Substring.new(from: 1)
10
- strategy.generate_from self.index
10
+ strategy.generate_from self.inverted
11
11
  end
12
12
 
13
13
  end
@@ -26,8 +26,8 @@ module Generators
26
26
  # In the following form:
27
27
  # [:meier, :mueller, :peter, :pater] => { MR: [:meier], MLR: [:mueller], PTR: [:peter, :pater] }
28
28
  #
29
- def generate_from index
30
- hash = hashify index.keys
29
+ def generate_from inverted
30
+ hash = hashify inverted.keys
31
31
  sort hash
32
32
  end
33
33
 
@@ -35,12 +35,12 @@ module Generators
35
35
 
36
36
  # Sorts the index values in place.
37
37
  #
38
- def sort index
39
- index.each_pair.each do |code, ary|
38
+ def sort hash
39
+ hash.each_pair.each do |code, ary|
40
40
  ary.sort_by_levenshtein! code
41
41
  ary.slice! amount, ary.size # size is not perfectly correct, but anyway
42
42
  end
43
- index
43
+ hash
44
44
  end
45
45
 
46
46
  # Hashifies a list of symbols.
@@ -4,10 +4,10 @@ module Generators
4
4
  #
5
5
  class SimilarityGenerator < Base
6
6
 
7
- # Generate a similarity index based on the given index.
7
+ # Generate a similarity index based on the given inverted index.
8
8
  #
9
9
  def generate strategy = Similarity::None.new
10
- strategy.generate_from self.index
10
+ strategy.generate_from self.inverted
11
11
  end
12
12
 
13
13
  end
@@ -9,10 +9,10 @@ module Generators
9
9
  #
10
10
  class Logarithmic < Strategy
11
11
 
12
- # Generates a partial index from the given index.
12
+ # Generates a partial index from the given inverted index.
13
13
  #
14
- def generate_from index
15
- index.inject({}) do |hash, text_ids|
14
+ def generate_from inverted
15
+ inverted.inject({}) do |hash, text_ids|
16
16
  text, ids = *text_ids
17
17
  weight = weight_for ids.size
18
18
  hash[text] ||= weight.round(2) if weight
@@ -4,10 +4,10 @@ module Generators
4
4
  #
5
5
  class WeightsGenerator < Base
6
6
 
7
- # Generate a weights index based on the given index.
7
+ # Generate a weights index based on the given inverted index.
8
8
  #
9
9
  def generate strategy = Weights::Logarithmic.new
10
- strategy.generate_from self.index
10
+ strategy.generate_from self.inverted
11
11
  end
12
12
 
13
13
  end
@@ -89,6 +89,7 @@ module Index
89
89
  :categories
90
90
 
91
91
  delegate :[],
92
+ :each_category,
92
93
  :to => :categories
93
94
 
94
95
  # Create a new index with a given source.
@@ -381,16 +382,6 @@ SOURCE
381
382
  ) unless source.respond_to?(:each) || source.respond_to?(:harvest)
382
383
  end
383
384
 
384
- def method_name
385
-
386
- end
387
-
388
- #
389
- #
390
- def to_s
391
- "#{self.class}(#{name}, result_id: #{result_identifier}, source: #{source}, categories: #{categories})"
392
- end
393
-
394
385
  def to_stats # :nodoc:
395
386
  stats = <<-INDEX
396
387
  #{name} (#{self.class}):
@@ -401,6 +392,18 @@ INDEX
401
392
  stats
402
393
  end
403
394
 
395
+ # Identifier used for technical output.
396
+ #
397
+ def identifier
398
+ "#{PICKY_ENVIRONMENT}:#{name}"
399
+ end
400
+
401
+ #
402
+ #
403
+ def to_s
404
+ "#{self.class}(#{name}, result_id: #{result_identifier}, source: #{source}, categories: #{categories})"
405
+ end
406
+
404
407
  end
405
408
 
406
409
  end
@@ -18,6 +18,8 @@ module Index
18
18
  #
19
19
  # A combination is a tuple <token, index_bundle>.
20
20
  #
21
+ # TODO Rename and delegate.
22
+ #
21
23
  def possible_combinations token
22
24
  categories.possible_combinations_for token
23
25
  end