picky 4.10.0 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/lib/picky/backends/memory/json.rb +6 -3
  2. data/lib/picky/categories.rb +12 -0
  3. data/lib/picky/categories_indexed.rb +3 -1
  4. data/lib/picky/extensions/array.rb +1 -11
  5. data/lib/picky/extensions/class.rb +5 -3
  6. data/lib/picky/extensions/object.rb +13 -1
  7. data/lib/picky/generators/similarity/phonetic.rb +0 -2
  8. data/lib/picky/index.rb +33 -0
  9. data/lib/picky/index_facets.rb +9 -5
  10. data/lib/picky/loader.rb +4 -7
  11. data/lib/picky/pool.rb +10 -7
  12. data/lib/picky/qualifier_mapper.rb +51 -0
  13. data/lib/picky/query/boosts.rb +2 -2
  14. data/lib/picky/query/indexes.rb +1 -29
  15. data/lib/picky/query/token.rb +7 -3
  16. data/lib/picky/query/tokens.rb +0 -6
  17. data/lib/picky/search_facets.rb +45 -9
  18. data/lib/picky/sinatra.rb +2 -0
  19. data/lib/picky/tokenizer.rb +19 -11
  20. data/lib/picky.rb +3 -1
  21. data/spec/functional/facets_spec.rb +9 -13
  22. data/spec/functional/multi_index_qualifier_spec.rb +30 -0
  23. data/spec/functional/only_spec.rb +34 -32
  24. data/spec/functional/pool_spec.rb +82 -0
  25. data/spec/functional/remap_qualifiers_spec.rb +1 -9
  26. data/spec/lib/categories_indexed_spec.rb +2 -2
  27. data/spec/lib/extensions/array_spec.rb +19 -19
  28. data/spec/lib/extensions/object_spec.rb +14 -11
  29. data/spec/lib/extensions/symbol_spec.rb +1 -1
  30. data/spec/lib/generators/similarity/phonetic_spec.rb +14 -7
  31. data/spec/lib/picky_spec.rb +1 -1
  32. data/spec/lib/pool_spec.rb +17 -17
  33. data/spec/lib/{query/qualifier_category_mapper_spec.rb → qualifier_mapper_spec.rb} +8 -8
  34. data/spec/lib/query/token_spec.rb +17 -12
  35. data/spec/lib/rack/harakiri_spec.rb +5 -0
  36. data/spec/lib/tokenizer_spec.rb +44 -3
  37. metadata +11 -8
  38. data/lib/picky/migrations/from_30_to_31.rb +0 -61
  39. data/lib/picky/query/qualifier_category_mapper.rb +0 -61
@@ -33,12 +33,15 @@ module Picky
33
33
 
34
34
  # Dump JSON into the cache file.
35
35
  #
36
- # TODO Ask MultiJson people to add IO option:
37
- # MultiJson.encode(object, out_file)
36
+ # TODO Add IO option:
37
+ # MultiJson.encode(object, io: out_file)
38
38
  #
39
39
  def dump_json internal
40
40
  ::File.open(cache_path, 'w') do |out_file|
41
- # MultiJson.encode internal, out_file
41
+ # If using Yajl, this will stream write to out_file.
42
+ # Note: But it fails on oj.
43
+ #
44
+ # MultiJson.dump internal, [out_file]
42
45
  out_file.write MultiJson.encode internal
43
46
  end
44
47
  end
@@ -29,10 +29,22 @@ module Picky
29
29
  @categories = []
30
30
  @category_hash = {}
31
31
  end
32
+
33
+ # Updates the qualifier ("qualifier:searchterm") mapping.
34
+ #
35
+ # Example:
36
+ # You dynamically add a new category to an index.
37
+ # To add the qualifiers to a search, you call this
38
+ # method.
39
+ #
40
+ def mapper
41
+ @mapper ||= QualifierMapper.new self
42
+ end
32
43
 
33
44
  # Add the given category to the list of categories.
34
45
  #
35
46
  def << category
47
+ @mapper = nil # TODO Move. (Resets category mapping)
36
48
  categories << category
37
49
  category_hash[category.name] = category
38
50
  end
@@ -61,8 +61,10 @@ module Picky
61
61
  #
62
62
  # Note: Once I thought this was called too often. But it is not (18.01.2011).
63
63
  #
64
+ # TODO Called too often?
65
+ #
64
66
  def possible_categories token
65
- token.predefined_categories || categories
67
+ token.predefined_categories(mapper) || categories
66
68
  end
67
69
 
68
70
  end
@@ -2,21 +2,11 @@
2
2
  #
3
3
  class Array
4
4
 
5
- # Cluster-uniqs equal neighborly elements.
6
- #
7
- # Returns a copy.
8
- #
9
- def clustered_uniq
10
- self.inject([]) do |result, element|
11
- result << element if element != result.last
12
- result
13
- end
14
- end
15
5
  # Around 10% faster than the above.
16
6
  #
17
7
  # Returns a copy.
18
8
  #
19
- def clustered_uniq_fast
9
+ def clustered_uniq
20
10
  result = []
21
11
  self.inject(nil) do |last, element|
22
12
  if last == element
@@ -2,9 +2,11 @@
2
2
  #
3
3
  class Class
4
4
 
5
- def instance_delegate *methods
6
- methods.each do |method|
7
- module_eval("def self.#{method}(*args, &block)\nself.instance.__send__(#{method.inspect}, *args, &block)\nend\n", "(__DELEGATION__)", 1)
5
+ def instance_delegate *method_names
6
+ method_names.each do |method_name|
7
+ module_eval(<<-DELEGATION, "(__DELEGATION__)", 1)
8
+ def self.#{method_name}(*args, &block)\n self.instance.#{method_name}(*args, &block)\nend
9
+ DELEGATION
8
10
  end
9
11
  end
10
12
 
@@ -9,6 +9,8 @@ class Object
9
9
 
10
10
  # Just outputs the given text to the logger.
11
11
  #
12
+ # Note: stubbed in spec_helper.rb
13
+ #
12
14
  def exclaim text
13
15
  Picky.logger.info text
14
16
  Picky.logger.flush
@@ -17,7 +19,17 @@ class Object
17
19
  # Puts a text that informs the user of a missing gem.
18
20
  #
19
21
  def warn_gem_missing gem_name, message
20
- Picky.logger.warn "#{gem_name} gem missing!\nTo use #{message}, you need to:\n 1. Add the following line to Gemfile:\n gem '#{gem_name}'\n or\n require '#{gem_name}'\n for example at the top of your app.rb file.\n 2. Then, run:\n bundle update\n"
22
+ Picky.logger.warn <<-WARNING
23
+ Warning: #{gem_name} gem missing!
24
+ To use #{message}, you need to:
25
+ 1. Add the following line to Gemfile:
26
+ gem '#{gem_name}'
27
+ or
28
+ require '#{gem_name}'
29
+ for example at the top of your app.rb file.
30
+ 2. Then, run:
31
+ bundle update
32
+ WARNING
21
33
  end
22
34
 
23
35
  # Indents each line by <tt>amount=2</tt> spaces.
@@ -20,8 +20,6 @@ module Picky
20
20
  #
21
21
  def initialize amount = 3
22
22
  check_gem
23
-
24
- raise "In Picky 2.0+, the Similarity::Phonetic has been renamed to Similarity::DoubleMetaphone. Please use that one. Thanks!" if self.class == Phonetic
25
23
  @amount = amount
26
24
  end
27
25
 
data/lib/picky/index.rb CHANGED
@@ -140,6 +140,23 @@ module Picky
140
140
  @backend ||= Backends::Memory.new
141
141
  end
142
142
  end
143
+
144
+ # Ignore the categories with these qualifiers.
145
+ #
146
+ # Example:
147
+ # search = Search.new(index1, index2, index3) do
148
+ # ignore :name, :first_name
149
+ # end
150
+ #
151
+ # Cleans up / optimizes after being called.
152
+ #
153
+ # TODO This needs to move to the index.
154
+ #
155
+ def ignore *qualifiers
156
+ @ignored_categories ||= []
157
+ @ignored_categories += qualifiers.map { |qualifier| @mapper.map qualifier }.compact
158
+ @ignored_categories.uniq!
159
+ end
143
160
 
144
161
  # SYMBOLS.
145
162
  #
@@ -179,6 +196,22 @@ module Picky
179
196
  new_category
180
197
  end
181
198
 
199
+ # Restrict categories to the given ones.
200
+ #
201
+ # Functionally equivalent as if indexes didn't
202
+ # have the categories at all.
203
+ #
204
+ # Note: Probably only makes sense when an index
205
+ # is used in multiple searches. If not, why even
206
+ # have the categories?
207
+ #
208
+ # TODO Redesign.
209
+ #
210
+ def only *qualifiers
211
+ raise "Sorry, Picky::Search#only has been removed in version."
212
+ # @mapper.restrict_to *qualifiers
213
+ end
214
+
182
215
  # The directory used by this index.
183
216
  #
184
217
  # Note: Used @directory ||=, but needs to be dynamic.
@@ -15,12 +15,16 @@ module Picky
15
15
  text_ids = self[category_identifier].exact.inverted
16
16
  no_counts = options[:counts] == false
17
17
  minimal_counts = options[:at_least]
18
- text_ids.inject(no_counts ? [] : {}) do |result, (text, ids)|
19
- size = ids.size
20
- next result if minimal_counts && size < minimal_counts
21
- if no_counts
18
+
19
+ if no_counts
20
+ text_ids.inject([]) do |result, (text, ids)|
21
+ next result if minimal_counts && ids.size < minimal_counts
22
22
  result << text
23
- else
23
+ end
24
+ else
25
+ text_ids.inject({}) do |result, (text, ids)|
26
+ size = ids.size
27
+ next result if minimal_counts && size < minimal_counts
24
28
  result[text] = size; result
25
29
  end
26
30
  end
data/lib/picky/loader.rb CHANGED
@@ -170,8 +170,6 @@ module Picky
170
170
  load_relative 'query/allocation',
171
171
  'query/allocations'
172
172
 
173
- load_relative 'query/qualifier_category_mapper'
174
-
175
173
  load_relative 'query/boosts'
176
174
 
177
175
  load_relative 'query/indexes',
@@ -219,6 +217,8 @@ module Picky
219
217
  end
220
218
 
221
219
  def load_inner_api
220
+ load_relative 'qualifier_mapper'
221
+
222
222
  load_relative 'category',
223
223
  'category_indexed',
224
224
  'category_indexing',
@@ -235,7 +235,7 @@ module Picky
235
235
  'indexes_indexed',
236
236
  'indexes_indexing',
237
237
  'indexes_convenience'
238
-
238
+
239
239
  load_relative 'index',
240
240
  'index_indexed',
241
241
  'index_indexing',
@@ -261,14 +261,12 @@ module Picky
261
261
 
262
262
  # Loads the user interface parts.
263
263
  #
264
- # TODO Move tokenizer etc.?
265
- #
266
264
  def load_user_interface
267
265
  load_api
268
266
  load_logging
269
267
  load_relative 'source'
270
268
  load_relative 'tokenizer'
271
- load_relative 'rack/harakiri'
269
+ # load_relative 'rack/harakiri' # Needs to be explicitly loaded/required.
272
270
  load_relative 'character_substituters/west_european'
273
271
  load_generators
274
272
  load_inner_api
@@ -276,7 +274,6 @@ module Picky
276
274
  load_search
277
275
  load_interfaces
278
276
  load_relative 'scheduler'
279
- load_relative 'migrations/from_30_to_31' # TODO Remove.
280
277
  end
281
278
 
282
279
  # Loads the framework.
data/lib/picky/pool.rb CHANGED
@@ -12,7 +12,8 @@ module Picky
12
12
  # Note: If you need to run two consecutive queries,
13
13
  # this can't be used.
14
14
  #
15
- # TODO Also install calling release_all after each query.
15
+ # Note: You need to call Picky::Pool.release_all after each query
16
+ # (or after a few queries).
16
17
  #
17
18
  def install
18
19
  Query::Token.extend self
@@ -76,19 +77,21 @@ module Picky
76
77
  # (And removes it from the used pool)
77
78
  #
78
79
  def release instance
79
- @__free__ << instance
80
+ @__free__ << instance
80
81
 
81
- # Note: This is relatively fast as there are often only
82
- # few instances in the used pool.
83
- @__used__.delete instance
82
+ # Note: This is relatively fast as there are often only
83
+ # few instances in the used pool.
84
+ #
85
+ @__used__.delete instance
84
86
  end
85
87
 
86
- # After you have called release all, you can't
88
+ # After you have called release all, you can't externally
87
89
  # use any reference that has formerly been obtained
88
90
  # anymore.
89
91
  #
90
92
  def release_all
91
- @__free__ += @__used__
93
+ @__used__.each { |used| @__free__ << used } # +0 Array per release_all
94
+ # @__used__ += @__free__ # +1 Array per release_all
92
95
  @__used__.clear
93
96
  end
94
97
 
@@ -0,0 +1,51 @@
1
+ module Picky
2
+
3
+ # Collection class for qualifiers.
4
+ #
5
+ class QualifierMapper
6
+
7
+ attr_reader :mapping
8
+
9
+ #
10
+ #
11
+ def initialize categories
12
+ @mapping = {}
13
+ categories.each { |category| add category }
14
+ end
15
+
16
+ #
17
+ #
18
+ def add category
19
+ category.qualifiers.each do |qualifier|
20
+ sym_qualifier = qualifier.intern
21
+ Picky.logger.warn %Q{Warning: Qualifier "#{qualifier}" already mapped to category #{mapping[sym_qualifier].identifier} (ambiguous qualifier mapping).} if mapping.has_key? sym_qualifier
22
+ mapping[sym_qualifier] = category
23
+ end
24
+ end
25
+
26
+ # Normalizes the given qualifier.
27
+ #
28
+ # Returns nil if it is not allowed, the normalized qualifier if it is.
29
+ #
30
+ def map qualifier
31
+ return nil if qualifier.empty?
32
+
33
+ mapping[qualifier.intern]
34
+ end
35
+
36
+ # Restricts the given categories.
37
+ #
38
+ def restrict user_qualified
39
+ if @restricted
40
+ user_qualified ? @restricted & user_qualified : @restricted
41
+ else
42
+ user_qualified
43
+ end
44
+ end
45
+ def restrict_to *qualifiers
46
+ @restricted = qualifiers.map { |qualifier| map qualifier }.compact
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -44,11 +44,11 @@ module Picky
44
44
  # [:name, :height, :color] returns +3, but
45
45
  # [:name, :height, :street] returns -1.
46
46
  #
47
- # Note: Use Array#clustered_uniq_fast to make
47
+ # Note: Use Array#clustered_uniq to make
48
48
  # [:a, :a, :b, :a] => [:a, :b, :a]
49
49
  #
50
50
  def boost_for_categories names
51
- @boosts[names.clustered_uniq_fast] || 0
51
+ @boosts[names.clustered_uniq] || 0
52
52
  end
53
53
 
54
54
  # API.
@@ -29,19 +29,6 @@ module Picky
29
29
  IndexesCheck.check_backends indexes
30
30
 
31
31
  @indexes = indexes
32
-
33
- remap_qualifiers
34
- end
35
-
36
- # Updates the qualifier ("qualifier:searchterm") mapping.
37
- #
38
- # Example:
39
- # You dynamically add a new category to an index.
40
- # To add the qualifiers to a search, you call this
41
- # method.
42
- #
43
- def remap_qualifiers
44
- @mapper = QualifierCategoryMapper.new @indexes # TODO Move into search?
45
32
  end
46
33
 
47
34
  # Ignore the categories with these qualifiers.
@@ -51,26 +38,13 @@ module Picky
51
38
  # ignore :name, :first_name
52
39
  # end
53
40
  #
54
- # Cleans up / optimizes after being called.
41
+ # Note: Cleans up / optimizes after being called.
55
42
  #
56
43
  def ignore *qualifiers
57
44
  @ignored_categories ||= []
58
45
  @ignored_categories += qualifiers.map { |qualifier| @mapper.map qualifier }.compact
59
46
  @ignored_categories.uniq!
60
47
  end
61
-
62
- # Restrict categories to the given ones.
63
- #
64
- # Functionally equivalent as if indexes didn't
65
- # have the categories at all.
66
- #
67
- # Note: Probably only makes sense when an index
68
- # is used in multiple searches. If not, why even
69
- # have the categories?
70
- #
71
- def only *qualifiers
72
- @mapper.restrict_to *qualifiers
73
- end
74
48
 
75
49
  # Returns a number of prepared (sorted, reduced etc.) allocations for the given tokens.
76
50
  #
@@ -105,8 +79,6 @@ module Picky
105
79
  # Returns a number of possible allocations for the given tokens.
106
80
  #
107
81
  def allocations_for tokens
108
- tokens.categorize @mapper
109
-
110
82
  Allocations.new allocations_ary_for(tokens)
111
83
  end
112
84
  def allocations_ary_for tokens
@@ -13,7 +13,7 @@ module Picky
13
13
 
14
14
  attr_reader :text, :original
15
15
  attr_writer :similar
16
- attr_accessor :predefined_categories
16
+ attr_writer :predefined_categories
17
17
 
18
18
  delegate :blank?, :to => :@text
19
19
 
@@ -22,6 +22,8 @@ module Picky
22
22
  # Note:
23
23
  # Use this if you do not want a normalized token.
24
24
  #
25
+ # TODO Throw away @predefined_categories?
26
+ #
25
27
  def initialize text, original = nil, categories = nil
26
28
  @text = text
27
29
  @original = original
@@ -59,8 +61,10 @@ module Picky
59
61
  # Note: If this is not done, there is no mapping.
60
62
  # Note: predefined is an Array of mapped categories.
61
63
  #
62
- def categorize mapper
63
- @predefined_categories ||= extract_predefined mapper
64
+ # TODO Do we really need to set the predefined categories on the token?
65
+ #
66
+ def predefined_categories mapper
67
+ @predefined_categories || extract_predefined(mapper)
64
68
  end
65
69
  def extract_predefined mapper
66
70
  user_qualified = categorize_with mapper, @qualifiers
@@ -63,12 +63,6 @@ module Picky
63
63
  @tokens.last.partial = true unless empty?
64
64
  end
65
65
 
66
- #
67
- #
68
- def categorize mapper
69
- @tokens.each { |token| token.categorize mapper }
70
- end
71
-
72
66
  #
73
67
  #
74
68
  def originals
@@ -16,6 +16,8 @@ module Picky
16
16
  # search.facets :name, filter: 'surname:peter', more_than: 0
17
17
  #
18
18
  def facets category_identifier, options = {}
19
+ # TODO Make it work. How should it work with multiple indexes?
20
+ #
19
21
  raise "#{__method__} cannot be used on searches with more than 1 index yet. Sorry!" if indexes.size > 1
20
22
  index = indexes.first
21
23
 
@@ -27,9 +29,21 @@ module Picky
27
29
  #
28
30
  return counts unless filter_query = options[:filter]
29
31
 
32
+ # Pre-tokenize query token category.
33
+ #
34
+ predefined_categories = [index[category_identifier]]
35
+
36
+ # Pre-tokenize key token – replace text below.
37
+ # Note: The original is not important.
38
+ #
39
+ # TODO Don't use predefined.
40
+ #
41
+ key_token = Query::Token.new '', nil, predefined_categories
42
+
30
43
  # Pre-tokenize filter for reuse.
31
44
  #
32
- tokenized_filter = tokenized filter_query, false
45
+ tokenized_filter_query = tokenized filter_query, false
46
+ tokenized_filter_query.tokens.push key_token
33
47
 
34
48
  # Extract options.
35
49
  #
@@ -38,15 +52,37 @@ module Picky
38
52
 
39
53
  # Get actual counts.
40
54
  #
41
- counts.inject(no_counts ? [] : {}) do |result, (key, _)|
42
- tokenized_query = tokenized "#{category_identifier}:#{key}", false
43
- total = search_with(tokenized_filter + tokenized_query, 0, 0).total
55
+ if no_counts
56
+ facets_without_counts counts, minimal_counts, tokenized_filter_query, key_token.text
57
+ else
58
+ facets_with_counts counts, minimal_counts, tokenized_filter_query, key_token.text
59
+ end
60
+ end
61
+ def facets_without_counts counts, minimal_counts, tokenized_filter_query, last_token_text
62
+ counts.inject([]) do |result, (key, _)|
63
+ # Replace only the key token text because that
64
+ # is the only information that changes in between
65
+ # queries.
66
+ #
67
+ last_token_text.replace key
68
+ total = search_with(tokenized_filter_query, 0, 0).total
69
+
70
+ next result unless total >= minimal_counts
71
+ result << key
72
+ end
73
+ end
74
+ def facets_with_counts counts, minimal_counts, tokenized_filter_query, last_token_text
75
+ counts.inject({}) do |result, (key, _)|
76
+ # Replace only the key token text because that
77
+ # is the only information that changes in between
78
+ # queries.
79
+ #
80
+ last_token_text.replace key
81
+ total = search_with(tokenized_filter_query, 0, 0).total
82
+
44
83
  next result unless total >= minimal_counts
45
- if no_counts
46
- result << key
47
- else
48
- result[key] = total; result
49
- end
84
+ result[key] = total
85
+ result
50
86
  end
51
87
  end
52
88
 
data/lib/picky/sinatra.rb CHANGED
@@ -2,6 +2,8 @@
2
2
  #
3
3
  require_relative 'sinatra/index_actions'
4
4
 
5
+ # TODO Remove for 5.0.
6
+ #
5
7
  module Picky
6
8
 
7
9
  # This Module is used to install delegator methods
@@ -93,27 +93,37 @@ Case sensitive? #{@case_sensitive ? "Yes." : "-"}
93
93
 
94
94
  # Splitting.
95
95
  #
96
- # We allow Strings and Regexps.
96
+ # We allow Strings, Regexps, and things that respond to #split.
97
+ #
97
98
  # Note: We do not test against to_str since symbols do not work with String#split.
98
99
  #
99
- def splits_text_on regexp_or_string
100
- raise ArgumentError.new "#{__method__} takes a Regexp or String as argument, not a #{regexp_or_string.class}." unless Regexp === regexp_or_string || String === regexp_or_string
101
- @splits_text_on = regexp_or_string
102
- end
103
- def split text
104
- text.split @splits_text_on
100
+ def splits_text_on thing
101
+ raise ArgumentError.new "#{__method__} takes a Regexp or String or a thing that responds to #split as argument, not a #{thing.class}." unless Regexp === thing || thing.respond_to?(:split)
102
+ @splits_text_on = thing
103
+ if thing.respond_to? :split
104
+ def split text
105
+ @splits_text_on.split text
106
+ end
107
+ else
108
+ def split text
109
+ text.split @splits_text_on
110
+ end
111
+ end
105
112
  end
106
113
 
107
114
  # Normalizing.
108
115
  #
109
116
  # We only allow arrays.
110
117
  #
118
+ # TODO 5.0 Rename to normalizes(config)
119
+ # TODO 5.0 Rename to normalize(text)
120
+ #
111
121
  def normalizes_words regexp_replaces
112
- raise ArgumentError.new "#{__method__} takes an Array of replaces as argument, not a #{regexp_replaces.class}." unless regexp_replaces.respond_to?(:to_ary)
122
+ raise ArgumentError.new "#{__method__} takes an Array of replaces as argument, not a #{regexp_replaces.class}." unless regexp_replaces.respond_to?(:to_ary) || regexp_replaces.respond_to?(:normalize_with_patterns)
113
123
  @normalizes_words_regexp_replaces = regexp_replaces
114
124
  end
115
125
  def normalize_with_patterns text
116
- return text unless @normalizes_words_regexp_replaces
126
+ return text unless @normalizes_words_regexp_replaces # TODO Remove.
117
127
 
118
128
  @normalizes_words_regexp_replaces.each do |regex, replace|
119
129
  # This should be sufficient
@@ -196,8 +206,6 @@ Case sensitive? #{@case_sensitive ? "Yes." : "-"}
196
206
  send method_name, value unless value.nil?
197
207
  end
198
208
  rescue NoMethodError => e
199
- # TODO Print out valid options.
200
- #
201
209
  raise <<-ERROR
202
210
  The option "#{e.name}" is not a valid option for a Picky tokenizer.
203
211
  Please see https://github.com/floere/picky/wiki/Indexing-configuration for valid options.
data/lib/picky.rb CHANGED
@@ -18,6 +18,8 @@ module Picky
18
18
 
19
19
  # External libraries.
20
20
  #
21
+ # TODO Remove active support.
22
+ #
21
23
  require 'active_support/core_ext/module/delegation'
22
24
  require 'active_support/core_ext/logger'
23
25
  require 'active_support/core_ext/object/blank'
@@ -69,7 +71,7 @@ module Picky
69
71
  # * Loggers::Silent
70
72
  # * Loggers::Concise (default)
71
73
  # * Loggers::Verbose
72
- #
74
+ #
73
75
  self.logger = Loggers::Default
74
76
 
75
77
  end