highline 2.0.0.pre.develop.4 → 2.0.0.pre.develop.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe7f4a2acbc139058d22c6e720cf45f3d8807278
4
- data.tar.gz: 4a2e208bb898d2498f5911efaa695095341cb43c
3
+ metadata.gz: 13e2a946fd059cbf2c25bff77dc7e70b299fccab
4
+ data.tar.gz: c35a2236e1ce0d83cac30b9e2464abf4f61fc421
5
5
  SHA512:
6
- metadata.gz: 3f276ad26eb858d757254770be10c6a007b0c4032078ef7f750b677499ed19c43315b0518d802480fd3cb9b8f2804286bdfd255ea647a85f5209be312dd8ab90
7
- data.tar.gz: ab6323e8a8a16a5912328700cb207ca9009a60f05772102bf643db3ca8dd4b21dc7a527d79aad8113cbb32f2d6a1ed66297220d3faf86c3ca43d8befa85a8034
6
+ metadata.gz: dadda880956f0ecb41ffca76a81cb89cd26fc63e3dea10f54bc7753d7af95e7f04a7185b0a1caab7a2b0ea31cc0cb932fb25971094252925af9cd52759176a4f
7
+ data.tar.gz: 54aa4ee03370b217bb9dacb8e94ba129f70cab24513297fe24f863a99b635ba45992091d5dea60c08ee94f5d77138329d9385f6ff01808336bdf8ac1d859d219
data/.gitignore CHANGED
@@ -2,3 +2,4 @@ doc
2
2
  pkg
3
3
  .DS_Store
4
4
  coverage
5
+ Gemfile.lock
@@ -2,6 +2,16 @@
2
2
 
3
3
  Below is a complete listing of changes for each revision of HighLine.
4
4
 
5
+ ### 2.0.0-develop.6 / 2016-02-01
6
+ * PR #184 - Menu improvements, bug fixes, and more tests by Geoff Lee (@matrinox)
7
+ * Add third arg to menu that overides the choice displayed to the user
8
+ * FIX: autocomplete prompt does not include menu choices after the first
9
+ * Add specs to cover the new features and the bug fix
10
+ * PR #183 - Fix menu example in README.md by Fabien Foerster (@fabienfoerster)
11
+
12
+ ### 2.0.0-develop.5 / 2015-12-27
13
+ * Fix #180 with PR #181 - Make it possible to overwrite the menu prompt shown on errors.
14
+
5
15
  ### 2.0.0-develop.4 / 2015-12-14
6
16
  This versions makes the code documentation 100% 'A' grade on inch.
7
17
  We have used inch and http://inch-ci.org to guide the priorities
data/README.md CHANGED
@@ -72,8 +72,8 @@ cli.say("This should be <%= color('bold', BOLD) %>!")
72
72
 
73
73
  cli.choose do |menu|
74
74
  menu.prompt = "Please choose your favorite programming language? "
75
- menu.choice(:ruby) { say("Good choice!") }
76
- menu.choices(:python, :perl) { say("Not from around here, are you?") }
75
+ menu.choice(:ruby) { cli.say("Good choice!") }
76
+ menu.choices(:python, :perl) { cli.say("Not from around here, are you?") }
77
77
  end
78
78
  ```
79
79
 
@@ -251,11 +251,18 @@ class HighLine
251
251
  menu.answer_type = menu.shell ? shell_style_lambda(menu) : menu.options
252
252
 
253
253
  selected = ask(menu)
254
+ return unless selected
254
255
 
255
256
  if menu.shell
256
- menu.select(self, *selected)
257
+ selection, details = selected
257
258
  else
258
- menu.select(self, selected)
259
+ selection = selected
260
+ end
261
+
262
+ if menu.gather
263
+ menu.gather_selected(self, selection, details)
264
+ else
265
+ menu.select(self, selection, details)
259
266
  end
260
267
  end
261
268
 
@@ -485,7 +492,7 @@ class HighLine
485
492
  # of the question.
486
493
  #
487
494
  def explain_error(error, question)
488
- say(question.responses[error]) if error
495
+ say(question.final_responses[error]) if error
489
496
  say(question.ask_on_error_msg)
490
497
  end
491
498
 
@@ -154,20 +154,45 @@ class HighLine
154
154
  # cli.choose do |menu|
155
155
  # menu.shell = true
156
156
  #
157
- # menu.choice(:load, "Load a file.")
158
- # menu.choice(:save, "Save data in file.")
159
- # menu.choice(:quit, "Exit program.")
157
+ # menu.choice(:load, text: 'Load a file', help: "Load a file using your favourite editor.")
158
+ # menu.choice(:save, help: "Save data in file.")
159
+ # menu.choice(:quit, help: "Exit program.")
160
160
  #
161
161
  # menu.help("rules", "The rules of this system are as follows...")
162
162
  # end
163
163
 
164
- def choice( name, help = nil, &action )
165
- @items << [name, action]
166
-
167
- @help[name.to_s.downcase] = help if help
164
+ def choice( name, help = nil, text = nil, &action )
165
+ item = MenuItem.new(name, text: text, help: help, action: action)
166
+ @items << item
167
+ @help.merge!(item.item_help)
168
168
  update_responses # rebuild responses based on our settings
169
169
  end
170
170
 
171
+ #
172
+ # This method helps reduce the namespaces in the original call, which would look
173
+ # like this: HighLine::Menu::MenuItem.new(...)
174
+ # With #build_item, it looks like this: menu.build_item(...)
175
+ # @param *args splat args, the same args you would pass to an initialization of
176
+ # HighLine::Menu::MenuItem
177
+ # @return [HighLine::Menu::MenuItem] the menu item
178
+
179
+ def build_item(*args)
180
+ MenuItem.new(*args)
181
+ end
182
+
183
+ #
184
+ # Adds an item directly to the menu. If you want more configuraiton or options,
185
+ # use this method
186
+ #
187
+ # @param item [Menu::MenuItem] item containing choice fields and more
188
+ # @return [void]
189
+
190
+ def add_item(item)
191
+ @items << item
192
+ @help.merge!(item.item_help)
193
+ update_responses
194
+ end
195
+
171
196
  #
172
197
  # A shortcut for multiple calls to the sister method {#choice}. <b>Be
173
198
  # warned:</b> An _action_ set here will apply to *all* provided
@@ -177,6 +202,10 @@ class HighLine
177
202
  # @param action (see #choice)
178
203
  # @return [void]
179
204
  # @example (see HighLine::Menu#initialize)
205
+ #
206
+ # choice has more options available to you, like longer text or help (and
207
+ # of course, individual actions)
208
+ #
180
209
  def choices( *names, &action )
181
210
  names.each { |n| choice(n, &action) }
182
211
  end
@@ -189,9 +218,9 @@ class HighLine
189
218
  # @return (see #choice)
190
219
 
191
220
  def hidden( name, help = nil, &action )
192
- @hidden_items << [name, action]
193
-
194
- @help[name.to_s.downcase] = help if help
221
+ item = MenuItem.new(name, text: name, help: help, action: action)
222
+ @hidden_items << item
223
+ @help.merge!(item.item_help)
195
224
  end
196
225
 
197
226
  #
@@ -302,27 +331,29 @@ class HighLine
302
331
  #
303
332
  def options( )
304
333
  # add in any hidden menu commands
305
- @items.concat(@hidden_items)
306
-
307
- by_index = if @index == :letter
308
- l_index = "`"
309
- @items.map { "#{l_index.succ!}" }
310
- else
311
- (1 .. @items.size).collect { |s| String(s) }
312
- end
313
- by_name = @items.collect { |c| c.first }
334
+ items = all_items
314
335
 
315
336
  case @select_by
316
337
  when :index then
317
- by_index
338
+ map_items_by_index(items, @index)
318
339
  when :name
319
- by_name
340
+ items.map(&:name)
341
+ else
342
+ map_items_by_index(items, @index) + items.map(&:name)
343
+ end
344
+ end
345
+
346
+ def map_items_by_index(items, index = nil)
347
+ if index == :letter
348
+ l_index = "`"
349
+ items.map { "#{l_index.succ!}" }
320
350
  else
321
- by_index + by_name
351
+ (1 .. items.size).map(&:to_s)
322
352
  end
323
- ensure
324
- # make sure the hidden items are removed, before we return
325
- @items.slice!(@items.size - @hidden_items.size, @hidden_items.size)
353
+ end
354
+
355
+ def all_items
356
+ @items + @hidden_items
326
357
  end
327
358
 
328
359
  #
@@ -337,44 +368,83 @@ class HighLine
337
368
  # else it returns the action return value.
338
369
  def select( highline_context, selection, details = nil )
339
370
  # add in any hidden menu commands
340
- @items.concat(@hidden_items)
371
+ items = all_items
341
372
 
342
373
  # Find the selected action.
343
- name, action = if selection =~ /^\d+$/ # is a number?
344
- get_item_by_number(selection)
345
- else
346
- get_item_by_letter(selection)
347
- end
374
+ selected_item = find_item_from_selection(items, selection)
348
375
 
349
376
  # Run or return it.
350
- if action
351
- @highline = highline_context
352
- if @shell
353
- result = action.call(name, details)
354
- else
355
- result = action.call(name)
356
- end
357
- @nil_on_handled ? nil : result
377
+ @highline = highline_context
378
+ value_for_selected_item(selected_item, details)
379
+ end
380
+
381
+ def find_item_from_selection(items, selection)
382
+ if selection =~ /^\d+$/ # is a number?
383
+ get_item_by_number(items, selection)
358
384
  else
359
- name
385
+ get_item_by_letter(items, selection)
360
386
  end
361
- ensure
362
- # make sure the hidden items are removed, before we return
363
- @items.slice!(@items.size - @hidden_items.size, @hidden_items.size)
364
387
  end
365
388
 
366
389
  # Returns the menu item referenced by its index
367
390
  # @param selection [Integer] menu item's index.
368
- def get_item_by_number(selection)
369
- @items[selection.to_i - 1]
391
+ def get_item_by_number(items, selection)
392
+ items[selection.to_i - 1]
370
393
  end
371
394
 
372
395
  # Returns the menu item referenced by its title/header/name.
373
396
  # @param selection [String] menu's title/header/name
374
- def get_item_by_letter(selection)
397
+ def get_item_by_letter(items, selection)
398
+ item = items.find { |i| i.name == selection }
399
+ return item if item
375
400
  l_index = "`" # character before the letter "a"
376
- index = @items.map { "#{l_index.succ!}" }.index(selection)
377
- @items.find { |c| c.first == selection } or @items[index]
401
+ index = items.map { "#{l_index.succ!}" }.index(selection)
402
+ items[index]
403
+ end
404
+
405
+ def value_for_selected_item(item, details)
406
+ if item.action
407
+ if @shell
408
+ result = item.action.call(item.name, details)
409
+ else
410
+ result = item.action.call(item.name)
411
+ end
412
+ @nil_on_handled ? nil : result
413
+ else
414
+ item.name
415
+ end
416
+ end
417
+
418
+ def gather_selected(highline_context, selections, details = nil)
419
+ @highline = highline_context
420
+ # add in any hidden menu commands
421
+ items = all_items
422
+
423
+ if selections.is_a?(Array)
424
+ value_for_array_selections(items, selections, details)
425
+ elsif selections.is_a?(Hash)
426
+ value_for_hash_selections(items, selections, details)
427
+ else
428
+ fail ArgumentError, 'selections must be either Array or Hash'
429
+ end
430
+ end
431
+
432
+ def value_for_array_selections(items, selections, details)
433
+ # Find the selected items and return values
434
+ selected_items = selections.map do |selection|
435
+ find_item_from_selection(items, selection)
436
+ end
437
+ selected_items.map do |selected_item|
438
+ value_for_selected_item(selected_item, details)
439
+ end
440
+ end
441
+
442
+ def value_for_hash_selections(items, selections, details)
443
+ # Find the selected items and return in hash form
444
+ selections.each_with_object({}) do |(key, selection), memo|
445
+ selected_item = find_item_from_selection(items, selection)
446
+ memo[key] = value_for_selected_item(selected_item, details)
447
+ end
378
448
  end
379
449
 
380
450
  #
@@ -385,14 +455,14 @@ class HighLine
385
455
  def to_ary( )
386
456
  case @index
387
457
  when :number
388
- @items.map { |c| "#{@items.index(c) + 1}#{@index_suffix}#{c.first}" }
458
+ @items.map { |i| "#{@items.index(i) + 1}#{@index_suffix}#{i.text}" }
389
459
  when :letter
390
460
  l_index = "`"
391
- @items.map { |c| "#{l_index.succ!}#{@index_suffix}#{c.first}" }
461
+ @items.map { |i| "#{l_index.succ!}#{@index_suffix}#{i.text}" }
392
462
  when :none
393
- @items.map { |c| "#{c.first}" }
463
+ @items.map { |i| "#{i.text}" }
394
464
  else
395
- @items.map { |c| "#{index}#{@index_suffix}#{c.first}" }
465
+ @items.map { |i| "#{index}#{@index_suffix}#{i.text}" }
396
466
  end
397
467
  end
398
468
 
@@ -425,12 +495,32 @@ class HighLine
425
495
  # This method will update the intelligent responses to account for
426
496
  # Menu specific differences. Calls the superclass' (Question's)
427
497
  # build_responses method, overriding its default arguments to specify
428
- # 'options' will be used to populate choice lists, and that
429
- # the newly built hash will predominate over the preexisting hash
430
- # for any keys that are the same.
498
+ # 'options' will be used to populate choice lists.
431
499
  #
432
- def update_responses( )
433
- build_responses(options, true)
500
+ def update_responses
501
+ build_responses(options)
502
+ end
503
+
504
+ class MenuItem
505
+ attr_reader :name, :text, :help, :action
506
+
507
+ #
508
+ # @param name [String] The name that is matched against the user input
509
+ # @param text: [String] The text that displays for that choice (defaults to name)
510
+ # @param help: [String] help, see above (not sure how it works)
511
+ # @param action: [Block] a block that gets called when choice is selected
512
+ #
513
+ def initialize(name, attributes)
514
+ @name = name
515
+ @text = attributes[:text] || @name
516
+ @help = attributes[:help]
517
+ @action = attributes[:action]
518
+ end
519
+
520
+ def item_help
521
+ return {} unless help
522
+ { name.to_s.downcase => help }
523
+ end
434
524
  end
435
525
  end
436
526
  end
@@ -61,7 +61,8 @@ class HighLine
61
61
  @first_answer = nil
62
62
  @directory = Pathname.new(File.expand_path(File.dirname($0)))
63
63
  @glob = "*"
64
- @responses = Hash.new
64
+ @user_responses = Hash.new
65
+ @internal_responses = default_responses_hash
65
66
  @overwrite = false
66
67
 
67
68
  # allow block to override settings
@@ -214,7 +215,9 @@ class HighLine
214
215
  # <tt>:not_valid</tt>:: The error message shown when
215
216
  # validation checks fail.
216
217
  #
217
- attr_reader :responses
218
+ def responses
219
+ @user_responses
220
+ end
218
221
  #
219
222
  # When set to +true+ the question is asked, but output does not progress to
220
223
  # the next line. The Cursor is moved back to the beginning of the question
@@ -242,16 +245,21 @@ class HighLine
242
245
  # @return [Hash] responses Hash winner (new and old merge).
243
246
  # @param message_source [Class] Array or String for example.
244
247
  # Same as {#answer_type}.
245
- # @param new_hash_wins [Boolean] merge precedence (new vs. old).
246
248
 
247
- def build_responses(message_source = answer_type, new_hash_wins = false)
249
+ def build_responses(message_source = answer_type)
248
250
  append_default if [::String, Symbol].include? default.class
249
251
 
250
- old_hash = responses
251
-
252
252
  new_hash = build_responses_new_hash(message_source)
253
+ # Update our internal responses with the new hash
254
+ # generated from the message source
255
+ @internal_responses = @internal_responses.merge(new_hash)
256
+ end
253
257
 
254
- @responses = new_hash_wins ? old_hash.merge(new_hash) : new_hash.merge(old_hash)
258
+ def default_responses_hash
259
+ {
260
+ :ask_on_error => "? ",
261
+ :mismatch => "Your entries didn't match."
262
+ }
255
263
  end
256
264
 
257
265
  # When updating the responses hash, it generates the new one.
@@ -260,17 +268,21 @@ class HighLine
260
268
  def build_responses_new_hash(message_source)
261
269
  { :ambiguous_completion => "Ambiguous choice. Please choose one of " +
262
270
  choice_error_str(message_source) + '.',
263
- :ask_on_error => "? ",
264
271
  :invalid_type => "You must enter a valid #{message_source}.",
265
272
  :no_completion => "You must choose one of " +
266
273
  choice_error_str(message_source) + '.',
267
274
  :not_in_range => "Your answer isn't within the expected range " +
268
275
  "(#{expected_range}).",
269
- :mismatch => "Your entries didn't match.",
270
276
  :not_valid => "Your answer isn't valid (must match " +
271
277
  "#{validate.inspect})." }
272
278
  end
273
279
 
280
+ # This is the actual responses hash that gets used in determining output
281
+ # Notice that we give @user_responses precedence over the responses
282
+ # generated internally via build_response
283
+ def final_responses
284
+ @internal_responses.merge(@user_responses)
285
+ end
274
286
 
275
287
  #
276
288
  # Returns the provided _answer_string_ after changing character case by
@@ -531,10 +543,10 @@ class HighLine
531
543
  # @return [self] if :ask_on_error on responses Hash is set to :question
532
544
  # @return [String] if :ask_on_error on responses Hash is set to something else
533
545
  def ask_on_error_msg
534
- if responses[:ask_on_error] == :question
546
+ if final_responses[:ask_on_error] == :question
535
547
  self
536
- elsif responses[:ask_on_error]
537
- responses[:ask_on_error]
548
+ elsif final_responses[:ask_on_error]
549
+ final_responses[:ask_on_error]
538
550
  end
539
551
  end
540
552
 
@@ -105,13 +105,11 @@ class HighLine
105
105
  # with keys provided by the Hash on {Question#gather}
106
106
  # @return [Hash]
107
107
  def gather_hash
108
- answers = {}
109
-
110
- question.gather.keys.sort.each do |key|
108
+ sorted_keys = question.gather.keys.sort_by(&:to_s)
109
+ sorted_keys.each_with_object({}) do |key, answers|
111
110
  @highline.key = key
112
111
  answers[key] = ask_once
113
112
  end
114
- answers
115
113
  end
116
114
 
117
115
 
@@ -119,7 +117,7 @@ class HighLine
119
117
 
120
118
  ## Delegate to Highline
121
119
  def explain_error(error)
122
- @highline.say(question.responses[error]) if error
120
+ @highline.say(question.final_responses[error]) if error
123
121
  @highline.say(question.ask_on_error_msg)
124
122
  end
125
123
 
@@ -133,15 +131,18 @@ class HighLine
133
131
  end
134
132
 
135
133
  def answer_matches_regex(answer)
136
- (question.gather.is_a?(::String) && answer.to_s == question.gather) ||
137
- (question.gather.is_a?(Regexp) && answer.to_s =~ question.gather)
134
+ if question.gather.is_a?(::String) || question.gather.is_a?(Symbol)
135
+ answer.to_s == question.gather.to_s
136
+ else question.gather.is_a?(Regexp)
137
+ answer.to_s =~ question.gather
138
+ end
138
139
  end
139
140
 
140
141
  def gather_answers_based_on_type
141
142
  case question.gather
142
143
  when Integer
143
144
  gather_integer
144
- when ::String, Regexp
145
+ when ::String, Symbol, Regexp
145
146
  gather_regexp
146
147
  when Hash
147
148
  gather_hash
@@ -2,5 +2,5 @@
2
2
 
3
3
  class HighLine
4
4
  # The version of the installed library.
5
- VERSION = "2.0.0-develop.4".freeze
5
+ VERSION = "2.0.0-develop.6".freeze
6
6
  end
@@ -37,21 +37,21 @@ class TestMenu < Minitest::Test
37
37
 
38
38
  @terminal.choose do |menu|
39
39
  # Default: menu.flow = :rows
40
-
41
- menu.choice "Sample1"
42
- menu.choice "Sample2"
43
- menu.choice "Sample3"
40
+
41
+ menu.choice "Sample1"
42
+ menu.choice "Sample2"
43
+ menu.choice "Sample3"
44
44
  end
45
45
  assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n? ", @output.string)
46
46
 
47
47
  @output.truncate(@output.rewind)
48
48
  @input.rewind
49
-
49
+
50
50
  @terminal.choose do |menu|
51
51
  menu.flow = :columns_across
52
-
53
- menu.choice "Sample1"
54
- menu.choice "Sample2"
52
+
53
+ menu.choice "Sample1"
54
+ menu.choice "Sample2"
55
55
  menu.choice "Sample3"
56
56
  end
57
57
  assert_equal("1. Sample1 2. Sample2 3. Sample3\n? ", @output.string)
@@ -63,13 +63,13 @@ class TestMenu < Minitest::Test
63
63
  menu.flow = :inline
64
64
  menu.index = :none
65
65
 
66
- menu.choice "Sample1"
67
- menu.choice "Sample2"
68
- menu.choice "Sample3"
66
+ menu.choice "Sample1"
67
+ menu.choice "Sample2"
68
+ menu.choice "Sample3"
69
69
  end
70
70
  assert_equal("Sample1, Sample2 or Sample3? ", @output.string)
71
71
  end
72
-
72
+
73
73
  def test_unicode_flow
74
74
  @input << "1\n"
75
75
  @input.rewind
@@ -81,6 +81,76 @@ class TestMenu < Minitest::Test
81
81
  assert_equal("1. Unicode right single quotation mark: ’\n? ".encode(@output.external_encoding, { :undef => :replace }), @output.string)
82
82
  end
83
83
 
84
+ def test_text_override_index_selects_name
85
+ @input << "1\n"
86
+ @input.rewind
87
+
88
+ selected = @terminal.choose do |menu|
89
+ menu.choice("Sample1", nil, "Sample2")
90
+ menu.choice("Sample2", nil, "Sample1")
91
+ end
92
+ assert_equal(selected, "Sample1")
93
+ assert_equal("1. Sample2\n" +
94
+ "2. Sample1\n" +
95
+ "? ", @output.string)
96
+ end
97
+
98
+ def test_text_override_selections_matches_name
99
+ @input << "Sample2\n"
100
+ @input.rewind
101
+
102
+ selected = @terminal.choose do |menu|
103
+ menu.choice("Sample1", nil, "Sample2")
104
+ menu.choice("Sample2", nil, "Sample1")
105
+ end
106
+ assert_equal(selected, "Sample2")
107
+ assert_equal("1. Sample2\n" +
108
+ "2. Sample1\n" +
109
+ "? ", @output.string)
110
+ end
111
+
112
+ def test_menu_add_item_index_selects_name
113
+ @input << "1\n"
114
+ @input.rewind
115
+
116
+ selected = @terminal.choose do |menu|
117
+ menu.add_item(HighLine::Menu::MenuItem.new("Sample1", text: "Sample2"))
118
+ menu.add_item(HighLine::Menu::MenuItem.new("Sample2", text: "Sample1"))
119
+ end
120
+ assert_equal(selected, "Sample1")
121
+ assert_equal("1. Sample2\n" +
122
+ "2. Sample1\n" +
123
+ "? ", @output.string)
124
+ end
125
+
126
+ def test_menu_add_item_selections_matches_name
127
+ @input << "Sample2\n"
128
+ @input.rewind
129
+
130
+ selected = @terminal.choose do |menu|
131
+ menu.add_item(HighLine::Menu::MenuItem.new("Sample1", text: "Sample2"))
132
+ menu.add_item(HighLine::Menu::MenuItem.new("Sample2", text: "Sample1"))
133
+ end
134
+ assert_equal(selected, "Sample2")
135
+ assert_equal("1. Sample2\n" +
136
+ "2. Sample1\n" +
137
+ "? ", @output.string)
138
+ end
139
+
140
+ def test_menu_build_item
141
+ @input << "Sample2\n"
142
+ @input.rewind
143
+
144
+ selected = @terminal.choose do |menu|
145
+ menu.add_item(menu.build_item("Sample1", text: "Sample2"))
146
+ menu.add_item(menu.build_item("Sample2", text: "Sample1"))
147
+ end
148
+ assert_equal(selected, "Sample2")
149
+ assert_equal("1. Sample2\n" +
150
+ "2. Sample1\n" +
151
+ "? ", @output.string)
152
+ end
153
+
84
154
  def test_help
85
155
  @input << "help\nhelp load\nhelp rules\nhelp missing\n"
86
156
  @input.rewind
@@ -92,7 +162,7 @@ class TestMenu < Minitest::Test
92
162
  menu.choice(:load, "Load a file.")
93
163
  menu.choice(:save, "Save data in file.")
94
164
  menu.choice(:quit, "Exit program.")
95
-
165
+
96
166
  menu.help("rules", "The rules of this system are as follows...")
97
167
  end
98
168
  end
@@ -102,15 +172,15 @@ class TestMenu < Minitest::Test
102
172
  "specific topic enter:\n" +
103
173
  "\thelp [TOPIC]\n" +
104
174
  "Try asking for help on any of the following:\n" +
105
- "\nload quit rules save \n" +
175
+ "\nload quit rules save \n" +
106
176
  "1. load\n2. save\n3. quit\n4. help\n? " +
107
- "= load\n\n" +
177
+ "= load\n\n" +
108
178
  "Load a file.\n" +
109
179
  "1. load\n2. save\n3. quit\n4. help\n? " +
110
180
  "= rules\n\n" +
111
181
  "The rules of this system are as follows...\n" +
112
182
  "1. load\n2. save\n3. quit\n4. help\n? " +
113
- "= missing\n\n" +
183
+ "= missing\n\n" +
114
184
  "There's no help for that topic.\n", @output.string )
115
185
  end
116
186
 
@@ -120,22 +190,22 @@ class TestMenu < Minitest::Test
120
190
 
121
191
  @terminal.choose do |menu|
122
192
  # Default: menu.index = :number
123
-
124
- menu.choice "Sample1"
125
- menu.choice "Sample2"
126
- menu.choice "Sample3"
193
+
194
+ menu.choice "Sample1"
195
+ menu.choice "Sample2"
196
+ menu.choice "Sample3"
127
197
  end
128
198
  assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n? ", @output.string)
129
199
 
130
200
  @output.truncate(@output.rewind)
131
201
  @input.rewind
132
-
202
+
133
203
  @terminal.choose do |menu|
134
204
  menu.index = :letter
135
205
  menu.index_suffix = ") "
136
-
137
- menu.choice "Sample1"
138
- menu.choice "Sample2"
206
+
207
+ menu.choice "Sample1"
208
+ menu.choice "Sample2"
139
209
  menu.choice "Sample3"
140
210
  end
141
211
  assert_equal("a) Sample1\nb) Sample2\nc) Sample3\n? ", @output.string)
@@ -146,15 +216,15 @@ class TestMenu < Minitest::Test
146
216
  @terminal.choose do |menu|
147
217
  menu.index = :none
148
218
 
149
- menu.choice "Sample1"
150
- menu.choice "Sample2"
151
- menu.choice "Sample3"
219
+ menu.choice "Sample1"
220
+ menu.choice "Sample2"
221
+ menu.choice "Sample3"
152
222
  end
153
223
  assert_equal("Sample1\nSample2\nSample3\n? ", @output.string)
154
224
 
155
225
  @output.truncate(@output.rewind)
156
226
  @input.rewind
157
-
227
+
158
228
  @terminal.choose do |menu|
159
229
  menu.index = "*"
160
230
 
@@ -164,11 +234,11 @@ class TestMenu < Minitest::Test
164
234
  end
165
235
  assert_equal("* Sample1\n* Sample2\n* Sample3\n? ", @output.string)
166
236
  end
167
-
237
+
168
238
  def test_layouts
169
239
  @input << "save\n"
170
240
  @input.rewind
171
-
241
+
172
242
  @terminal.choose(:load, :save, :quit) # Default: layout = :list
173
243
  assert_equal("1. load\n2. save\n3. quit\n? ", @output.string)
174
244
 
@@ -178,7 +248,7 @@ class TestMenu < Minitest::Test
178
248
  @terminal.choose(:load, :save, :quit) do |menu|
179
249
  menu.header = "File Menu"
180
250
  end
181
- assert_equal( "File Menu:\n" +
251
+ assert_equal( "File Menu:\n" +
182
252
  "1. load\n2. save\n3. quit\n? ", @output.string )
183
253
 
184
254
  @input.rewind
@@ -189,7 +259,7 @@ class TestMenu < Minitest::Test
189
259
  menu.header = "File Menu"
190
260
  menu.prompt = "Operation? "
191
261
  end
192
- assert_equal( "File Menu: Operation? " +
262
+ assert_equal( "File Menu: Operation? " +
193
263
  "(load, save or quit) ", @output.string )
194
264
 
195
265
  @input.rewind
@@ -208,7 +278,7 @@ class TestMenu < Minitest::Test
208
278
  end
209
279
  assert_equal("1. load\n2. save\n3. quit\nFile Menu: ", @output.string)
210
280
  end
211
-
281
+
212
282
  def test_list_option
213
283
  @input << "l\n"
214
284
  @input.rewind
@@ -252,18 +322,18 @@ class TestMenu < Minitest::Test
252
322
  end
253
323
  assert_equal("Sample2", output)
254
324
  end
255
-
325
+
256
326
  def test_passed_command
257
327
  @input << "q\n"
258
328
  @input.rewind
259
-
329
+
260
330
  selected = nil
261
331
  @terminal.choose do |menu|
262
332
  menu.choices(:load, :save, :quit) { |command| selected = command }
263
333
  end
264
334
  assert_equal(:quit, selected)
265
335
  end
266
-
336
+
267
337
  def test_question_options
268
338
  @input << "save\n"
269
339
  @input.rewind
@@ -286,19 +356,19 @@ class TestMenu < Minitest::Test
286
356
  def test_select_by
287
357
  @input << "Sample1\n2\n"
288
358
  @input.rewind
289
-
359
+
290
360
  selected = @terminal.choose do |menu|
291
361
  menu.choice "Sample1"
292
362
  menu.choice "Sample2"
293
363
  menu.choice "Sample3"
294
364
  end
295
365
  assert_equal("Sample1", selected)
296
-
366
+
297
367
  @input.rewind
298
368
 
299
369
  selected = @terminal.choose do |menu|
300
370
  menu.select_by = :index
301
-
371
+
302
372
  menu.choice "Sample1"
303
373
  menu.choice "Sample2"
304
374
  menu.choice "Sample3"
@@ -309,7 +379,7 @@ class TestMenu < Minitest::Test
309
379
 
310
380
  selected = @terminal.choose do |menu|
311
381
  menu.select_by = :name
312
-
382
+
313
383
  menu.choice "Sample1"
314
384
  menu.choice "Sample2"
315
385
  menu.choice "Sample3"
@@ -320,7 +390,7 @@ class TestMenu < Minitest::Test
320
390
  def test_hidden
321
391
  @input << "Hidden\n4\n"
322
392
  @input.rewind
323
-
393
+
324
394
  selected = @terminal.choose do |menu|
325
395
  menu.choice "Sample1"
326
396
  menu.choice "Sample2"
@@ -329,12 +399,12 @@ class TestMenu < Minitest::Test
329
399
  end
330
400
  assert_equal("Hidden!", selected)
331
401
  assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n? ", @output.string)
332
-
402
+
333
403
  @input.rewind
334
404
 
335
405
  selected = @terminal.choose do |menu|
336
406
  menu.select_by = :index
337
-
407
+
338
408
  menu.choice "Sample1"
339
409
  menu.choice "Sample2"
340
410
  menu.choice "Sample3"
@@ -346,7 +416,7 @@ class TestMenu < Minitest::Test
346
416
 
347
417
  selected = @terminal.choose do |menu|
348
418
  menu.select_by = :name
349
-
419
+
350
420
  menu.choice "Sample1"
351
421
  menu.choice "Sample2"
352
422
  menu.choice "Sample3"
@@ -360,8 +430,8 @@ class TestMenu < Minitest::Test
360
430
  def test_select_by_letter
361
431
  @input << "b\n"
362
432
  @input.rewind
363
-
364
- selected = @terminal.choose do |menu|
433
+
434
+ selected = @terminal.choose do |menu|
365
435
  menu.index = :letter
366
436
  menu.choice :save
367
437
  menu.choice :load
@@ -369,7 +439,7 @@ class TestMenu < Minitest::Test
369
439
  end
370
440
  assert_equal(:load, selected)
371
441
  end
372
-
442
+
373
443
  def test_shell
374
444
  @input << "save --some-option my_file.txt\n"
375
445
  @input.rewind
@@ -381,7 +451,7 @@ class TestMenu < Minitest::Test
381
451
  menu.choice(:save) do |command, details|
382
452
  selected = command
383
453
  options = details
384
-
454
+
385
455
  "Saved!"
386
456
  end
387
457
  menu.shell = true
@@ -402,9 +472,9 @@ class TestMenu < Minitest::Test
402
472
  def test_symbols
403
473
  @input << "3\n"
404
474
  @input.rewind
405
-
475
+
406
476
  selected = @terminal.choose do |menu|
407
- menu.choices(:save, :load, :quit)
477
+ menu.choices(:save, :load, :quit)
408
478
  end
409
479
  assert_equal(:quit, selected)
410
480
  end
@@ -414,13 +484,12 @@ class TestMenu < Minitest::Test
414
484
  # Will page twice, so start with two new lines
415
485
  @input << "\n\n3\n"
416
486
  @input.rewind
417
-
418
- # Sadly this goes into an infinite loop without the fix to page_print
419
- selected = @terminal.choose(* 1..10)
487
+
488
+ # Sadly this goes into an infinite loop without the fix to page_print
489
+ selected = @terminal.choose(* 1..10)
420
490
  assert_equal(selected, 3)
421
491
  end
422
492
 
423
-
424
493
  def test_cancel_paging
425
494
  # Tests that paging can be cancelled halfway through
426
495
  @terminal.page_at = 5
@@ -434,9 +503,152 @@ class TestMenu < Minitest::Test
434
503
  # Make sure paging message appeared
435
504
  assert( @output.string.index('press enter/return to continue or q to stop'),
436
505
  "Paging message did not appear." )
437
-
506
+
438
507
  # Make sure it only appeared once
439
508
  assert( @output.string !~ /q to stop.*q to stop/m,
440
509
  "Paging message appeared more than once." )
441
510
  end
511
+
512
+ def test_autocomplete_prompt
513
+ @input << "lisp\nRuby\n"
514
+ @input.rewind
515
+
516
+ answer = @terminal.choose do |menu|
517
+ menu.choice(:Perl)
518
+ menu.choice(:Python)
519
+ menu.choice(:Ruby)
520
+ menu.prompt = "What is your favorite programming language? "
521
+ end
522
+ languages = [:Perl, :Python, :Ruby]
523
+ assert_equal("1. Perl\n" +
524
+ "2. Python\n" +
525
+ "3. Ruby\n" +
526
+ "What is your favorite programming language? " +
527
+ "You must choose one of [1, 2, 3, Perl, Python, Ruby].\n" +
528
+ "? ", @output.string )
529
+ end
530
+
531
+ # Issue #180 - https://github.com/JEG2/highline/issues/180
532
+ def test_menu_prompt
533
+ @input << "2\n1\n"
534
+ @input.rewind
535
+
536
+ selected = @terminal.choose do |menu|
537
+ menu.responses[:ask_on_error] = "> "
538
+ menu.prompt = "> "
539
+ menu.choice :exit, "Exit cube editor"
540
+ end
541
+
542
+ prompt = "> "
543
+ first_asking = "1. exit\n"
544
+ error_message = "You must choose one of [1, exit].\n"
545
+ complete_interaction = first_asking + prompt + error_message + prompt # Same prompt when repeating question
546
+
547
+ assert_equal complete_interaction, @output.string
548
+ end
549
+
550
+ def test_menu_gather_integer
551
+ @input << "Sample1\nlast\n"
552
+ @input.rewind
553
+
554
+ selected = @terminal.choose do |menu|
555
+ menu.gather = 2
556
+ menu.choice "Sample1"
557
+ menu.choice "Sample2"
558
+ menu.choice "last"
559
+ end
560
+ assert_equal(["Sample1", "last"], selected)
561
+
562
+ assert_equal("1. Sample1\n" +
563
+ "2. Sample2\n" +
564
+ "3. last\n" +
565
+ "? 1. Sample1\n" +
566
+ "2. Sample2\n" +
567
+ "3. last\n" +
568
+ "? ", @output.string)
569
+ end
570
+
571
+ def test_menu_gather_string
572
+ @input << "Sample1\nlast\n"
573
+ @input.rewind
574
+
575
+ selected = @terminal.choose do |menu|
576
+ menu.gather = :last
577
+ menu.choice "Sample1"
578
+ menu.choice "Sample2"
579
+ menu.choice :last
580
+ end
581
+ assert_equal(["Sample1"], selected)
582
+
583
+ assert_equal("1. Sample1\n" +
584
+ "2. Sample2\n" +
585
+ "3. last\n" +
586
+ "? 1. Sample1\n" +
587
+ "2. Sample2\n" +
588
+ "3. last\n" +
589
+ "? ", @output.string)
590
+ end
591
+
592
+ def test_menu_gather_symbol
593
+ @input << "Sample1\nlast\n"
594
+ @input.rewind
595
+
596
+ selected = @terminal.choose do |menu|
597
+ menu.gather = "last"
598
+ menu.choice "Sample1"
599
+ menu.choice "Sample2"
600
+ menu.choice "last"
601
+ end
602
+ assert_equal(["Sample1"], selected)
603
+
604
+ assert_equal("1. Sample1\n" +
605
+ "2. Sample2\n" +
606
+ "3. last\n" +
607
+ "? 1. Sample1\n" +
608
+ "2. Sample2\n" +
609
+ "3. last\n" +
610
+ "? ", @output.string)
611
+ end
612
+
613
+ def test_menu_gather_regexp
614
+ @input << "Sample1\nlast\n"
615
+ @input.rewind
616
+
617
+ selected = @terminal.choose do |menu|
618
+ menu.gather = /la/
619
+ menu.choice "Sample1"
620
+ menu.choice "Sample2"
621
+ menu.choice "last"
622
+ end
623
+ assert_equal(["Sample1"], selected)
624
+
625
+ assert_equal("1. Sample1\n" +
626
+ "2. Sample2\n" +
627
+ "3. last\n" +
628
+ "? 1. Sample1\n" +
629
+ "2. Sample2\n" +
630
+ "3. last\n" +
631
+ "? ", @output.string)
632
+ end
633
+
634
+ def test_menu_gather_hash
635
+ @input << "Sample1\n3\n"
636
+ @input.rewind
637
+
638
+ selected = @terminal.choose do |menu|
639
+ menu.gather = { "First" => true, second: true }
640
+ menu.choice "Sample1"
641
+ menu.choice "Sample2"
642
+ menu.choice "last"
643
+ end
644
+ assert_equal({ "First" => "Sample1", second: "last" }, selected)
645
+
646
+ assert_equal("1. Sample1\n" +
647
+ "2. Sample2\n" +
648
+ "3. last\n" +
649
+ "? 1. Sample1\n" +
650
+ "2. Sample2\n" +
651
+ "3. last\n" +
652
+ "? ", @output.string)
653
+ end
442
654
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: highline
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre.develop.4
4
+ version: 2.0.0.pre.develop.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Edward Gray II
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-14 00:00:00.000000000 Z
11
+ date: 2016-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: code_statistics