picky 4.0.0pre1 → 4.0.0pre2

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 (112) hide show
  1. data/aux/picky/cli.rb +6 -2
  2. data/lib/picky.rb +10 -8
  3. data/lib/picky/backends/backend.rb +37 -0
  4. data/lib/picky/backends/file.rb +0 -20
  5. data/lib/picky/backends/memory.rb +0 -29
  6. data/lib/picky/backends/redis.rb +74 -15
  7. data/lib/picky/backends/redis/list.rb +1 -1
  8. data/lib/picky/backends/sqlite.rb +0 -27
  9. data/lib/picky/bundle.rb +2 -2
  10. data/lib/picky/bundle_indexed.rb +1 -1
  11. data/lib/picky/bundle_indexing.rb +1 -1
  12. data/lib/picky/categories_indexed.rb +1 -11
  13. data/lib/picky/category.rb +4 -4
  14. data/lib/picky/category/location.rb +25 -0
  15. data/lib/picky/category_realtime.rb +4 -3
  16. data/lib/picky/console.rb +1 -1
  17. data/lib/picky/constants.rb +1 -1
  18. data/lib/picky/ext/maybe_compile.rb +2 -2
  19. data/lib/picky/extensions/object.rb +3 -2
  20. data/lib/picky/generators/aliases.rb +7 -2
  21. data/lib/picky/generators/partial/default.rb +1 -0
  22. data/lib/picky/generators/similarity/default.rb +1 -0
  23. data/lib/picky/generators/similarity/phonetic.rb +13 -2
  24. data/lib/picky/generators/strategy.rb +0 -2
  25. data/lib/picky/generators/weights/constant.rb +1 -2
  26. data/lib/picky/generators/weights/default.rb +1 -0
  27. data/lib/picky/generators/weights/dynamic.rb +1 -1
  28. data/lib/picky/generators/weights/logarithmic.rb +1 -1
  29. data/lib/picky/generators/weights/{runtime.rb → stub.rb} +1 -3
  30. data/lib/picky/index.rb +3 -3
  31. data/lib/picky/index_indexing.rb +0 -2
  32. data/lib/picky/index_realtime.rb +1 -1
  33. data/lib/picky/indexers/base.rb +7 -0
  34. data/lib/picky/indexers/parallel.rb +2 -4
  35. data/lib/picky/indexers/serial.rb +2 -0
  36. data/lib/picky/indexes_indexing.rb +1 -1
  37. data/lib/picky/interfaces/live_parameters/master_child.rb +175 -0
  38. data/lib/picky/interfaces/live_parameters/unicorn.rb +37 -0
  39. data/lib/picky/loader.rb +238 -259
  40. data/lib/picky/query/allocation.rb +19 -10
  41. data/lib/picky/query/combination.rb +7 -1
  42. data/lib/picky/query/combinations.rb +1 -6
  43. data/lib/picky/query/token.rb +26 -36
  44. data/lib/picky/results.rb +18 -17
  45. data/lib/picky/scheduler.rb +2 -1
  46. data/lib/picky/search.rb +1 -1
  47. data/lib/picky/sinatra.rb +6 -6
  48. data/lib/picky/statistics.rb +2 -0
  49. data/lib/picky/tokenizer.rb +8 -8
  50. data/lib/picky/wrappers/bundle/calculation.rb +4 -4
  51. data/lib/picky/wrappers/bundle/location.rb +1 -2
  52. data/lib/tasks/framework.rake +1 -1
  53. data/lib/tasks/statistics.rake +1 -1
  54. data/lib/tasks/try.rake +1 -1
  55. data/lib/tasks/try.rb +1 -1
  56. data/spec/aux/picky/cli_spec.rb +12 -12
  57. data/spec/ext/performant_spec.rb +16 -16
  58. data/spec/functional/backends/file_spec.rb +78 -7
  59. data/spec/functional/backends/memory_spec.rb +78 -7
  60. data/spec/functional/backends/redis_spec.rb +73 -13
  61. data/spec/functional/dynamic_weights_spec.rb +3 -4
  62. data/spec/functional/realtime_spec.rb +2 -2
  63. data/spec/functional/speed_spec.rb +2 -2
  64. data/spec/functional/terminate_early_spec.rb +3 -3
  65. data/spec/lib/analytics_spec.rb +1 -1
  66. data/spec/lib/analyzer_spec.rb +5 -3
  67. data/spec/lib/categories_indexed_spec.rb +38 -20
  68. data/spec/lib/category/location_spec.rb +30 -0
  69. data/spec/lib/character_substituters/west_european_spec.rb +1 -0
  70. data/spec/lib/extensions/hash_spec.rb +6 -5
  71. data/spec/lib/extensions/module_spec.rb +6 -6
  72. data/spec/lib/extensions/object_spec.rb +9 -8
  73. data/spec/lib/extensions/string_spec.rb +1 -1
  74. data/spec/lib/generators/similarity/phonetic_spec.rb +11 -0
  75. data/spec/lib/index_realtime_spec.rb +5 -5
  76. data/spec/lib/interfaces/{live_parameters_spec.rb → live_parameters/master_child_spec.rb} +26 -26
  77. data/spec/lib/interfaces/live_parameters/unicorn_spec.rb +160 -0
  78. data/spec/lib/loader_spec.rb +65 -25
  79. data/spec/lib/query/allocation_spec.rb +25 -22
  80. data/spec/lib/query/combinations_spec.rb +13 -36
  81. data/spec/lib/query/token_spec.rb +144 -131
  82. data/spec/lib/query/tokens_spec.rb +14 -0
  83. data/spec/lib/results_spec.rb +14 -8
  84. data/spec/lib/search_spec.rb +1 -1
  85. data/spec/lib/sinatra_spec.rb +8 -8
  86. metadata +28 -91
  87. data/lib/picky/adapters/rack.rb +0 -34
  88. data/lib/picky/adapters/rack/base.rb +0 -27
  89. data/lib/picky/adapters/rack/live_parameters.rb +0 -37
  90. data/lib/picky/adapters/rack/search.rb +0 -67
  91. data/lib/picky/application.rb +0 -268
  92. data/lib/picky/frontend_adapters/rack.rb +0 -161
  93. data/lib/picky/interfaces/live_parameters.rb +0 -187
  94. data/lib/picky/sources/base.rb +0 -92
  95. data/lib/picky/sources/couch.rb +0 -76
  96. data/lib/picky/sources/csv.rb +0 -83
  97. data/lib/picky/sources/db.rb +0 -189
  98. data/lib/picky/sources/delicious.rb +0 -63
  99. data/lib/picky/sources/mongo.rb +0 -80
  100. data/lib/picky/wrappers/category/location.rb +0 -38
  101. data/lib/tasks/routes.rake +0 -8
  102. data/spec/lib/adapters/rack/base_spec.rb +0 -24
  103. data/spec/lib/adapters/rack/live_parameters_spec.rb +0 -26
  104. data/spec/lib/adapters/rack/query_spec.rb +0 -39
  105. data/spec/lib/application_spec.rb +0 -155
  106. data/spec/lib/frontend_adapters/rack_spec.rb +0 -294
  107. data/spec/lib/sources/base_spec.rb +0 -53
  108. data/spec/lib/sources/couch_spec.rb +0 -114
  109. data/spec/lib/sources/csv_spec.rb +0 -89
  110. data/spec/lib/sources/db_spec.rb +0 -125
  111. data/spec/lib/sources/delicious_spec.rb +0 -94
  112. data/spec/lib/sources/mongo_spec.rb +0 -50
@@ -26,22 +26,31 @@ module Picky
26
26
  def hash
27
27
  @combinations.hash
28
28
  end
29
- def eql? other_allocation
30
- true # FIXME
31
- # @combinations.eql? other_allocation.combinations
32
- end
29
+ # def eql? other
30
+ # self.class == other.class && combinations.eql?(other.combinations)
31
+ # end
33
32
 
34
- # Scores its combinations and caches the result.
33
+ # Asks the backend for the total score and
34
+ # adds the boosts to it.
35
+ #
36
+ # THINK Can the combinations be empty?
35
37
  #
36
38
  def calculate_score weights
37
- @score ||= @combinations.calculate_score(weights)
39
+ @score ||= if @combinations.empty?
40
+ 0
41
+ else
42
+ @backend.weight(@combinations) +
43
+ @combinations.weighted_score(weights)
44
+ end
38
45
  end
39
46
 
40
47
  # Asks the backend for the (intersected) ids.
41
48
  #
49
+ # THINK Can the combinations be empty?
50
+ #
42
51
  def calculate_ids amount, offset
43
- return [] if combinations.empty?
44
- @backend.ids combinations, amount, offset
52
+ return [] if @combinations.empty?
53
+ @backend.ids @combinations, amount, offset
45
54
  end
46
55
 
47
56
  # Ids return by default [].
@@ -82,8 +91,8 @@ module Picky
82
91
  #
83
92
  # Note: Delegates to to_result.
84
93
  #
85
- def to_json
86
- to_result.to_json
94
+ def to_json options = {}
95
+ Yajl::Encoder.encode to_result, options
87
96
  end
88
97
 
89
98
  #
@@ -27,6 +27,12 @@ module Picky
27
27
  @category_name ||= category.name
28
28
  end
29
29
 
30
+ #
31
+ #
32
+ def bundle
33
+ category.bundle_for token
34
+ end
35
+
30
36
  # Returns the weight of this combination.
31
37
  #
32
38
  # Note: Caching is most of the time useful.
@@ -46,7 +52,7 @@ module Picky
46
52
  # The identifier for this combination.
47
53
  #
48
54
  def identifier
49
- @identifier ||= "#{category.bundle_for(token).identifier}:inverted:#{token.text}"
55
+ @identifier ||= "#{bundle.identifier}:inverted:#{token.text}"
50
56
  end
51
57
 
52
58
  # Note: Required for uniq!
@@ -25,12 +25,7 @@ module Picky
25
25
  @combinations.hash
26
26
  end
27
27
 
28
- # Uses user specific weights to calculate a score for the combinations.
29
- #
30
- def calculate_score weights
31
- total_score + weighted_score(weights)
32
- end
33
- def total_score
28
+ def score
34
29
  @combinations.sum &:weight
35
30
  end
36
31
  def weighted_score weights
@@ -11,19 +11,22 @@ module Picky
11
11
  #
12
12
  class Token # :nodoc:all
13
13
 
14
- attr_reader :text, :original, :qualifiers, :user_defined_categories
14
+ attr_reader :text, :original
15
15
  attr_writer :similar
16
+ attr_accessor :user_defined_categories
16
17
 
17
- delegate :blank?, :to => :text
18
+ delegate :blank?,
19
+ :to => :text
18
20
 
19
21
  # Normal initializer.
20
22
  #
21
23
  # Note:
22
24
  # Use this if you do not want a normalized token.
23
25
  #
24
- def initialize text, original = nil
26
+ def initialize text, original = nil, category = nil
25
27
  @text = text
26
28
  @original = original
29
+ @user_defined_categories = [category] if category
27
30
  end
28
31
 
29
32
  # Returns a qualified and normalized token.
@@ -89,10 +92,10 @@ module Picky
89
92
  # So "hello*" will not be partially searched.
90
93
  # So "hello"* will be partially searched.
91
94
  #
92
- @@no_partial = /\"\Z/
93
- @@partial = /\*\Z/
95
+ @@no_partial = /\"\z/
96
+ @@partial = /\*\z/
94
97
  def partialize
95
- self.partial = false and return unless @text !~ @@no_partial
98
+ self.partial = false or return unless @text !~ @@no_partial
96
99
  self.partial = true unless @text !~ @@partial
97
100
  end
98
101
 
@@ -100,11 +103,11 @@ module Picky
100
103
  #
101
104
  # The latter wins.
102
105
  #
103
- @@no_similar = /\"\Z/
104
- @@similar = /\~\Z/
106
+ @@no_similar = /\"\z/
107
+ @@similar = /\~\z/
105
108
  def similarize
106
- self.similar = false and return if @text =~ @@no_similar
107
- self.similar = true if @text =~ @@similar
109
+ self.similar = false or return unless @text !~ @@no_similar
110
+ self.similar = true unless @text !~ @@similar
108
111
  end
109
112
 
110
113
  def similar?
@@ -124,33 +127,13 @@ module Picky
124
127
  index.possible_combinations self
125
128
  end
126
129
 
127
- # Returns a token with the next similar text.
130
+ # Returns all similar tokens for the token.
128
131
  #
129
- # THINK Rewrite this. It is hard to understand. Also spec performance.
130
- #
131
- def next_similar_token category
132
- token = self.dup
133
- token if token.next_similar category.bundle_for(token)
134
- end
135
- # Sets and returns the next similar word.
136
- #
137
- # Note: Also overrides the original.
138
- #
139
- def next_similar bundle
140
- @text = @original = (similarity(bundle).shift || return) if similar?
141
- end
142
- # Lazy similar reader.
143
- #
144
- def similarity bundle = nil
145
- @similarity || @similarity = generate_similarity_for(bundle)
146
- end
147
- # Returns an enumerator that traverses over the similar.
148
- #
149
- # Note: The dup isn't too nice – since it is needed on account of the shift, above.
150
- # (We avoid a StopIteration exception. Which of both is less evil?)
151
- #
152
- def generate_similarity_for bundle
153
- bundle.similar(@text) || []
132
+ def similar_tokens_for category
133
+ similars = category.bundle_for(self).similar @text
134
+ similars.map do |similar|
135
+ self.class.new similar, similar, category
136
+ end
154
137
  end
155
138
 
156
139
  # Splits text into a qualifier and text.
@@ -166,6 +149,13 @@ module Picky
166
149
  end
167
150
  end
168
151
 
152
+ # Internally, qualifiers are nil if there are none.
153
+ # This returns an empty array in this case for a nicer API.
154
+ #
155
+ def qualifiers
156
+ @qualifiers || []
157
+ end
158
+
169
159
  #
170
160
  #
171
161
  def to_result
data/lib/picky/results.rb CHANGED
@@ -30,6 +30,15 @@ module Picky
30
30
  results
31
31
  end
32
32
 
33
+ # This starts the actual processing.
34
+ #
35
+ # Without this, the allocations are not processed,
36
+ # and no ids are calculated.
37
+ #
38
+ def prepare! extra_allocations = nil
39
+ allocations.process! amount, offset, extra_allocations
40
+ end
41
+
33
42
  # Delegates to allocations.
34
43
  #
35
44
  def ids amount = 20
@@ -39,7 +48,7 @@ module Picky
39
48
  # The total results. Delegates to the allocations.
40
49
  #
41
50
  def total
42
- @total || @total = allocations.total || 0
51
+ @total ||= allocations.total || 0
43
52
  end
44
53
 
45
54
  # Duration default is 0.
@@ -48,15 +57,6 @@ module Picky
48
57
  @duration || 0
49
58
  end
50
59
 
51
- # This starts the actual processing.
52
- #
53
- # Without this, the allocations are not processed,
54
- # and no ids are calculated.
55
- #
56
- def prepare! extra_allocations = nil
57
- allocations.process! amount, offset, extra_allocations
58
- end
59
-
60
60
  # Returns a hash with the allocations, offset, duration and total.
61
61
  #
62
62
  def to_hash
@@ -69,7 +69,14 @@ module Picky
69
69
  # Convert to json format.
70
70
  #
71
71
  def to_json options = {}
72
- to_hash.to_json options
72
+ Yajl::Encoder.encode to_hash, options
73
+ end
74
+
75
+ # For logging.
76
+ #
77
+ @@log_time_format = "%Y-%m-%d %H:%M:%S".freeze
78
+ def to_s
79
+ "#{log_type}|#{Time.now.strftime @@log_time_format}|#{'%8f' % duration}|#{'%-50s' % query}|#{'%8d' % total}|#{'%4d' % offset}|#{'%2d' % allocations.size}|"
73
80
  end
74
81
 
75
82
  # The first character in the blog designates what type of query it is.
@@ -80,12 +87,6 @@ module Picky
80
87
  amount.zero?? :'.' : :'>'
81
88
  end
82
89
 
83
- # For logging.
84
- #
85
- def to_s
86
- "#{log_type}|#{Time.now.to_s(:db)}|#{'%8f' % duration}|#{'%-50s' % query}|#{'%8d' % total}|#{'%4d' % offset}|#{'%2d' % allocations.size}|"
87
- end
88
-
89
90
  end
90
91
 
91
92
  end
@@ -6,6 +6,7 @@ module Picky
6
6
 
7
7
  def initialize options = {}
8
8
  @parallel = options[:parallel]
9
+ @factor = options[:factor] || 2
9
10
 
10
11
  configure
11
12
  end
@@ -21,7 +22,7 @@ module Picky
21
22
  end
22
23
 
23
24
  def scheduler
24
- @scheduler ||= Procrastinate::Scheduler.start Procrastinate::SpawnStrategy::Default.new(2)
25
+ @scheduler ||= Procrastinate::Scheduler.start Procrastinate::SpawnStrategy::Default.new(@factor)
25
26
  end
26
27
  else
27
28
  def schedule
data/lib/picky/search.rb CHANGED
@@ -40,7 +40,7 @@ module Picky
40
40
 
41
41
  instance_eval(&Proc.new) if block_given?
42
42
 
43
- @tokenizer ||= Tokenizer.query_default # THINK Not dynamic. Ok?
43
+ @tokenizer ||= Tokenizer.searching # THINK Not dynamic. Ok?
44
44
  @weights ||= Query::Weights.new
45
45
  @ignore_unassigned = false if @ignore_unassigned.nil?
46
46
 
data/lib/picky/sinatra.rb CHANGED
@@ -11,16 +11,16 @@ module Picky
11
11
  private :indexing, :searching
12
12
  end
13
13
 
14
- # Delegates to Application.
14
+ # Sets tokenizer default indexing options.
15
15
  #
16
- def indexing options
17
- Application.indexing options
16
+ def indexing options = {}
17
+ Tokenizer.default_indexing_with options
18
18
  end
19
19
 
20
- # Delegates to Application.
20
+ # Sets tokenizer default searching options.
21
21
  #
22
- def searching options
23
- Application.searching options
22
+ def searching options = {}
23
+ Tokenizer.default_searching_with options
24
24
  end
25
25
 
26
26
  end
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
  #
3
+ require_relative 'analyzer'
4
+
3
5
  module Picky
4
6
 
5
7
  # Gathers various statistics.
@@ -6,18 +6,18 @@ module Picky
6
6
  #
7
7
  class Tokenizer
8
8
 
9
- def self.index_default= new_default
10
- @index_default = new_default
9
+ def self.default_indexing_with options = {}
10
+ @indexing = options.respond_to?(:tokenize) ? options : new(options)
11
11
  end
12
- def self.index_default
13
- @index_default ||= new
12
+ def self.indexing
13
+ @indexing ||= new
14
14
  end
15
15
 
16
- def self.query_default= new_default
17
- @query_default = new_default
16
+ def self.default_searching_with options = {}
17
+ @searching = options.respond_to?(:tokenize) ? options : new(options)
18
18
  end
19
- def self.query_default
20
- @query_default ||= new
19
+ def self.searching
20
+ @searching ||= new
21
21
  end
22
22
 
23
23
  def to_s
@@ -9,10 +9,6 @@ module Picky
9
9
  # Note: A calculation will try to find a float in the index,
10
10
  # not a sym.
11
11
  #
12
- # TODO I really need to allow integers as keys.
13
- # The code below is just not up to the needed quality.
14
- # Use key_format :to_i?
15
- #
16
12
  class Calculation < Wrapper
17
13
 
18
14
  # API.
@@ -26,12 +22,16 @@ module Picky
26
22
 
27
23
  # TODO Symbols. Use a block here?
28
24
  #
25
+ # THINK Move the calculation elsewhere?
26
+ #
29
27
  def ids float_str
30
28
  @bundle.ids calculate(float_str.to_f).to_s
31
29
  end
32
30
 
33
31
  # TODO Symbols.
34
32
  #
33
+ # THINK Move the calculation elsewhere?
34
+ #
35
35
  def weight float_str
36
36
  @bundle.weight calculate(float_str.to_f).to_s
37
37
  end
@@ -8,10 +8,9 @@ module Picky
8
8
  #
9
9
  class Location < Calculation
10
10
 
11
- def initialize bundle, options = {}
11
+ def initialize bundle, user_grid, options = {}
12
12
  super bundle
13
13
 
14
- user_grid = options[:grid] || raise("Gridsize needs to be given for location #{bundle.identifier}.")
15
14
  anchor = options[:anchor] || 0.0
16
15
  precision = options[:precision] || 1
17
16
 
@@ -3,5 +3,5 @@
3
3
  # Note: This is used by tasks to load the framework as a dependency.
4
4
  #
5
5
  task :framework do
6
- require File.expand_path '../../picky', __FILE__
6
+ require_relative '../picky'
7
7
  end
@@ -28,7 +28,7 @@ end
28
28
  namespace :stats do
29
29
 
30
30
  task :prepare => :application do
31
- require File.expand_path('../../picky/statistics', __FILE__)
31
+ require_relative '../picky/statistics'
32
32
  end
33
33
 
34
34
  end
data/lib/tasks/try.rake CHANGED
@@ -5,7 +5,7 @@ task :try, [:text, :index, :category] => :application do |_, options|
5
5
  puts
6
6
  fail "\x1b[31mrake try needs a text to try indexing and query preparation\x1b[m, e.g. rake 'try[yourtext]'." unless options.text
7
7
 
8
- require File.expand_path '../try', __FILE__
8
+ require_relative 'try'
9
9
  try = Picky::Try.new options.text, options.index, options.category
10
10
  try.to_stdout
11
11
  end
data/lib/tasks/try.rb CHANGED
@@ -16,7 +16,7 @@ module Picky
16
16
  end
17
17
 
18
18
  def searched
19
- Picky::Tokenizer.query_default.tokenize(text.dup).first
19
+ Picky::Tokenizer.searching.tokenize(text.dup).first
20
20
  end
21
21
 
22
22
  def output
@@ -4,14 +4,14 @@ require 'spec_helper'
4
4
 
5
5
  # We need to load the CLI file explicitly as the CLI is not loaded with the Loader (not needed in the server, only for script runs).
6
6
  #
7
- require File.expand_path '../../../../aux/picky/cli', __FILE__
7
+ require_relative '../../../aux/picky/cli'
8
8
 
9
9
  describe Picky::CLI do
10
-
10
+
11
11
  describe '.mapping' do
12
12
  it 'returns the right mapping' do
13
13
  Picky::CLI.mapping.should == {
14
- :generate => [Picky::CLI::Generate, :"{client,server,sinatra_client,unicorn_server,all_in_one}", :app_directory_name],
14
+ :generate => [Picky::CLI::Generate, :"{client,server,all_in_one}", :app_directory_name],
15
15
  :help => [Picky::CLI::Help],
16
16
  :live => [Picky::CLI::Live, "host:port/path (default: localhost:8080/admin)", "port (default: 4568)"],
17
17
  :search => [Picky::CLI::Search, :url_or_path, 'amount of ids (default 20)'],
@@ -19,20 +19,20 @@ describe Picky::CLI do
19
19
  }
20
20
  end
21
21
  end
22
-
22
+
23
23
  describe 'instance' do
24
24
  let(:cli) { described_class.new }
25
25
  describe 'execute' do
26
26
  it 'calls generate correctly' do
27
27
  Kernel.should_receive(:system).once.with 'picky-generate one two three'
28
-
28
+
29
29
  cli.execute 'generate', 'one', 'two', 'three'
30
30
  end
31
31
  it 'calls help correctly' do
32
32
  Kernel.should_receive(:puts).once.with <<-HELP
33
33
  Possible commands:
34
- picky generate {client,server,sinatra_client,unicorn_server,all_in_one} app_directory_name
35
- picky help
34
+ picky generate {client,server,all_in_one} app_directory_name
35
+ picky help
36
36
  picky live [host:port/path (default: localhost:8080/admin)] [port (default: 4568)]
37
37
  picky search url_or_path [amount of ids (default 20)]
38
38
  picky stats logfile (e.g. log/search.log) [port (default: 4567)]
@@ -51,7 +51,7 @@ HELP
51
51
  cli.executor_class_for.should == [Picky::CLI::Help]
52
52
  end
53
53
  it 'returns Generator for generate' do
54
- cli.executor_class_for(:generate).should == [Picky::CLI::Generate, :'{client,server,sinatra_client,unicorn_server,all_in_one}', :"app_directory_name"]
54
+ cli.executor_class_for(:generate).should == [Picky::CLI::Generate, :'{client,server,all_in_one}', :"app_directory_name"]
55
55
  end
56
56
  it 'returns Help for help' do
57
57
  cli.executor_class_for(:help).should == [Picky::CLI::Help]
@@ -70,17 +70,17 @@ HELP
70
70
  end
71
71
  end
72
72
  end
73
-
73
+
74
74
  describe Picky::CLI::Live do
75
75
  let(:executor) { Picky::CLI::Live.new }
76
76
  end
77
-
77
+
78
78
  describe Picky::CLI::Base do
79
79
  let(:executor) { Picky::CLI::Base.new }
80
80
  describe 'usage' do
81
81
  it 'calls puts with an usage' do
82
82
  executor.should_receive(:puts).once.with "Usage:\n picky some_name param1 [param2]"
83
-
83
+
84
84
  executor.usage :some_name, [:param1, 'param2']
85
85
  end
86
86
  end
@@ -90,5 +90,5 @@ HELP
90
90
  end
91
91
  end
92
92
  end
93
-
93
+
94
94
  end