picky 4.10.0 → 4.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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