highline 0.6.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +17 -0
- data/LICENSE +2 -2
- data/Rakefile +11 -1
- data/TODO +1 -7
- data/examples/asking_for_arrays.rb +18 -0
- data/examples/menus.rb +3 -3
- data/examples/using_readline.rb +17 -0
- data/lib/highline.rb +95 -7
- data/lib/highline/menu.rb +49 -7
- data/lib/highline/question.rb +85 -6
- data/test/tc_highline.rb +62 -3
- data/test/tc_import.rb +0 -3
- data/test/tc_menu.rb +34 -4
- data/test/ts_all.rb +0 -3
- metadata +4 -2
data/CHANGELOG
CHANGED
@@ -2,6 +2,23 @@
|
|
2
2
|
|
3
3
|
Below is a complete listing of changes for each revision of HighLine.
|
4
4
|
|
5
|
+
== 1.0.0
|
6
|
+
|
7
|
+
* Fixed documentation typo pointed out by Gavin Kistner.
|
8
|
+
* Added <tt>gather = ...</tt> option to question for fetching entire Arrays or
|
9
|
+
Hashes filled with answers. You can set +gather+ to a count of answers to
|
10
|
+
collect, a String or Regexp matching the end of input, or a Hash where each
|
11
|
+
key can be used in a new question.
|
12
|
+
* Added File support to HighLine.ask(). You can specify a _directory_ and a
|
13
|
+
_glob_ pattern that combine into a list of file choices the user can select
|
14
|
+
from. You can choose to receive the user's answer as an open filehandle or as
|
15
|
+
a Pathname object.
|
16
|
+
* Added Readline support for history and editing.
|
17
|
+
* Added tab completion for menu and file selection selection (requires
|
18
|
+
Readline).
|
19
|
+
* Added an optional character limit for input.
|
20
|
+
* Added a complete help system to HighLine's shell menu creation tools.
|
21
|
+
|
5
22
|
== 0.6.1
|
6
23
|
|
7
24
|
* Removed termios dependancy in gem, to fix Windows' install.
|
data/LICENSE
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
= License Terms
|
2
2
|
|
3
|
-
Distributed under the
|
3
|
+
Distributed under the user's choice of the GPL[http://www.gnu.org/copyleft/gpl.html] (see COPYING for details) or the
|
4
4
|
{Ruby software license}[http://www.ruby-lang.org/en/LICENSE.txt] by
|
5
|
-
James Edward Gray II.
|
5
|
+
James Edward Gray II and Greg Brown.
|
6
6
|
|
7
7
|
Please email James[mailto:james@grayproductions.net] with any questions.
|
data/Rakefile
CHANGED
@@ -16,11 +16,13 @@ Rake::RDocTask.new do |rdoc|
|
|
16
16
|
rdoc.main = "README"
|
17
17
|
rdoc.rdoc_files.include( "README", "INSTALL",
|
18
18
|
"TODO", "CHANGELOG",
|
19
|
+
"AUTHORS", "COPYING",
|
19
20
|
"LICENSE", "lib/" )
|
20
21
|
rdoc.rdoc_dir = "doc/html"
|
21
22
|
rdoc.title = "HighLine Documentation"
|
22
23
|
end
|
23
24
|
|
25
|
+
desc "Upload current documentation to Rubyforge"
|
24
26
|
task :upload_docs => [:rdoc] do
|
25
27
|
sh "scp -r site/* " +
|
26
28
|
"bbazzarrakk@rubyforge.org:/var/www/gforge-projects/highline/"
|
@@ -30,7 +32,7 @@ end
|
|
30
32
|
|
31
33
|
spec = Gem::Specification.new do |spec|
|
32
34
|
spec.name = "highline"
|
33
|
-
spec.version = "0.
|
35
|
+
spec.version = "1.0.0"
|
34
36
|
spec.platform = Gem::Platform::RUBY
|
35
37
|
spec.summary = "HighLine is a high-level line oriented console interface."
|
36
38
|
spec.files = Dir.glob("{examples,lib,test}/**/*.rb").
|
@@ -62,3 +64,11 @@ Rake::GemPackageTask.new(spec) do |pkg|
|
|
62
64
|
pkg.need_zip = true
|
63
65
|
pkg.need_tar = true
|
64
66
|
end
|
67
|
+
|
68
|
+
desc "Show library's code statistics"
|
69
|
+
task :stats do
|
70
|
+
require 'code_statistics'
|
71
|
+
CodeStatistics.new( ["HighLine", "lib"],
|
72
|
+
["Functionals", "examples"],
|
73
|
+
["Units", "test"] ).to_s
|
74
|
+
end
|
data/TODO
CHANGED
@@ -3,10 +3,4 @@
|
|
3
3
|
The following is a list of planned expansions for HighLine, in no particular
|
4
4
|
order.
|
5
5
|
|
6
|
-
*
|
7
|
-
<tt>ask(..., lambda { |arr| arr.split(",") })</tt> or similar.
|
8
|
-
* Support <tt>ask(..., Hash)</tt>.
|
9
|
-
* Support <tt>ask(..., File)</tt>.
|
10
|
-
* Add readline support for history and editing.
|
11
|
-
* Add an easy-access help system for menus.
|
12
|
-
* Add tab completion for menu selection.
|
6
|
+
* This space for rent...
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# asking_for_arrays.rb
|
4
|
+
#
|
5
|
+
# Created by James Edward Gray II on 2005-07-05.
|
6
|
+
# Copyright 2005 Gray Productions. All rights reserved.
|
7
|
+
|
8
|
+
require "rubygems"
|
9
|
+
require "highline/import"
|
10
|
+
require "pp"
|
11
|
+
|
12
|
+
grades = ask( "Enter test scores (or a blank line to quit):",
|
13
|
+
lambda { |ans| ans =~ /^-?\d+$/ ? Integer(ans) : ans} ) do |q|
|
14
|
+
q.gather = ""
|
15
|
+
end
|
16
|
+
|
17
|
+
say("Grades:")
|
18
|
+
pp grades
|
data/examples/menus.rb
CHANGED
@@ -55,12 +55,12 @@ loop do
|
|
55
55
|
menu.shell = true
|
56
56
|
menu.case = :capitalize
|
57
57
|
|
58
|
-
menu.choice
|
58
|
+
menu.choice(:Load, "Load a file.") do |command, details|
|
59
59
|
say("Loading file with options: #{details}...")
|
60
60
|
end
|
61
|
-
menu.choice
|
61
|
+
menu.choice(:Save, "Save a file.") do |command, details|
|
62
62
|
say("Saving file with options: #{details}...")
|
63
63
|
end
|
64
|
-
menu.choice(:Quit) { exit }
|
64
|
+
menu.choice(:Quit, "Exit program.") { exit }
|
65
65
|
end
|
66
66
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# using_readline.rb
|
4
|
+
#
|
5
|
+
# Created by James Edward Gray II on 2005-07-06.
|
6
|
+
# Copyright 2005 Gray Productions. All rights reserved.
|
7
|
+
|
8
|
+
require "rubygems"
|
9
|
+
require "highline/import"
|
10
|
+
|
11
|
+
loop do
|
12
|
+
cmd = ask("Enter command: ", %w{save load reset quit}) do |q|
|
13
|
+
q.readline = true
|
14
|
+
end
|
15
|
+
say("Executing \"#{cmd}\"...")
|
16
|
+
break if cmd == "quit"
|
17
|
+
end
|
data/lib/highline.rb
CHANGED
@@ -11,13 +11,15 @@ require "highline/question"
|
|
11
11
|
require "highline/menu"
|
12
12
|
require "erb"
|
13
13
|
require "optparse"
|
14
|
+
require "stringio"
|
15
|
+
require "abbrev"
|
14
16
|
|
15
17
|
#
|
16
18
|
# A HighLine object is a "high-level line oriented" shell over an input and an
|
17
19
|
# output stream. HighLine simplifies common console interaction, effectively
|
18
20
|
# replacing puts() and gets(). User code can simply specify the question to ask
|
19
21
|
# and any details about user interaction, then leave the rest of the work to
|
20
|
-
# HighLine. When HighLine.ask() returns, you'll have
|
22
|
+
# HighLine. When HighLine.ask() returns, you'll have the answer you requested,
|
21
23
|
# even if HighLine had to ask many times, validate results, perform range
|
22
24
|
# checking, convert types, etc.
|
23
25
|
#
|
@@ -93,6 +95,15 @@ class HighLine
|
|
93
95
|
@output = output
|
94
96
|
@wrap_at = wrap_at
|
95
97
|
@page_at = page_at
|
98
|
+
|
99
|
+
@question = nil
|
100
|
+
@answer = nil
|
101
|
+
@menu = nil
|
102
|
+
@header = nil
|
103
|
+
@prompt = nil
|
104
|
+
@gather = nil
|
105
|
+
@answers = nil
|
106
|
+
@key = nil
|
96
107
|
end
|
97
108
|
|
98
109
|
#
|
@@ -136,7 +147,10 @@ class HighLine
|
|
136
147
|
def ask(question, answer_type = String, &details) # :yields: question
|
137
148
|
@question ||= Question.new(question, answer_type, &details)
|
138
149
|
|
139
|
-
|
150
|
+
return gather if @question.gather
|
151
|
+
|
152
|
+
# readline() needs to handle it's own output
|
153
|
+
say(@question) unless @question.readline
|
140
154
|
begin
|
141
155
|
@answer = @question.answer_or_default(get_response)
|
142
156
|
unless @question.valid_answer?(@answer)
|
@@ -230,10 +244,10 @@ class HighLine
|
|
230
244
|
|
231
245
|
if @menu.shell
|
232
246
|
selected = ask("Ignored", @menu.answer_type)
|
233
|
-
@menu.select(*selected)
|
247
|
+
@menu.select(self, *selected)
|
234
248
|
else
|
235
249
|
selected = ask("Ignored", @menu.answer_type)
|
236
|
-
@menu.select(selected)
|
250
|
+
@menu.select(self, selected)
|
237
251
|
end
|
238
252
|
end
|
239
253
|
|
@@ -376,6 +390,51 @@ class HighLine
|
|
376
390
|
end
|
377
391
|
end
|
378
392
|
|
393
|
+
#
|
394
|
+
# Collects an Array/Hash full of answers as described in
|
395
|
+
# HighLine::Question.gather().
|
396
|
+
#
|
397
|
+
def gather( )
|
398
|
+
@gather = @question.gather
|
399
|
+
@answers = [ ]
|
400
|
+
original_question = @question
|
401
|
+
|
402
|
+
@question.gather = false
|
403
|
+
|
404
|
+
case @gather
|
405
|
+
when Integer
|
406
|
+
@answers << ask(@question)
|
407
|
+
@gather -= 1
|
408
|
+
|
409
|
+
original_question.question = ""
|
410
|
+
until @gather.zero?
|
411
|
+
@question = original_question
|
412
|
+
@answers << ask(@question)
|
413
|
+
@gather -= 1
|
414
|
+
end
|
415
|
+
when String, Regexp
|
416
|
+
@answers << ask(@question)
|
417
|
+
|
418
|
+
original_question.question = ""
|
419
|
+
until (@gather.is_a?(String) and @answers.last.to_s == @gather) or
|
420
|
+
(@gather.is_a?(Regexp) and @answers.last.to_s =~ @gather)
|
421
|
+
@question = original_question
|
422
|
+
@answers << ask(@question)
|
423
|
+
end
|
424
|
+
|
425
|
+
@answers.pop
|
426
|
+
when Hash
|
427
|
+
@answers = { }
|
428
|
+
@gather.keys.sort.each do |key|
|
429
|
+
@question = original_question
|
430
|
+
@key = key
|
431
|
+
@answers[key] = ask(@question)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
@answers
|
436
|
+
end
|
437
|
+
|
379
438
|
#
|
380
439
|
# This section builds a character reading function to suit the proper
|
381
440
|
# platform we're running on. Be warned: Here be dragons!
|
@@ -442,9 +501,37 @@ class HighLine
|
|
442
501
|
#
|
443
502
|
# Read a line of input from the input stream and process whitespace as
|
444
503
|
# requested by the Question object.
|
504
|
+
#
|
505
|
+
# If Question's _readline_ property is set, that library will be used to
|
506
|
+
# fetch input. *WARNING*: This ignores the currently set input stream.
|
445
507
|
#
|
446
508
|
def get_line( )
|
447
|
-
@question.
|
509
|
+
if @question.readline
|
510
|
+
require "readline" # load only if needed
|
511
|
+
|
512
|
+
# capture say()'s work in a String to feed to readline()
|
513
|
+
old_output = @output
|
514
|
+
@output = StringIO.new
|
515
|
+
say(@question)
|
516
|
+
question = @output.string
|
517
|
+
@output = old_output
|
518
|
+
|
519
|
+
# prep auto-completion
|
520
|
+
completions = @question.selection.abbrev
|
521
|
+
Readline.completion_proc = lambda { |string| completions[string] }
|
522
|
+
|
523
|
+
# work-around ugly readline() warnings
|
524
|
+
old_verbose = $VERBOSE
|
525
|
+
$VERBOSE = nil
|
526
|
+
answer = @question.change_case(
|
527
|
+
@question.remove_whitespace(
|
528
|
+
Readline.readline(question, true) ) )
|
529
|
+
$VERBOSE = old_verbose
|
530
|
+
|
531
|
+
answer
|
532
|
+
else
|
533
|
+
@question.change_case(@question.remove_whitespace(@input.gets))
|
534
|
+
end
|
448
535
|
end
|
449
536
|
|
450
537
|
#
|
@@ -454,7 +541,7 @@ class HighLine
|
|
454
541
|
#
|
455
542
|
def get_response( )
|
456
543
|
if @question.character.nil?
|
457
|
-
if @question.echo == true
|
544
|
+
if @question.echo == true and @question.limit.nil?
|
458
545
|
get_line
|
459
546
|
else
|
460
547
|
line = ""
|
@@ -462,7 +549,8 @@ class HighLine
|
|
462
549
|
line << character.chr
|
463
550
|
# looking for carriage return (decimal 13) or
|
464
551
|
# newline (decimal 10) in raw input
|
465
|
-
break if character == 13 or character == 10
|
552
|
+
break if character == 13 or character == 10 or
|
553
|
+
(@question.limit and line.size == @question.limit)
|
466
554
|
@output.print(@question.echo) if @question.echo != false
|
467
555
|
end
|
468
556
|
say("\n")
|
data/lib/highline/menu.rb
CHANGED
@@ -23,12 +23,13 @@ class HighLine
|
|
23
23
|
#
|
24
24
|
def initialize( )
|
25
25
|
#
|
26
|
-
# Initialize Question objects with ignored
|
26
|
+
# Initialize Question objects with ignored values, we'll
|
27
27
|
# adjust ours as needed.
|
28
28
|
#
|
29
|
-
super("Ignored", [ ], &nil) # avoiding passing
|
29
|
+
super("Ignored", [ ], &nil) # avoiding passing the block along
|
30
30
|
|
31
31
|
@items = [ ]
|
32
|
+
@help = Hash.new("There's no help for that topic.")
|
32
33
|
|
33
34
|
@index = :number
|
34
35
|
@index_suffix = ". "
|
@@ -41,12 +42,15 @@ class HighLine
|
|
41
42
|
@shell = false
|
42
43
|
@nil_on_handled = false
|
43
44
|
|
44
|
-
# Override Questions
|
45
|
+
# Override Questions responses, we'll set our own.
|
45
46
|
@responses = { }
|
47
|
+
# Context for action code.
|
48
|
+
@highline = nil
|
46
49
|
|
47
50
|
yield self if block_given?
|
48
51
|
|
49
52
|
update_responses # rebuild responses based on our settings
|
53
|
+
init_help if @shell and not @help.empty?
|
50
54
|
end
|
51
55
|
|
52
56
|
#
|
@@ -125,10 +129,14 @@ class HighLine
|
|
125
129
|
# will be returned, unless _nil_on_handled_ is set (when you would get
|
126
130
|
# +nil+ instead). In _shell_ mode, a provided block will be passed the
|
127
131
|
# command chosen and any details that followed the command. Otherwise,
|
128
|
-
# just the command is passed.
|
132
|
+
# just the command is passed. The <tt>@highline</tt> variable is set to
|
133
|
+
# the current HighLine context before the action code is called and can
|
134
|
+
# thus be used for adding output and the like.
|
129
135
|
#
|
130
|
-
def choice( name, &action )
|
136
|
+
def choice( name, help = nil, &action )
|
131
137
|
@items << [name, action]
|
138
|
+
|
139
|
+
@help[name.to_s.downcase] = help unless help.nil?
|
132
140
|
end
|
133
141
|
|
134
142
|
#
|
@@ -166,6 +174,39 @@ class HighLine
|
|
166
174
|
end
|
167
175
|
end
|
168
176
|
|
177
|
+
#
|
178
|
+
# Initializes the help system by adding a <tt>:help</tt> choice, some
|
179
|
+
# action code, and the default help listing.
|
180
|
+
#
|
181
|
+
def init_help( )
|
182
|
+
return if @items.include?(:help)
|
183
|
+
|
184
|
+
topics = @help.keys.sort
|
185
|
+
help_help = @help.include?("help") ? @help["help"] :
|
186
|
+
"This command will display helpful messages about " +
|
187
|
+
"functionality, like this one. To see the help for " +
|
188
|
+
"a specific topic enter:\n\thelp [TOPIC]\nTry asking " +
|
189
|
+
"for help on any of the following:\n\n" +
|
190
|
+
"<%= list(#{topics.inspect}, :columns_across) %>"
|
191
|
+
choice(:help, help_help) do |command, topic|
|
192
|
+
topic.strip!
|
193
|
+
topic.downcase!
|
194
|
+
if topic.empty?
|
195
|
+
@highline.say(@help["help"])
|
196
|
+
else
|
197
|
+
@highline.say("= #{topic}\n\n#{@help[topic]}")
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
#
|
203
|
+
# Used to set help for arbitrary topics. Use the topic <tt>"help"</tt>
|
204
|
+
# to override the default message.
|
205
|
+
#
|
206
|
+
def help( topic, help )
|
207
|
+
@help[topic] = help
|
208
|
+
end
|
209
|
+
|
169
210
|
#
|
170
211
|
# Setting a _layout_ with this method also adjusts some other attributes
|
171
212
|
# of the Menu object, to ideal defaults for the chosen _layout_. To
|
@@ -232,10 +273,10 @@ class HighLine
|
|
232
273
|
|
233
274
|
#
|
234
275
|
# This method processes the auto-completed user selection, based on the
|
235
|
-
# rules for this Menu object.
|
276
|
+
# rules for this Menu object. If an action was provided for the
|
236
277
|
# selection, it will be executed as described in Menu.choice().
|
237
278
|
#
|
238
|
-
def select( selection, details = nil )
|
279
|
+
def select( highline_context, selection, details = nil )
|
239
280
|
# Find the selected action.
|
240
281
|
name, action = if selection =~ /^\d+$/
|
241
282
|
@items[selection.to_i - 1]
|
@@ -247,6 +288,7 @@ class HighLine
|
|
247
288
|
|
248
289
|
# Run or return it.
|
249
290
|
if not @nil_on_handled and not action.nil?
|
291
|
+
@highline = highline_context
|
250
292
|
if @shell
|
251
293
|
action.call(name, details)
|
252
294
|
else
|
data/lib/highline/question.rb
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
require "optparse"
|
9
9
|
require "date"
|
10
|
+
require "pathname"
|
10
11
|
|
11
12
|
class HighLine
|
12
13
|
#
|
@@ -34,7 +35,9 @@ class HighLine
|
|
34
35
|
@answer_type = answer_type
|
35
36
|
|
36
37
|
@character = nil
|
38
|
+
@limit = nil
|
37
39
|
@echo = true
|
40
|
+
@readline = false
|
38
41
|
@whitespace = :strip
|
39
42
|
@case = nil
|
40
43
|
@default = nil
|
@@ -43,6 +46,9 @@ class HighLine
|
|
43
46
|
@below = nil
|
44
47
|
@in = nil
|
45
48
|
@confirm = nil
|
49
|
+
@gather = false
|
50
|
+
@directory = Pathname.new(File.expand_path(File.dirname($0)))
|
51
|
+
@glob = "*"
|
46
52
|
@responses = Hash.new
|
47
53
|
|
48
54
|
# allow block to override settings
|
@@ -52,6 +58,8 @@ class HighLine
|
|
52
58
|
build_responses
|
53
59
|
end
|
54
60
|
|
61
|
+
# The ERb template of the question to be asked.
|
62
|
+
attr_accessor :question
|
55
63
|
# The type that will be used to convert this answer.
|
56
64
|
attr_accessor :answer_type
|
57
65
|
#
|
@@ -65,6 +73,12 @@ class HighLine
|
|
65
73
|
#
|
66
74
|
attr_accessor :character
|
67
75
|
#
|
76
|
+
# Allows you to set a character limit for input.
|
77
|
+
#
|
78
|
+
# *WARNING*: This option forces a character by character read.
|
79
|
+
#
|
80
|
+
attr_accessor :limit
|
81
|
+
#
|
68
82
|
# Can be set to +true+ or +false+ to control whether or not input will
|
69
83
|
# be echoed back to the user. A setting of +true+ will cause echo to
|
70
84
|
# match input, but any other true value will be treated as to String to
|
@@ -75,6 +89,16 @@ class HighLine
|
|
75
89
|
#
|
76
90
|
attr_accessor :echo
|
77
91
|
#
|
92
|
+
# Use the Readline library to fetch input. This allows input editing as
|
93
|
+
# well as keeping a history. In addition, tab will auto-complete
|
94
|
+
# within an Array of choices or a file listing.
|
95
|
+
#
|
96
|
+
# *WARNING*: This option is incompatible with all of HighLine's
|
97
|
+
# character reading modes and it causes HighLine to ignore the
|
98
|
+
# specified _input_ stream.
|
99
|
+
#
|
100
|
+
attr_accessor :readline
|
101
|
+
#
|
78
102
|
# Used to control whitespace processing for the answer to this question.
|
79
103
|
# See HighLine::Question.remove_whitespace() for acceptable settings.
|
80
104
|
#
|
@@ -105,6 +129,31 @@ class HighLine
|
|
105
129
|
#
|
106
130
|
attr_accessor :confirm
|
107
131
|
#
|
132
|
+
# When set, the user will be prompted for multiple answers which will
|
133
|
+
# be collected into an Array or Hash and returned as the final answer.
|
134
|
+
#
|
135
|
+
# You can set _gather_ to an Integer to have an Array of exactly that
|
136
|
+
# many answers collected, or a String/Regexp to match an end input which
|
137
|
+
# will not be returned in the Array.
|
138
|
+
#
|
139
|
+
# Optionally _gather_ can be set to a Hash. In this case, the question
|
140
|
+
# will be asked once for each key and the answers will be returned in a
|
141
|
+
# Hash, mapped by key. The <tt>@key</tt> variable is set before each
|
142
|
+
# question is evaluated, so you can use it in your question.
|
143
|
+
#
|
144
|
+
attr_accessor :gather
|
145
|
+
#
|
146
|
+
# The directory from which a user will be allowed to select files, when
|
147
|
+
# File or Pathname is specified as an _answer_type_. Initially set to
|
148
|
+
# <tt>Pathname.new(File.expand_path(File.dirname($0)))</tt>.
|
149
|
+
#
|
150
|
+
attr_accessor :directory
|
151
|
+
#
|
152
|
+
# The glob pattern used to limit file selection when File or Pathname is
|
153
|
+
# specified as an _answer_type_. Initially set to <tt>"*"</tt>.
|
154
|
+
#
|
155
|
+
attr_accessor :glob
|
156
|
+
#
|
108
157
|
# A Hash that stores the various responses used by HighLine to notify
|
109
158
|
# the user. The currently used responses and their purpose are as
|
110
159
|
# follows:
|
@@ -148,7 +197,7 @@ class HighLine
|
|
148
197
|
#
|
149
198
|
def build_responses( )
|
150
199
|
### WARNING: This code is quasi-duplicated in ###
|
151
|
-
### Menu.update_responses(). Check
|
200
|
+
### Menu.update_responses(). Check there too when ###
|
152
201
|
### making changes! ###
|
153
202
|
append_default unless default.nil?
|
154
203
|
@responses = { :ambiguous_completion =>
|
@@ -168,7 +217,7 @@ class HighLine
|
|
168
217
|
"Your answer isn't valid (must match " +
|
169
218
|
"#{@validate.inspect})." }.merge(@responses)
|
170
219
|
### WARNING: This code is quasi-duplicated in ###
|
171
|
-
### Menu.update_responses(). Check
|
220
|
+
### Menu.update_responses(). Check there too when ###
|
172
221
|
### making changes! ###
|
173
222
|
end
|
174
223
|
|
@@ -208,9 +257,14 @@ class HighLine
|
|
208
257
|
# <tt>lambda {...}</tt>:: Answer is passed to lambda for conversion.
|
209
258
|
# Date:: Date.parse() is called with answer.
|
210
259
|
# DateTime:: DateTime.parse() is called with answer.
|
260
|
+
# File:: The entered file name is auto-completed in
|
261
|
+
# terms of _directory_ + _glob_, opened, and
|
262
|
+
# returned.
|
211
263
|
# Float:: Answer is converted with Kernel.Float().
|
212
264
|
# Integer:: Answer is converted with Kernel.Integer().
|
213
265
|
# +nil+:: Answer is left in String format. (Default.)
|
266
|
+
# Pathname:: Same as File, save that a Pathname object is
|
267
|
+
# returned.
|
214
268
|
# String:: Answer is converted with Kernel.String().
|
215
269
|
# Regexp:: Answer is fed to Regexp.new().
|
216
270
|
# Symbol:: The method to_sym() is called on answer and
|
@@ -230,14 +284,22 @@ class HighLine
|
|
230
284
|
answer_string.to_sym
|
231
285
|
elsif @answer_type == Regexp
|
232
286
|
Regexp.new(answer_string)
|
233
|
-
elsif @answer_type.is_a?(Array)
|
287
|
+
elsif @answer_type.is_a?(Array) or
|
288
|
+
[File, Pathname].include?(@answer_type)
|
234
289
|
# cheating, using OptionParser's Completion module
|
235
|
-
|
236
|
-
|
290
|
+
choices = selection
|
291
|
+
choices.extend(OptionParser::Completion)
|
292
|
+
answer = choices.complete(answer_string)
|
237
293
|
if answer.nil?
|
238
294
|
raise NoAutoCompleteMatch
|
239
295
|
end
|
240
|
-
|
296
|
+
if @answer_type.is_a?(Array)
|
297
|
+
answer.last
|
298
|
+
elsif @answer_type == File
|
299
|
+
File.open(File.join(@directory.to_s, answer.last))
|
300
|
+
else
|
301
|
+
Pathname.new(File.join(@directory.to_s, answer.last))
|
302
|
+
end
|
241
303
|
elsif [Date, DateTime].include?(@answer_type) or
|
242
304
|
@answer_type.is_a?(Class)
|
243
305
|
@answer_type.parse(answer_string)
|
@@ -310,6 +372,23 @@ class HighLine
|
|
310
372
|
answer_string
|
311
373
|
end
|
312
374
|
end
|
375
|
+
|
376
|
+
#
|
377
|
+
# Returns an Array of valid answers to this question. These answers are
|
378
|
+
# only known when _answer_type_ is set to an Array of choices, File, or
|
379
|
+
# Pathname. Any other time, this method will return an empty Array.
|
380
|
+
#
|
381
|
+
def selection( )
|
382
|
+
if @answer_type.is_a?(Array)
|
383
|
+
@answer_type
|
384
|
+
elsif [File, Pathname].include?(@answer_type)
|
385
|
+
Dir[File.join(@directory.to_s, @glob)].map do |file|
|
386
|
+
File.basename(file)
|
387
|
+
end
|
388
|
+
else
|
389
|
+
[ ]
|
390
|
+
end
|
391
|
+
end
|
313
392
|
|
314
393
|
# Stringifies the question to be asked.
|
315
394
|
def to_str( )
|
data/test/tc_highline.rb
CHANGED
@@ -5,9 +5,6 @@
|
|
5
5
|
# Created by James Edward Gray II on 2005-04-26.
|
6
6
|
# Copyright 2005 Gray Productions. All rights reserved.
|
7
7
|
|
8
|
-
$test_lib_dir ||= File.join(File.dirname(__FILE__), "..", "lib")
|
9
|
-
$:.unshift($test_lib_dir) unless $:.include?($test_lib_dir)
|
10
|
-
|
11
8
|
require "test/unit"
|
12
9
|
|
13
10
|
require "highline"
|
@@ -233,6 +230,68 @@ class TestHighLine < Test::Unit::TestCase
|
|
233
230
|
@output.string )
|
234
231
|
end
|
235
232
|
|
233
|
+
def test_files
|
234
|
+
@input << "#{File.basename(__FILE__)[0, 5]}\n"
|
235
|
+
@input.rewind
|
236
|
+
|
237
|
+
file = @terminal.ask("Select a file: ", File) do |q|
|
238
|
+
q.directory = File.expand_path(File.dirname(__FILE__))
|
239
|
+
q.glob = "*.rb"
|
240
|
+
end
|
241
|
+
assert_instance_of(File, file)
|
242
|
+
assert_equal("#!/usr/local/bin/ruby -w\n", file.gets)
|
243
|
+
assert_equal("\n", file.gets)
|
244
|
+
assert_equal("# tc_highline.rb\n", file.gets)
|
245
|
+
file.close
|
246
|
+
|
247
|
+
@input.rewind
|
248
|
+
|
249
|
+
pathname = @terminal.ask("Select a file: ", Pathname) do |q|
|
250
|
+
q.directory = File.expand_path(File.dirname(__FILE__))
|
251
|
+
q.glob = "*.rb"
|
252
|
+
end
|
253
|
+
assert_instance_of(Pathname, pathname)
|
254
|
+
assert_equal(File.size(__FILE__), pathname.size)
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_gather
|
258
|
+
@input << "James\nDana\nStorm\nGypsy\n\n"
|
259
|
+
@input.rewind
|
260
|
+
|
261
|
+
answers = @terminal.ask("Enter four names:") do |q|
|
262
|
+
q.gather = 4
|
263
|
+
end
|
264
|
+
assert_equal(%w{James Dana Storm Gypsy}, answers)
|
265
|
+
assert_equal("\n", @input.gets)
|
266
|
+
assert_equal("Enter four names:\n", @output.string)
|
267
|
+
|
268
|
+
@input.rewind
|
269
|
+
|
270
|
+
answers = @terminal.ask("Enter four names:") do |q|
|
271
|
+
q.gather = ""
|
272
|
+
end
|
273
|
+
assert_equal(%w{James Dana Storm Gypsy}, answers)
|
274
|
+
|
275
|
+
@input.rewind
|
276
|
+
|
277
|
+
answers = @terminal.ask("Enter four names:") do |q|
|
278
|
+
q.gather = /^\s*$/
|
279
|
+
end
|
280
|
+
assert_equal(%w{James Dana Storm Gypsy}, answers)
|
281
|
+
|
282
|
+
@input.truncate(@input.rewind)
|
283
|
+
@input << "29\n49\n30\n"
|
284
|
+
@input.rewind
|
285
|
+
@output.truncate(@output.rewind)
|
286
|
+
|
287
|
+
answers = @terminal.ask("<%= @key %>: ", Integer) do |q|
|
288
|
+
q.gather = { "Age" => 0, "Wife's Age" => 0, "Father's Age" => 0}
|
289
|
+
end
|
290
|
+
assert_equal( { "Age" => 29, "Wife's Age" => 30, "Father's Age" => 49},
|
291
|
+
answers )
|
292
|
+
assert_equal("Age: Father's Age: Wife's Age: ", @output.string)
|
293
|
+
end
|
294
|
+
|
236
295
|
def test_lists
|
237
296
|
digits = %w{Zero One Two Three Four Five Six Seven Eight Nine}
|
238
297
|
|
data/test/tc_import.rb
CHANGED
@@ -5,9 +5,6 @@
|
|
5
5
|
# Created by James Edward Gray II on 2005-04-26.
|
6
6
|
# Copyright 2005 Gray Productions. All rights reserved.
|
7
7
|
|
8
|
-
$test_lib_dir ||= File.join(File.dirname(__FILE__), "..", "lib")
|
9
|
-
$:.unshift($test_lib_dir) unless $:.include?($test_lib_dir)
|
10
|
-
|
11
8
|
require "test/unit"
|
12
9
|
|
13
10
|
require "highline/import"
|
data/test/tc_menu.rb
CHANGED
@@ -5,9 +5,6 @@
|
|
5
5
|
# Created by Gregory Thomas Brown on 2005-05-10.
|
6
6
|
# Copyright 2005 smtose.org. All rights reserved.
|
7
7
|
|
8
|
-
$test_lib_dir ||= File.join(File.dirname(__FILE__), "..", "lib")
|
9
|
-
$:.unshift($test_lib_dir) unless $:.include?($test_lib_dir)
|
10
|
-
|
11
8
|
require "test/unit"
|
12
9
|
|
13
10
|
require "highline"
|
@@ -69,6 +66,39 @@ class TestMenu < Test::Unit::TestCase
|
|
69
66
|
assert_equal("Sample1, Sample2 or Sample3? ", @output.string)
|
70
67
|
end
|
71
68
|
|
69
|
+
def test_help
|
70
|
+
@input << "help\nhelp load\nhelp rules\nhelp missing\n"
|
71
|
+
@input.rewind
|
72
|
+
|
73
|
+
4.times do
|
74
|
+
@terminal.choose do |menu|
|
75
|
+
menu.shell = true
|
76
|
+
|
77
|
+
menu.choice(:load, "Load a file.")
|
78
|
+
menu.choice(:save, "Save data in file.")
|
79
|
+
menu.choice(:quit, "Exit program.")
|
80
|
+
|
81
|
+
menu.help("rules", "The rules of this system are as follows...")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
assert_equal( "1. load\n2. save\n3. quit\n4. help\n? " +
|
85
|
+
"This command will display helpful messages about " +
|
86
|
+
"functionality, like this one. To see the help for a " +
|
87
|
+
"specific topic enter:\n" +
|
88
|
+
"\thelp [TOPIC]\n" +
|
89
|
+
"Try asking for help on any of the following:\n" +
|
90
|
+
"\nload quit rules save \n" +
|
91
|
+
"1. load\n2. save\n3. quit\n4. help\n? " +
|
92
|
+
"= load\n\n" +
|
93
|
+
"Load a file.\n" +
|
94
|
+
"1. load\n2. save\n3. quit\n4. help\n? " +
|
95
|
+
"= rules\n\n" +
|
96
|
+
"The rules of this system are as follows...\n" +
|
97
|
+
"1. load\n2. save\n3. quit\n4. help\n? " +
|
98
|
+
"= missing\n\n" +
|
99
|
+
"There's no help for that topic.\n", @output.string )
|
100
|
+
end
|
101
|
+
|
72
102
|
def test_index
|
73
103
|
@input << "Sample1\n"
|
74
104
|
@input.rewind
|
@@ -291,7 +321,7 @@ class TestMenu < Test::Unit::TestCase
|
|
291
321
|
|
292
322
|
selected = nil
|
293
323
|
options = nil
|
294
|
-
answer = @terminal.choose
|
324
|
+
answer = @terminal.choose do |menu|
|
295
325
|
menu.choices(:load, :quit)
|
296
326
|
menu.choice(:save) do |command, details|
|
297
327
|
selected = command
|
data/test/ts_all.rb
CHANGED
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
|
|
3
3
|
specification_version: 1
|
4
4
|
name: highline
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2005-
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2005-07-07
|
8
8
|
summary: HighLine is a high-level line oriented console interface.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -30,10 +30,12 @@ authors:
|
|
30
30
|
- James Edward Gray II
|
31
31
|
files:
|
32
32
|
- examples/ansi_colors.rb
|
33
|
+
- examples/asking_for_arrays.rb
|
33
34
|
- examples/basic_usage.rb
|
34
35
|
- examples/menus.rb
|
35
36
|
- examples/page_and_wrap.rb
|
36
37
|
- examples/password.rb
|
38
|
+
- examples/using_readline.rb
|
37
39
|
- lib/highline.rb
|
38
40
|
- lib/highline/import.rb
|
39
41
|
- lib/highline/menu.rb
|