highline 1.7.10 → 2.0.0.pre.develop.2
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 +2 -0
- data/.simplecov +5 -0
- data/.travis.yml +11 -6
- data/Changelog.md +112 -20
- data/Gemfile +8 -7
- data/README.rdoc +3 -0
- data/Rakefile +7 -2
- data/appveyor.yml +19 -0
- data/examples/asking_for_arrays.rb +3 -0
- data/examples/basic_usage.rb +3 -0
- data/examples/get_character.rb +3 -0
- data/examples/limit.rb +3 -0
- data/examples/menus.rb +3 -0
- data/examples/overwrite.rb +3 -0
- data/examples/password.rb +3 -0
- data/examples/repeat_entry.rb +4 -1
- data/lib/highline.rb +182 -704
- data/lib/highline/builtin_styles.rb +109 -0
- data/lib/highline/color_scheme.rb +4 -1
- data/lib/highline/compatibility.rb +2 -0
- data/lib/highline/custom_errors.rb +19 -0
- data/lib/highline/import.rb +4 -2
- data/lib/highline/list.rb +93 -0
- data/lib/highline/list_renderer.rb +232 -0
- data/lib/highline/menu.rb +20 -20
- data/lib/highline/paginator.rb +43 -0
- data/lib/highline/question.rb +157 -97
- data/lib/highline/question/answer_converter.rb +84 -0
- data/lib/highline/question_asker.rb +147 -0
- data/lib/highline/simulate.rb +5 -1
- data/lib/highline/statement.rb +58 -0
- data/lib/highline/string.rb +34 -0
- data/lib/highline/string_extensions.rb +3 -28
- data/lib/highline/style.rb +18 -8
- data/lib/highline/template_renderer.rb +38 -0
- data/lib/highline/terminal.rb +78 -0
- data/lib/highline/terminal/io_console.rb +98 -0
- data/lib/highline/terminal/ncurses.rb +38 -0
- data/lib/highline/terminal/unix_stty.rb +94 -0
- data/lib/highline/version.rb +3 -1
- data/lib/highline/wrapper.rb +43 -0
- data/test/acceptance/acceptance.rb +62 -0
- data/test/acceptance/acceptance_test.rb +69 -0
- data/test/acceptance/at_color_output_using_erb_templates.rb +17 -0
- data/test/acceptance/at_echo_false.rb +23 -0
- data/test/acceptance/at_readline.rb +37 -0
- data/test/io_console_compatible.rb +37 -0
- data/test/string_methods.rb +3 -0
- data/test/test_answer_converter.rb +26 -0
- data/test/{tc_color_scheme.rb → test_color_scheme.rb} +7 -9
- data/test/test_helper.rb +26 -0
- data/test/{tc_highline.rb → test_highline.rb} +193 -136
- data/test/{tc_import.rb → test_import.rb} +5 -2
- data/test/test_list.rb +60 -0
- data/test/{tc_menu.rb → test_menu.rb} +6 -3
- data/test/test_paginator.rb +73 -0
- data/test/test_question_asker.rb +20 -0
- data/test/test_simulator.rb +24 -0
- data/test/test_string_extension.rb +72 -0
- data/test/{tc_string_highline.rb → test_string_highline.rb} +7 -3
- data/test/{tc_style.rb → test_style.rb} +70 -35
- data/test/test_wrapper.rb +188 -0
- metadata +57 -22
- data/lib/highline/system_extensions.rb +0 -254
- data/test/tc_simulator.rb +0 -33
- data/test/tc_string_extension.rb +0 -33
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
class HighLine
|
6
|
+
class TemplateRenderer
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@highline, :color, :list, :key
|
10
|
+
def_delegators :@source, :answer_type, :prompt, :header, :answer
|
11
|
+
|
12
|
+
attr_reader :template, :source, :highline
|
13
|
+
|
14
|
+
def initialize(template, source, highline)
|
15
|
+
@template = template
|
16
|
+
@source = source
|
17
|
+
@highline = highline
|
18
|
+
end
|
19
|
+
|
20
|
+
def render
|
21
|
+
template.result(binding)
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(method, *args)
|
25
|
+
"Method #{method} with args #{args.inspect} " +
|
26
|
+
"is not available on #{self.inspect}. " +
|
27
|
+
"Try #{methods(false).sort.inspect}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def menu
|
31
|
+
source
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.const_missing(name)
|
35
|
+
HighLine.const_get(name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# terminal.rb
|
5
|
+
#
|
6
|
+
# Originally created by James Edward Gray II on 2006-06-14 as
|
7
|
+
# system_extensions.rb.
|
8
|
+
# Copyright 2006 Gray Productions. All rights reserved.
|
9
|
+
#
|
10
|
+
# This is Free Software. See LICENSE and COPYING for details.
|
11
|
+
|
12
|
+
require "highline/compatibility"
|
13
|
+
|
14
|
+
class HighLine
|
15
|
+
class Terminal
|
16
|
+
def self.get_terminal(input, output)
|
17
|
+
terminal = nil
|
18
|
+
|
19
|
+
# First of all, probe for io/console
|
20
|
+
begin
|
21
|
+
require "io/console"
|
22
|
+
require "highline/terminal/io_console"
|
23
|
+
terminal = HighLine::Terminal::IOConsole.new(input, output)
|
24
|
+
rescue LoadError
|
25
|
+
end
|
26
|
+
|
27
|
+
# Fall back to UnixStty
|
28
|
+
unless terminal
|
29
|
+
require 'highline/terminal/unix_stty'
|
30
|
+
terminal = HighLine::Terminal::UnixStty.new(input, output)
|
31
|
+
end
|
32
|
+
|
33
|
+
terminal.initialize_system_extensions
|
34
|
+
terminal
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :input, :output
|
38
|
+
|
39
|
+
def initialize(input, output)
|
40
|
+
@input = input
|
41
|
+
@output = output
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize_system_extensions
|
45
|
+
end
|
46
|
+
|
47
|
+
def terminal_size
|
48
|
+
end
|
49
|
+
|
50
|
+
def raw_no_echo_mode
|
51
|
+
end
|
52
|
+
|
53
|
+
def raw_no_echo_mode_exec
|
54
|
+
raw_no_echo_mode
|
55
|
+
yield
|
56
|
+
ensure
|
57
|
+
restore_mode
|
58
|
+
end
|
59
|
+
|
60
|
+
def restore_mode
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_character
|
64
|
+
end
|
65
|
+
|
66
|
+
def jruby?
|
67
|
+
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
68
|
+
end
|
69
|
+
|
70
|
+
def rubinius?
|
71
|
+
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
72
|
+
end
|
73
|
+
|
74
|
+
def windows?
|
75
|
+
defined?(RUBY_PLATFORM) && (RUBY_PLATFORM =~ /mswin|mingw|cygwin/)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
class HighLine
|
4
|
+
class Terminal
|
5
|
+
class IOConsole < Terminal
|
6
|
+
def terminal_size
|
7
|
+
output.winsize.reverse
|
8
|
+
end
|
9
|
+
|
10
|
+
CHARACTER_MODE = "io_console" # For Debugging purposes only.
|
11
|
+
|
12
|
+
def raw_no_echo_mode
|
13
|
+
input.echo = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def restore_mode
|
17
|
+
input.echo = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_character
|
21
|
+
input.getch # from ruby io/console
|
22
|
+
end
|
23
|
+
|
24
|
+
def character_mode
|
25
|
+
"io_console"
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_line(question, highline, options={})
|
29
|
+
raw_answer =
|
30
|
+
if question.readline
|
31
|
+
get_line_with_readline(question, highline, options={})
|
32
|
+
else
|
33
|
+
get_line_default(highline)
|
34
|
+
end
|
35
|
+
|
36
|
+
question.format_answer(raw_answer)
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_line_with_readline(question, highline, options={})
|
40
|
+
require "readline" # load only if needed
|
41
|
+
|
42
|
+
question_string = highline.render_statement(question)
|
43
|
+
|
44
|
+
raw_answer = readline_read(question_string, question)
|
45
|
+
|
46
|
+
if !raw_answer and highline.track_eof?
|
47
|
+
raise EOFError, "The input stream is exhausted."
|
48
|
+
end
|
49
|
+
|
50
|
+
raw_answer || ""
|
51
|
+
end
|
52
|
+
|
53
|
+
def readline_read(string, question)
|
54
|
+
# prep auto-completion
|
55
|
+
unless question.selection.empty?
|
56
|
+
Readline.completion_proc = lambda do |str|
|
57
|
+
question.selection.grep(/\A#{Regexp.escape(str)}/)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# work-around ugly readline() warnings
|
62
|
+
old_verbose = $VERBOSE
|
63
|
+
$VERBOSE = nil
|
64
|
+
|
65
|
+
raw_answer = run_preserving_stty do
|
66
|
+
Readline.readline(string, true)
|
67
|
+
end
|
68
|
+
|
69
|
+
$VERBOSE = old_verbose
|
70
|
+
|
71
|
+
raw_answer
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_line_default(highline)
|
75
|
+
raise EOFError, "The input stream is exhausted." if highline.track_eof? and
|
76
|
+
highline.input.eof?
|
77
|
+
highline.input.gets
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def run_preserving_stty
|
83
|
+
save_stty
|
84
|
+
yield
|
85
|
+
ensure
|
86
|
+
restore_stty
|
87
|
+
end
|
88
|
+
|
89
|
+
def save_stty
|
90
|
+
@stty_save = `stty -g`.chomp rescue nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def restore_stty
|
94
|
+
system("stty", @stty_save) if @stty_save
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# TODO:
|
4
|
+
# Code below to be discussed.
|
5
|
+
# Will we maintain an ncurses version of HighLine::Terminal?
|
6
|
+
# If so, port it to the new api.
|
7
|
+
|
8
|
+
class HighLine
|
9
|
+
module SystemExtensions
|
10
|
+
module NCurses
|
11
|
+
require 'ffi-ncurses'
|
12
|
+
CHARACTER_MODE = "ncurses" # For Debugging purposes only.
|
13
|
+
|
14
|
+
def raw_no_echo_mode
|
15
|
+
FFI::NCurses.initscr
|
16
|
+
FFI::NCurses.cbreak
|
17
|
+
end
|
18
|
+
|
19
|
+
def restore_mode
|
20
|
+
FFI::NCurses.endwin
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# A ncurses savvy method to fetch the console columns, and rows.
|
25
|
+
#
|
26
|
+
def terminal_size
|
27
|
+
size = [80, 40]
|
28
|
+
FFI::NCurses.initscr
|
29
|
+
begin
|
30
|
+
size = FFI::NCurses.getmaxyx(FFI::NCurses.stdscr).reverse
|
31
|
+
ensure
|
32
|
+
FFI::NCurses.endwin
|
33
|
+
end
|
34
|
+
size
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
class HighLine
|
4
|
+
class Terminal::UnixStty < Terminal
|
5
|
+
|
6
|
+
# A Unix savvy method using stty to fetch the console columns, and rows.
|
7
|
+
# ... stty does not work in JRuby
|
8
|
+
def terminal_size
|
9
|
+
begin
|
10
|
+
require "io/console"
|
11
|
+
winsize = IO.console.winsize.reverse rescue nil
|
12
|
+
return winsize if winsize
|
13
|
+
rescue LoadError
|
14
|
+
end
|
15
|
+
|
16
|
+
if /solaris/ =~ RUBY_PLATFORM and
|
17
|
+
`stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/
|
18
|
+
[$2, $1].map { |c| x.to_i }
|
19
|
+
elsif `stty size` =~ /^(\d+)\s(\d+)$/
|
20
|
+
[$2.to_i, $1.to_i]
|
21
|
+
else
|
22
|
+
[ 80, 24 ]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# *WARNING*: This requires the external "stty" program!
|
27
|
+
CHARACTER_MODE = "unix_stty" # For Debugging purposes only.
|
28
|
+
|
29
|
+
def raw_no_echo_mode
|
30
|
+
@state = `stty -g`
|
31
|
+
system "stty raw -echo -icanon isig"
|
32
|
+
end
|
33
|
+
|
34
|
+
def restore_mode
|
35
|
+
system "stty #{@state}"
|
36
|
+
print "\r"
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_character( input = STDIN )
|
40
|
+
input.getc
|
41
|
+
end
|
42
|
+
|
43
|
+
def character_mode
|
44
|
+
"unix_stty"
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_line(question, highline, options={})
|
48
|
+
raw_answer =
|
49
|
+
if question.readline
|
50
|
+
get_line_with_readline(question, highline, options={})
|
51
|
+
else
|
52
|
+
get_line_default(highline)
|
53
|
+
end
|
54
|
+
|
55
|
+
question.format_answer(raw_answer)
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_line_with_readline(question, highline, options={})
|
59
|
+
require "readline" # load only if needed
|
60
|
+
|
61
|
+
question_string = highline.render_statement(question)
|
62
|
+
|
63
|
+
raw_answer = readline_read(question_string, question)
|
64
|
+
|
65
|
+
if !raw_answer and highline.track_eof?
|
66
|
+
raise EOFError, "The input stream is exhausted."
|
67
|
+
end
|
68
|
+
|
69
|
+
raw_answer || ""
|
70
|
+
end
|
71
|
+
|
72
|
+
def readline_read(string, question)
|
73
|
+
# prep auto-completion
|
74
|
+
Readline.completion_proc = lambda do |string|
|
75
|
+
question.selection.grep(/\A#{Regexp.escape(string)}/)
|
76
|
+
end
|
77
|
+
|
78
|
+
# work-around ugly readline() warnings
|
79
|
+
old_verbose = $VERBOSE
|
80
|
+
$VERBOSE = nil
|
81
|
+
raw_answer = Readline.readline(string, true)
|
82
|
+
|
83
|
+
$VERBOSE = old_verbose
|
84
|
+
|
85
|
+
raw_answer
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_line_default(highline)
|
89
|
+
raise EOFError, "The input stream is exhausted." if highline.track_eof? and
|
90
|
+
highline.input.eof?
|
91
|
+
highline.input.gets
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/highline/version.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
class HighLine
|
4
|
+
module Wrapper
|
5
|
+
|
6
|
+
#
|
7
|
+
# Wrap a sequence of _lines_ at _wrap_at_ characters per line. Existing
|
8
|
+
# newlines will not be affected by this process, but additional newlines
|
9
|
+
# may be added.
|
10
|
+
#
|
11
|
+
def self.wrap(text, wrap_at)
|
12
|
+
return text unless wrap_at
|
13
|
+
wrap_at = Integer(wrap_at)
|
14
|
+
|
15
|
+
wrapped = [ ]
|
16
|
+
text.each_line do |line|
|
17
|
+
# take into account color escape sequences when wrapping
|
18
|
+
wrap_at = wrap_at + (line.length - actual_length(line))
|
19
|
+
while line =~ /([^\n]{#{wrap_at + 1},})/
|
20
|
+
search = $1.dup
|
21
|
+
replace = $1.dup
|
22
|
+
if index = replace.rindex(" ", wrap_at)
|
23
|
+
replace[index, 1] = "\n"
|
24
|
+
replace.sub!(/\n[ \t]+/, "\n")
|
25
|
+
line.sub!(search, replace)
|
26
|
+
else
|
27
|
+
line[$~.begin(1) + wrap_at, 0] = "\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
wrapped << line
|
31
|
+
end
|
32
|
+
return wrapped.join
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Returns the length of the passed +string_with_escapes+, minus and color
|
37
|
+
# sequence escapes.
|
38
|
+
#
|
39
|
+
def self.actual_length( string_with_escapes )
|
40
|
+
string_with_escapes.to_s.gsub(/\e\[\d{1,2}m/, "").length
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
current_dir = File.dirname(File.expand_path(__FILE__))
|
5
|
+
|
6
|
+
# All acceptance test files begins with 'at_'
|
7
|
+
acceptance_test_files = Dir["#{current_dir}/at_*"]
|
8
|
+
|
9
|
+
# Load each acceptance test file making
|
10
|
+
# all tests to be run
|
11
|
+
acceptance_test_files.each { |file| load file }
|
12
|
+
|
13
|
+
# Print a report
|
14
|
+
|
15
|
+
report = <<EOF
|
16
|
+
|
17
|
+
===
|
18
|
+
Well done!
|
19
|
+
|
20
|
+
Below you have a report with all the answers you gave.
|
21
|
+
It has also some environment information to help us debugging.
|
22
|
+
|
23
|
+
If any of the tests have not passed on your environment,
|
24
|
+
please copy/past the text bellow and send to us.
|
25
|
+
|
26
|
+
If you are familiar with GitHub you can report the failing test
|
27
|
+
as a GitHub issue at https://github.com/JEG2/highline/issues.
|
28
|
+
If possible, always check if your issue is already reported
|
29
|
+
by someone else. If so, just report that you are also affected
|
30
|
+
on the same alredy open issued.
|
31
|
+
|
32
|
+
If you are more confortable with e-mail, you could send it to
|
33
|
+
james@grayproductions.net
|
34
|
+
|
35
|
+
=== HighLine Acceptance Tests Report
|
36
|
+
Date: #{Time.now.utc}
|
37
|
+
HighLine::VERSION: #{HighLine::VERSION}
|
38
|
+
Terminal: #{$terminal.terminal.class}
|
39
|
+
RUBY_DESCRIPTION: #{RUBY_DESCRIPTION rescue 'not available'}
|
40
|
+
Readline::VERSION: #{Readline::VERSION rescue 'not availabe'}
|
41
|
+
ENV['SHELL']: #{ENV['SHELL']}
|
42
|
+
ENV['TERM']: #{ENV['TERM']}
|
43
|
+
ENV['TERM_PROGRAM']: #{ENV['TERM_PROGRAM']}
|
44
|
+
|
45
|
+
Answers:
|
46
|
+
#{HighLine::AcceptanceTest.answers_for_report}
|
47
|
+
EOF
|
48
|
+
|
49
|
+
puts report
|
50
|
+
|
51
|
+
timestamp = Time.now.strftime('%Y%m%d%H%M%S')
|
52
|
+
filename = "highlinetests-#{timestamp}.log"
|
53
|
+
|
54
|
+
File.open "#{filename}", 'w+' do |f|
|
55
|
+
f.puts report
|
56
|
+
end
|
57
|
+
|
58
|
+
puts
|
59
|
+
puts "You can also see the above information in"
|
60
|
+
puts "a timestamped file named #{filename}"
|
61
|
+
puts "at the current directory."
|
62
|
+
puts
|