highline 2.0.0.pre.develop.2 → 2.0.0.pre.develop.4
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/Changelog.md +28 -0
- data/README.md +188 -0
- data/Rakefile +0 -11
- data/highline.gemspec +2 -4
- data/lib/highline.rb +170 -73
- data/lib/highline/builtin_styles.rb +18 -2
- data/lib/highline/color_scheme.rb +15 -5
- data/lib/highline/compatibility.rb +6 -1
- data/lib/highline/custom_errors.rb +43 -6
- data/lib/highline/import.rb +10 -3
- data/lib/highline/list.rb +95 -7
- data/lib/highline/list_renderer.rb +36 -17
- data/lib/highline/menu.rb +73 -18
- data/lib/highline/paginator.rb +10 -0
- data/lib/highline/question.rb +98 -41
- data/lib/highline/question/answer_converter.rb +19 -0
- data/lib/highline/question_asker.rb +21 -17
- data/lib/highline/simulate.rb +10 -1
- data/lib/highline/statement.rb +62 -38
- data/lib/highline/string.rb +26 -25
- data/lib/highline/string_extensions.rb +60 -32
- data/lib/highline/style.rb +125 -25
- data/lib/highline/template_renderer.rb +25 -1
- data/lib/highline/terminal.rb +124 -1
- data/lib/highline/terminal/io_console.rb +6 -75
- data/lib/highline/terminal/ncurses.rb +7 -8
- data/lib/highline/terminal/unix_stty.rb +35 -81
- data/lib/highline/version.rb +1 -1
- data/lib/highline/wrapper.rb +9 -0
- data/test/test_highline.rb +1 -1
- metadata +6 -13
- data/INSTALL +0 -59
- data/README.rdoc +0 -77
- data/setup.rb +0 -1360
@@ -4,6 +4,7 @@ require 'forwardable'
|
|
4
4
|
|
5
5
|
class HighLine
|
6
6
|
class Question
|
7
|
+
# It provides all answer conversion flow.
|
7
8
|
class AnswerConverter
|
8
9
|
extend Forwardable
|
9
10
|
|
@@ -11,10 +12,19 @@ class HighLine
|
|
11
12
|
:answer, :answer=, :check_range,
|
12
13
|
:directory, :answer_type, :choices_complete
|
13
14
|
|
15
|
+
# It should be initialized with a Question object.
|
16
|
+
# The class will get the answer from {Question#answer}
|
17
|
+
# and then convert it to the proper {Question#answer_type}.
|
18
|
+
# It is mainly used by {Question#convert}
|
19
|
+
#
|
20
|
+
# @param question [Question]
|
14
21
|
def initialize(question)
|
15
22
|
@question = question
|
16
23
|
end
|
17
24
|
|
25
|
+
# Based on the given Question object's settings,
|
26
|
+
# it makes the conversion and returns the answer.
|
27
|
+
# @return [Object] the converted answer.
|
18
28
|
def convert
|
19
29
|
return unless answer_type
|
20
30
|
|
@@ -23,6 +33,7 @@ class HighLine
|
|
23
33
|
answer
|
24
34
|
end
|
25
35
|
|
36
|
+
# @return [HighLine::String] answer converted to a HighLine::String
|
26
37
|
def to_string
|
27
38
|
HighLine::String(answer)
|
28
39
|
end
|
@@ -33,37 +44,45 @@ class HighLine
|
|
33
44
|
HighLine::String(answer)
|
34
45
|
end
|
35
46
|
|
47
|
+
# @return [Integer] answer converted to an Integer
|
36
48
|
def to_integer
|
37
49
|
Kernel.send(:Integer, answer)
|
38
50
|
end
|
39
51
|
|
52
|
+
# @return [Float] answer converted to a Float
|
40
53
|
def to_float
|
41
54
|
Kernel.send(:Float, answer)
|
42
55
|
end
|
43
56
|
|
57
|
+
# @return [Symbol] answer converted to an Symbol
|
44
58
|
def to_symbol
|
45
59
|
answer.to_sym
|
46
60
|
end
|
47
61
|
|
62
|
+
# @return [Regexp] answer converted to a Regexp
|
48
63
|
def to_regexp
|
49
64
|
Regexp.new(answer)
|
50
65
|
end
|
51
66
|
|
67
|
+
# @return [File] answer converted to a File
|
52
68
|
def to_file
|
53
69
|
self.answer = choices_complete(answer)
|
54
70
|
File.open(File.join(directory.to_s, answer.last))
|
55
71
|
end
|
56
72
|
|
73
|
+
# @return [Pathname] answer converted to an Pathname
|
57
74
|
def to_pathname
|
58
75
|
self.answer = choices_complete(answer)
|
59
76
|
Pathname.new(File.join(directory.to_s, answer.last))
|
60
77
|
end
|
61
78
|
|
79
|
+
# @return [Array] answer converted to an Array
|
62
80
|
def to_array
|
63
81
|
self.answer = choices_complete(answer)
|
64
82
|
answer.last
|
65
83
|
end
|
66
84
|
|
85
|
+
# @return [Proc] answer converted to an Proc
|
67
86
|
def to_proc
|
68
87
|
answer_type.call(answer)
|
69
88
|
end
|
@@ -1,9 +1,17 @@
|
|
1
1
|
class HighLine
|
2
|
+
# Deals with the task of "asking" a question
|
2
3
|
class QuestionAsker
|
4
|
+
# @return [Question] question to be asked
|
3
5
|
attr_reader :question
|
4
6
|
|
5
7
|
include CustomErrors
|
6
8
|
|
9
|
+
# To do its work QuestionAsker needs a Question
|
10
|
+
# to be asked and a HighLine context where to
|
11
|
+
# direct output.
|
12
|
+
#
|
13
|
+
# @param question [Question] question to be asked
|
14
|
+
# @param highline [HighLine] context
|
7
15
|
def initialize(question, highline)
|
8
16
|
@question = question
|
9
17
|
@highline = highline
|
@@ -12,6 +20,7 @@ class HighLine
|
|
12
20
|
#
|
13
21
|
# Gets just one answer, as opposed to #gather_answers
|
14
22
|
#
|
23
|
+
# @return [String] answer
|
15
24
|
def ask_once
|
16
25
|
question.show_question(@highline)
|
17
26
|
|
@@ -25,19 +34,8 @@ class HighLine
|
|
25
34
|
raise NoConfirmationQuestionError unless @highline.send(:confirm, question)
|
26
35
|
end
|
27
36
|
|
28
|
-
rescue
|
29
|
-
explain_error(
|
30
|
-
retry
|
31
|
-
|
32
|
-
rescue NotInRangeQuestionError
|
33
|
-
explain_error(:not_in_range)
|
34
|
-
retry
|
35
|
-
|
36
|
-
rescue NotValidQuestionError
|
37
|
-
explain_error(:not_valid)
|
38
|
-
retry
|
39
|
-
|
40
|
-
rescue QuestionError
|
37
|
+
rescue ExplainableError => e
|
38
|
+
explain_error(e.explanation_key)
|
41
39
|
retry
|
42
40
|
|
43
41
|
rescue ArgumentError => error
|
@@ -54,11 +52,8 @@ class HighLine
|
|
54
52
|
else
|
55
53
|
raise
|
56
54
|
end
|
57
|
-
|
58
|
-
rescue NoAutoCompleteMatch
|
59
|
-
explain_error(:no_completion)
|
60
|
-
retry
|
61
55
|
end
|
56
|
+
|
62
57
|
question.answer
|
63
58
|
end
|
64
59
|
|
@@ -68,6 +63,7 @@ class HighLine
|
|
68
63
|
# Collects an Array/Hash full of answers as described in
|
69
64
|
# HighLine::Question.gather().
|
70
65
|
#
|
66
|
+
# @return [Array, Hash] answers
|
71
67
|
def gather_answers
|
72
68
|
original_question_template = question.template
|
73
69
|
verify_match = question.verify_match
|
@@ -87,12 +83,17 @@ class HighLine
|
|
87
83
|
question.verify_match ? @highline.send(:last_answer, answers) : answers
|
88
84
|
end
|
89
85
|
|
86
|
+
# Gather multiple integer values based on {Question#gather} count
|
87
|
+
# @return [Array] answers
|
90
88
|
def gather_integer
|
91
89
|
gather_with_array do |answers|
|
92
90
|
(question.gather-1).times { answers << ask_once }
|
93
91
|
end
|
94
92
|
end
|
95
93
|
|
94
|
+
# Gather multiple values until any of them matches the
|
95
|
+
# {Question#gather} Regexp.
|
96
|
+
# @return [Array] answers
|
96
97
|
def gather_regexp
|
97
98
|
gather_with_array do |answers|
|
98
99
|
answers << ask_once until answer_matches_regex(answers.last)
|
@@ -100,6 +101,9 @@ class HighLine
|
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
104
|
+
# Gather multiple values and store them on a Hash
|
105
|
+
# with keys provided by the Hash on {Question#gather}
|
106
|
+
# @return [Hash]
|
103
107
|
def gather_hash
|
104
108
|
answers = {}
|
105
109
|
|
data/lib/highline/simulate.rb
CHANGED
@@ -10,12 +10,15 @@
|
|
10
10
|
#
|
11
11
|
# adapted from https://gist.github.com/194554
|
12
12
|
|
13
|
+
|
13
14
|
class HighLine
|
14
15
|
|
15
16
|
# Simulates Highline input for use in tests.
|
16
17
|
class Simulate
|
17
18
|
|
18
19
|
# Creates a simulator with an array of Strings as a script
|
20
|
+
# @param strings [Array<String>] preloaded string to be used
|
21
|
+
# as input buffer when simulating.
|
19
22
|
def initialize(strings)
|
20
23
|
@strings = strings
|
21
24
|
end
|
@@ -40,7 +43,13 @@ class HighLine
|
|
40
43
|
false
|
41
44
|
end
|
42
45
|
|
43
|
-
# A wrapper method that temporarily replaces the Highline
|
46
|
+
# A wrapper method that temporarily replaces the Highline
|
47
|
+
# instance in $terminal with an instance of this object
|
48
|
+
# for the duration of the block
|
49
|
+
#
|
50
|
+
# @param strings [String] preloaded string buffer that
|
51
|
+
# will feed the input operations when simulating.
|
52
|
+
|
44
53
|
def self.with(*strings)
|
45
54
|
@input = $terminal.instance_variable_get :@input
|
46
55
|
$terminal.instance_variable_set :@input, new(strings)
|
data/lib/highline/statement.rb
CHANGED
@@ -4,55 +4,79 @@ require 'highline/wrapper'
|
|
4
4
|
require 'highline/paginator'
|
5
5
|
require 'highline/template_renderer'
|
6
6
|
|
7
|
-
class HighLine
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
class HighLine
|
8
|
+
# This class handles proper formatting based
|
9
|
+
# on a HighLine context, applying wrapping,
|
10
|
+
# pagination, indentation and color rendering
|
11
|
+
# when necessary. It's used by {HighLine#render_statement}
|
12
|
+
# @see HighLine#render_statement
|
13
|
+
class Statement
|
14
|
+
# The source object to be stringfied and formatted.
|
15
|
+
attr_reader :source
|
16
16
|
|
17
|
-
|
18
|
-
@
|
19
|
-
|
17
|
+
# The HighLine context
|
18
|
+
# @return [HighLine]
|
19
|
+
attr_reader :highline
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# The stringfied source object
|
22
|
+
# @return [String]
|
23
|
+
attr_reader :template_string
|
24
24
|
|
25
|
-
|
25
|
+
# It needs the input String and the HighLine context
|
26
|
+
# @param source [#to_s]
|
27
|
+
# @param highline [HighLine] context
|
28
|
+
def initialize(source, highline)
|
29
|
+
@highline = highline
|
30
|
+
@source = source
|
31
|
+
@template_string = stringfy(source)
|
32
|
+
end
|
26
33
|
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
# Returns the formated statement.
|
35
|
+
# Applies wrapping, pagination, indentation and color rendering
|
36
|
+
# based on HighLine instance settings.
|
37
|
+
# @return [String] formated statement
|
38
|
+
def statement
|
39
|
+
@statement ||= format_statement
|
40
|
+
end
|
30
41
|
|
31
|
-
|
32
|
-
|
42
|
+
# (see #statement)
|
43
|
+
# Delegates to {#statement}
|
44
|
+
def to_s
|
45
|
+
statement
|
46
|
+
end
|
33
47
|
|
34
|
-
|
48
|
+
private
|
35
49
|
|
36
|
-
|
37
|
-
|
50
|
+
def stringfy(template_string)
|
51
|
+
String(template_string || "").dup
|
52
|
+
end
|
38
53
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
54
|
+
def format_statement
|
55
|
+
return template_string unless template_string.length > 0
|
42
56
|
|
43
|
-
|
44
|
-
# Assigning to a local var so it may be
|
45
|
-
# used inside instance eval block
|
57
|
+
statement = render_template
|
46
58
|
|
47
|
-
|
48
|
-
|
49
|
-
end
|
59
|
+
statement = HighLine::Wrapper.wrap(statement, highline.wrap_at)
|
60
|
+
statement = HighLine::Paginator.new(highline).page_print(statement)
|
50
61
|
|
51
|
-
|
52
|
-
|
53
|
-
|
62
|
+
statement = statement.gsub(/\n(?!$)/,"\n#{highline.indentation}") if highline.multi_indent
|
63
|
+
statement
|
64
|
+
end
|
65
|
+
|
66
|
+
def render_template
|
67
|
+
# Assigning to a local var so it may be
|
68
|
+
# used inside instance eval block
|
69
|
+
|
70
|
+
template_renderer = TemplateRenderer.new(template, source, highline)
|
71
|
+
template_renderer.render
|
72
|
+
end
|
73
|
+
|
74
|
+
def template
|
75
|
+
@template ||= ERB.new(template_string, nil, "%")
|
76
|
+
end
|
54
77
|
|
55
|
-
|
56
|
-
|
78
|
+
def self.const_missing(constant)
|
79
|
+
HighLine.const_get(constant)
|
80
|
+
end
|
57
81
|
end
|
58
82
|
end
|
data/lib/highline/string.rb
CHANGED
@@ -2,32 +2,33 @@
|
|
2
2
|
|
3
3
|
require "highline/string_extensions"
|
4
4
|
|
5
|
-
#
|
6
|
-
# HighLine::String is a subclass of String with convenience methods added for colorization.
|
7
|
-
#
|
8
|
-
# Available convenience methods include:
|
9
|
-
# * 'color' method e.g. highline_string.color(:bright_blue, :underline)
|
10
|
-
# * colors e.g. highline_string.magenta
|
11
|
-
# * RGB colors e.g. highline_string.rgb_ff6000
|
12
|
-
# or highline_string.rgb(255,96,0)
|
13
|
-
# * background colors e.g. highline_string.on_magenta
|
14
|
-
# * RGB background colors e.g. highline_string.on_rgb_ff6000
|
15
|
-
# or highline_string.on_rgb(255,96,0)
|
16
|
-
# * styles e.g. highline_string.underline
|
17
|
-
#
|
18
|
-
# Additionally, convenience methods can be chained, for instance the following are equivalent:
|
19
|
-
# highline_string.bright_blue.blink.underline
|
20
|
-
# highline_string.color(:bright_blue, :blink, :underline)
|
21
|
-
# HighLine.color(highline_string, :bright_blue, :blink, :underline)
|
22
|
-
#
|
23
|
-
# For those less squeamish about possible conflicts, the same convenience methods can be
|
24
|
-
# added to the built-in String class, as follows:
|
25
|
-
#
|
26
|
-
# require 'highline'
|
27
|
-
# Highline.colorize_strings
|
28
|
-
#
|
29
|
-
|
30
5
|
class HighLine
|
6
|
+
|
7
|
+
#
|
8
|
+
# HighLine::String is a subclass of String with convenience methods added for colorization.
|
9
|
+
#
|
10
|
+
# Available convenience methods include:
|
11
|
+
# * 'color' method e.g. highline_string.color(:bright_blue, :underline)
|
12
|
+
# * colors e.g. highline_string.magenta
|
13
|
+
# * RGB colors e.g. highline_string.rgb_ff6000
|
14
|
+
# or highline_string.rgb(255,96,0)
|
15
|
+
# * background colors e.g. highline_string.on_magenta
|
16
|
+
# * RGB background colors e.g. highline_string.on_rgb_ff6000
|
17
|
+
# or highline_string.on_rgb(255,96,0)
|
18
|
+
# * styles e.g. highline_string.underline
|
19
|
+
#
|
20
|
+
# Additionally, convenience methods can be chained, for instance the following are equivalent:
|
21
|
+
# highline_string.bright_blue.blink.underline
|
22
|
+
# highline_string.color(:bright_blue, :blink, :underline)
|
23
|
+
# HighLine.color(highline_string, :bright_blue, :blink, :underline)
|
24
|
+
#
|
25
|
+
# For those less squeamish about possible conflicts, the same convenience methods can be
|
26
|
+
# added to the built-in String class, as follows:
|
27
|
+
#
|
28
|
+
# require 'highline'
|
29
|
+
# Highline.colorize_strings
|
30
|
+
#
|
31
|
+
|
31
32
|
class String < ::String
|
32
33
|
include StringExtensions
|
33
34
|
end
|
@@ -1,40 +1,30 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
class HighLine
|
4
|
+
# Returns a HighLine::String from any given String.
|
5
|
+
# @param s [String]
|
6
|
+
# @return [HighLine::String] from the given string.
|
4
7
|
def self.String(s)
|
5
8
|
HighLine::String.new(s)
|
6
9
|
end
|
7
10
|
|
8
|
-
# HighLine extensions for String class
|
9
|
-
# Included by HighLine::String
|
11
|
+
# HighLine extensions for String class.
|
12
|
+
# Included by HighLine::String.
|
10
13
|
module StringExtensions
|
14
|
+
# Included hook. Actions to take when being included.
|
15
|
+
# @param base [Class, Module] base class
|
11
16
|
def self.included(base)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
undef :#{color} if method_defined? :#{color}
|
16
|
-
def #{color}
|
17
|
-
color(:#{color})
|
18
|
-
end
|
19
|
-
END
|
20
|
-
|
21
|
-
base.class_eval <<-END
|
22
|
-
undef :on_#{color} if method_defined? :on_#{color}
|
23
|
-
def on_#{color}
|
24
|
-
on(:#{color})
|
25
|
-
end
|
26
|
-
END
|
27
|
-
HighLine::STYLES.each do |style|
|
28
|
-
style = style.downcase
|
29
|
-
base.class_eval <<-END
|
30
|
-
undef :#{style} if method_defined? :#{style}
|
31
|
-
def #{style}
|
32
|
-
color(:#{style})
|
33
|
-
end
|
34
|
-
END
|
35
|
-
end
|
36
|
-
end
|
17
|
+
define_builtin_style_methods(base)
|
18
|
+
define_style_support_methods(base)
|
19
|
+
end
|
37
20
|
|
21
|
+
# At include time, it defines all basic style
|
22
|
+
# support method like #color, #on, #uncolor,
|
23
|
+
# #rgb, #on_rgb and the #method_missing callback
|
24
|
+
# @return [void]
|
25
|
+
# @param base [Class, Module] the base class/module
|
26
|
+
#
|
27
|
+
def self.define_style_support_methods(base)
|
38
28
|
base.class_eval do
|
39
29
|
undef :color if method_defined? :color
|
40
30
|
undef :foreground if method_defined? :foreground
|
@@ -55,19 +45,17 @@ class HighLine
|
|
55
45
|
|
56
46
|
undef :rgb if method_defined? :rgb
|
57
47
|
def rgb(*colors)
|
58
|
-
color_code = colors
|
59
|
-
raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
|
48
|
+
color_code = setup_color_code(*colors)
|
60
49
|
color("rgb_#{color_code}".to_sym)
|
61
50
|
end
|
62
51
|
|
63
52
|
undef :on_rgb if method_defined? :on_rgb
|
64
53
|
def on_rgb(*colors)
|
65
|
-
color_code = colors
|
66
|
-
raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
|
54
|
+
color_code = setup_color_code(*colors)
|
67
55
|
color("on_rgb_#{color_code}".to_sym)
|
68
56
|
end
|
69
57
|
|
70
|
-
#
|
58
|
+
# @todo Chain existing method_missing?
|
71
59
|
undef :method_missing if method_defined? :method_missing
|
72
60
|
def method_missing(method, *args, &blk)
|
73
61
|
if method.to_s =~ /^(on_)?rgb_([0-9a-fA-F]{6})$/
|
@@ -76,10 +64,50 @@ class HighLine
|
|
76
64
|
raise NoMethodError, "undefined method `#{method}' for #<#{self.class}:#{'%#x'%self.object_id}>"
|
77
65
|
end
|
78
66
|
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def setup_color_code(*colors)
|
71
|
+
color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
|
72
|
+
raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
|
73
|
+
color_code
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# At include time, it defines all basic builtin styles.
|
79
|
+
# @param base [Class, Module] base Class/Module
|
80
|
+
def self.define_builtin_style_methods(base)
|
81
|
+
HighLine::COLORS.each do |color|
|
82
|
+
color = color.downcase
|
83
|
+
base.class_eval <<-END
|
84
|
+
undef :#{color} if method_defined? :#{color}
|
85
|
+
def #{color}
|
86
|
+
color(:#{color})
|
87
|
+
end
|
88
|
+
END
|
89
|
+
|
90
|
+
base.class_eval <<-END
|
91
|
+
undef :on_#{color} if method_defined? :on_#{color}
|
92
|
+
def on_#{color}
|
93
|
+
on(:#{color})
|
94
|
+
end
|
95
|
+
END
|
96
|
+
|
97
|
+
HighLine::STYLES.each do |style|
|
98
|
+
style = style.downcase
|
99
|
+
base.class_eval <<-END
|
100
|
+
undef :#{style} if method_defined? :#{style}
|
101
|
+
def #{style}
|
102
|
+
color(:#{style})
|
103
|
+
end
|
104
|
+
END
|
105
|
+
end
|
79
106
|
end
|
80
107
|
end
|
81
108
|
end
|
82
109
|
|
110
|
+
# Adds color support to the base String class
|
83
111
|
def self.colorize_strings
|
84
112
|
::String.send(:include, StringExtensions)
|
85
113
|
end
|