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 +4 -4
- data/.gitignore +1 -0
- data/Changelog.md +10 -0
- data/README.md +2 -2
- data/lib/highline.rb +10 -3
- data/lib/highline/menu.rb +147 -57
- data/lib/highline/question.rb +24 -12
- data/lib/highline/question_asker.rb +9 -8
- data/lib/highline/version.rb +1 -1
- data/test/test_menu.rb +267 -55
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13e2a946fd059cbf2c25bff77dc7e70b299fccab
|
4
|
+
data.tar.gz: c35a2236e1ce0d83cac30b9e2464abf4f61fc421
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dadda880956f0ecb41ffca76a81cb89cd26fc63e3dea10f54bc7753d7af95e7f04a7185b0a1caab7a2b0ea31cc0cb932fb25971094252925af9cd52759176a4f
|
7
|
+
data.tar.gz: 54aa4ee03370b217bb9dacb8e94ba129f70cab24513297fe24f863a99b635ba45992091d5dea60c08ee94f5d77138329d9385f6ff01808336bdf8ac1d859d219
|
data/.gitignore
CHANGED
data/Changelog.md
CHANGED
@@ -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
|
|
data/lib/highline.rb
CHANGED
@@ -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
|
-
|
257
|
+
selection, details = selected
|
257
258
|
else
|
258
|
-
|
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.
|
495
|
+
say(question.final_responses[error]) if error
|
489
496
|
say(question.ask_on_error_msg)
|
490
497
|
end
|
491
498
|
|
data/lib/highline/menu.rb
CHANGED
@@ -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
|
-
|
166
|
-
|
167
|
-
@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
|
-
|
193
|
-
|
194
|
-
@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
|
-
|
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
|
-
|
338
|
+
map_items_by_index(items, @index)
|
318
339
|
when :name
|
319
|
-
|
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
|
-
|
351
|
+
(1 .. items.size).map(&:to_s)
|
322
352
|
end
|
323
|
-
|
324
|
-
|
325
|
-
|
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
|
-
|
371
|
+
items = all_items
|
341
372
|
|
342
373
|
# Find the selected action.
|
343
|
-
|
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
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
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
|
-
|
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
|
-
|
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 =
|
377
|
-
|
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 { |
|
458
|
+
@items.map { |i| "#{@items.index(i) + 1}#{@index_suffix}#{i.text}" }
|
389
459
|
when :letter
|
390
460
|
l_index = "`"
|
391
|
-
@items.map { |
|
461
|
+
@items.map { |i| "#{l_index.succ!}#{@index_suffix}#{i.text}" }
|
392
462
|
when :none
|
393
|
-
@items.map { |
|
463
|
+
@items.map { |i| "#{i.text}" }
|
394
464
|
else
|
395
|
-
@items.map { |
|
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
|
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
|
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
|
data/lib/highline/question.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
|
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
|
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
|
-
|
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
|
546
|
+
if final_responses[:ask_on_error] == :question
|
535
547
|
self
|
536
|
-
elsif
|
537
|
-
|
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
|
-
|
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.
|
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
|
-
|
137
|
-
|
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
|
data/lib/highline/version.rb
CHANGED
data/test/test_menu.rb
CHANGED
@@ -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
|
+
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:
|
11
|
+
date: 2016-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: code_statistics
|