highline 1.7.10 → 2.0.3
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 +5 -5
- data/.gitignore +5 -0
- data/.rubocop.yml +84 -0
- data/.simplecov +5 -0
- data/.travis.yml +35 -9
- data/Changelog.md +214 -15
- data/Gemfile +16 -5
- data/README.md +202 -0
- data/Rakefile +8 -20
- data/appveyor.yml +37 -0
- data/examples/ansi_colors.rb +6 -11
- data/examples/asking_for_arrays.rb +6 -2
- data/examples/basic_usage.rb +31 -21
- data/examples/color_scheme.rb +11 -10
- data/examples/get_character.rb +8 -4
- data/examples/limit.rb +4 -0
- data/examples/menus.rb +16 -10
- data/examples/overwrite.rb +9 -5
- data/examples/page_and_wrap.rb +5 -4
- data/examples/password.rb +4 -0
- data/examples/repeat_entry.rb +10 -5
- data/examples/trapping_eof.rb +2 -1
- data/examples/using_readline.rb +2 -1
- data/highline.gemspec +25 -27
- data/lib/highline/builtin_styles.rb +129 -0
- data/lib/highline/color_scheme.rb +49 -32
- data/lib/highline/compatibility.rb +11 -4
- data/lib/highline/custom_errors.rb +57 -0
- data/lib/highline/import.rb +19 -12
- data/lib/highline/io_console_compatible.rb +37 -0
- data/lib/highline/list.rb +177 -0
- data/lib/highline/list_renderer.rb +261 -0
- data/lib/highline/menu/item.rb +32 -0
- data/lib/highline/menu.rb +306 -111
- data/lib/highline/paginator.rb +52 -0
- data/lib/highline/question/answer_converter.rb +103 -0
- data/lib/highline/question.rb +281 -131
- data/lib/highline/question_asker.rb +150 -0
- data/lib/highline/simulate.rb +24 -13
- data/lib/highline/statement.rb +88 -0
- data/lib/highline/string.rb +36 -0
- data/lib/highline/string_extensions.rb +83 -64
- data/lib/highline/style.rb +196 -63
- data/lib/highline/template_renderer.rb +62 -0
- data/lib/highline/terminal/io_console.rb +36 -0
- data/lib/highline/terminal/ncurses.rb +38 -0
- data/lib/highline/terminal/unix_stty.rb +51 -0
- data/lib/highline/terminal.rb +190 -0
- data/lib/highline/version.rb +3 -1
- data/lib/highline/wrapper.rb +53 -0
- data/lib/highline.rb +390 -788
- metadata +56 -35
- data/INSTALL +0 -59
- data/README.rdoc +0 -74
- data/lib/highline/system_extensions.rb +0 -254
- data/setup.rb +0 -1360
- data/test/string_methods.rb +0 -32
- data/test/tc_color_scheme.rb +0 -96
- data/test/tc_highline.rb +0 -1402
- data/test/tc_import.rb +0 -52
- data/test/tc_menu.rb +0 -439
- data/test/tc_simulator.rb +0 -33
- data/test/tc_string_extension.rb +0 -33
- data/test/tc_string_highline.rb +0 -38
- data/test/tc_style.rb +0 -578
@@ -0,0 +1,261 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require "highline/template_renderer"
|
4
|
+
require "highline/wrapper"
|
5
|
+
require "highline/list"
|
6
|
+
|
7
|
+
class HighLine
|
8
|
+
#
|
9
|
+
# This class is a utility for quickly and easily laying out lists
|
10
|
+
# to be used by HighLine.
|
11
|
+
#
|
12
|
+
class ListRenderer
|
13
|
+
# Items list
|
14
|
+
# @return [Array]
|
15
|
+
attr_reader :items
|
16
|
+
|
17
|
+
# @return [Symbol] the current mode the List is being rendered
|
18
|
+
# @see #initialize for more details see mode parameter of #initialize
|
19
|
+
attr_reader :mode
|
20
|
+
|
21
|
+
# Changes the behaviour of some modes. Example, in :inline mode
|
22
|
+
# the option is treated as the 'end separator' (defaults to " or ")
|
23
|
+
# @return option parameter that changes the behaviour of some modes.
|
24
|
+
attr_reader :option
|
25
|
+
|
26
|
+
# @return [HighLine] context
|
27
|
+
attr_reader :highline
|
28
|
+
|
29
|
+
# The only required parameters are _items_ and _highline_.
|
30
|
+
# @param items [Array] the Array of items to list
|
31
|
+
# @param mode [Symbol] controls how that list is formed
|
32
|
+
# @param option has different effects, depending on the _mode_.
|
33
|
+
# @param highline [HighLine] a HighLine instance to direct the output to.
|
34
|
+
#
|
35
|
+
# Recognized modes are:
|
36
|
+
#
|
37
|
+
# <tt>:columns_across</tt>:: _items_ will be placed in columns,
|
38
|
+
# flowing from left to right. If given,
|
39
|
+
# _option_ is the number of columns to be
|
40
|
+
# used. When absent, columns will be
|
41
|
+
# determined based on _wrap_at_ or a
|
42
|
+
# default of 80 characters.
|
43
|
+
# <tt>:columns_down</tt>:: Identical to <tt>:columns_across</tt>,
|
44
|
+
# save flow goes down.
|
45
|
+
# <tt>:uneven_columns_across</tt>:: Like <tt>:columns_across</tt> but each
|
46
|
+
# column is sized independently.
|
47
|
+
# <tt>:uneven_columns_down</tt>:: Like <tt>:columns_down</tt> but each
|
48
|
+
# column is sized independently.
|
49
|
+
# <tt>:inline</tt>:: All _items_ are placed on a single
|
50
|
+
# line. The last two _items_ are
|
51
|
+
# separated by _option_ or a default of
|
52
|
+
# " or ". All other _items_ are
|
53
|
+
# separated by ", ".
|
54
|
+
# <tt>:rows</tt>:: The default mode. Each of the _items_
|
55
|
+
# is placed on its own line. The _option_
|
56
|
+
# parameter is ignored in this mode.
|
57
|
+
#
|
58
|
+
# Each member of the _items_ Array is passed through ERb and thus can
|
59
|
+
# contain their own expansions. Color escape expansions do not contribute to
|
60
|
+
# the final field width.
|
61
|
+
|
62
|
+
def initialize(items, mode = :rows, option = nil, highline)
|
63
|
+
@highline = highline
|
64
|
+
@mode = mode
|
65
|
+
@option = option
|
66
|
+
@items = render_list_items(items)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Render the list using the appropriate mode and options.
|
70
|
+
# @return [String] rendered list as String
|
71
|
+
def render
|
72
|
+
return "" if items.empty?
|
73
|
+
|
74
|
+
case mode
|
75
|
+
when :inline
|
76
|
+
list_inline_mode
|
77
|
+
when :columns_across
|
78
|
+
list_columns_across_mode
|
79
|
+
when :columns_down
|
80
|
+
list_columns_down_mode
|
81
|
+
when :uneven_columns_across
|
82
|
+
list_uneven_columns_mode
|
83
|
+
when :uneven_columns_down
|
84
|
+
list_uneven_columns_down_mode
|
85
|
+
else
|
86
|
+
list_default_mode
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def render_list_items(items)
|
93
|
+
items.to_ary.map do |item|
|
94
|
+
item = String(item)
|
95
|
+
template = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
|
96
|
+
ERB.new(item, trim_mode: "%")
|
97
|
+
else
|
98
|
+
ERB.new(item, nil, "%")
|
99
|
+
end
|
100
|
+
template_renderer =
|
101
|
+
HighLine::TemplateRenderer.new(template, self, highline)
|
102
|
+
template_renderer.render
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def list_default_mode
|
107
|
+
items.map { |i| "#{i}\n" }.join
|
108
|
+
end
|
109
|
+
|
110
|
+
def list_inline_mode
|
111
|
+
end_separator = option || " or "
|
112
|
+
|
113
|
+
if items.size == 1
|
114
|
+
items.first
|
115
|
+
else
|
116
|
+
items[0..-2].join(", ") + "#{end_separator}#{items.last}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def list_columns_across_mode
|
121
|
+
HighLine::List.new(right_padded_items, cols: col_count).to_s
|
122
|
+
end
|
123
|
+
|
124
|
+
def list_columns_down_mode
|
125
|
+
HighLine::List.new(
|
126
|
+
right_padded_items,
|
127
|
+
cols: col_count,
|
128
|
+
col_down: true
|
129
|
+
).to_s
|
130
|
+
end
|
131
|
+
|
132
|
+
def list_uneven_columns_mode(list = nil)
|
133
|
+
list ||= HighLine::List.new(items)
|
134
|
+
|
135
|
+
col_max = option || items.size
|
136
|
+
col_max.downto(1) do |column_count|
|
137
|
+
list.cols = column_count
|
138
|
+
widths = get_col_widths(list)
|
139
|
+
|
140
|
+
if column_count == 1 || # last guess
|
141
|
+
inside_line_size_limit?(widths) || # good guess
|
142
|
+
option # defined by user
|
143
|
+
return pad_uneven_rows(list, widths)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def list_uneven_columns_down_mode
|
149
|
+
list = HighLine::List.new(items, col_down: true)
|
150
|
+
list_uneven_columns_mode(list)
|
151
|
+
end
|
152
|
+
|
153
|
+
def pad_uneven_rows(list, widths)
|
154
|
+
right_padded_list = Array(list).map do |row|
|
155
|
+
right_pad_row(row.compact, widths)
|
156
|
+
end
|
157
|
+
stringfy_list(right_padded_list)
|
158
|
+
end
|
159
|
+
|
160
|
+
def stringfy_list(list)
|
161
|
+
list.map { |row| row_to_s(row) }.join
|
162
|
+
end
|
163
|
+
|
164
|
+
def row_to_s(row)
|
165
|
+
row.compact.join(row_join_string) + "\n"
|
166
|
+
end
|
167
|
+
|
168
|
+
def right_pad_row(row, widths)
|
169
|
+
row.zip(widths).map do |field, width|
|
170
|
+
right_pad_field(field, width)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def right_pad_field(field, width)
|
175
|
+
field = String(field) # nil protection
|
176
|
+
pad_size = width - actual_length(field)
|
177
|
+
field + (pad_char * pad_size)
|
178
|
+
end
|
179
|
+
|
180
|
+
def get_col_widths(lines)
|
181
|
+
lines = transpose(lines)
|
182
|
+
get_segment_widths(lines)
|
183
|
+
end
|
184
|
+
|
185
|
+
def get_row_widths(lines)
|
186
|
+
get_segment_widths(lines)
|
187
|
+
end
|
188
|
+
|
189
|
+
def get_segment_widths(lines)
|
190
|
+
lines.map do |col|
|
191
|
+
actual_lengths_for(col).max
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def actual_lengths_for(line)
|
196
|
+
line.map do |item|
|
197
|
+
actual_length(item)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def transpose(lines)
|
202
|
+
lines = Array(lines)
|
203
|
+
first_line = lines.shift
|
204
|
+
first_line.zip(*lines)
|
205
|
+
end
|
206
|
+
|
207
|
+
def inside_line_size_limit?(widths)
|
208
|
+
line_size = widths.reduce(0) { |sum, n| sum + n + row_join_str_size }
|
209
|
+
line_size <= line_size_limit + row_join_str_size
|
210
|
+
end
|
211
|
+
|
212
|
+
def actual_length(text)
|
213
|
+
HighLine::Wrapper.actual_length text
|
214
|
+
end
|
215
|
+
|
216
|
+
def items_max_length
|
217
|
+
@items_max_length ||= max_length(items)
|
218
|
+
end
|
219
|
+
|
220
|
+
def max_length(items)
|
221
|
+
items.map { |item| actual_length(item) }.max
|
222
|
+
end
|
223
|
+
|
224
|
+
def line_size_limit
|
225
|
+
@line_size_limit ||= (highline.wrap_at || 80)
|
226
|
+
end
|
227
|
+
|
228
|
+
def row_join_string
|
229
|
+
@row_join_string ||= " "
|
230
|
+
end
|
231
|
+
|
232
|
+
attr_writer :row_join_string
|
233
|
+
|
234
|
+
def row_join_str_size
|
235
|
+
row_join_string.size
|
236
|
+
end
|
237
|
+
|
238
|
+
def col_count_calculate
|
239
|
+
(line_size_limit + row_join_str_size) /
|
240
|
+
(items_max_length + row_join_str_size)
|
241
|
+
end
|
242
|
+
|
243
|
+
def col_count
|
244
|
+
option || col_count_calculate
|
245
|
+
end
|
246
|
+
|
247
|
+
def right_padded_items
|
248
|
+
items.map do |item|
|
249
|
+
right_pad_field(item, items_max_length)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def pad_char
|
254
|
+
" "
|
255
|
+
end
|
256
|
+
|
257
|
+
def row_count
|
258
|
+
(items.count / col_count.to_f).ceil
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class HighLine
|
4
|
+
class Menu < Question
|
5
|
+
# Represents an Item of a HighLine::Menu.
|
6
|
+
#
|
7
|
+
class Item
|
8
|
+
attr_reader :name, :text, :help, :action
|
9
|
+
|
10
|
+
#
|
11
|
+
# @param name [String] The name that is matched against the user input
|
12
|
+
# @param attributes [Hash] options Hash to tailor menu item to your needs
|
13
|
+
# @option attributes text: [String] The text that displays for that
|
14
|
+
# choice (defaults to name)
|
15
|
+
# @option attributes help: [String] help/hint string to be displayed.
|
16
|
+
# @option attributes action: [Block] a block that gets called when choice
|
17
|
+
# is selected
|
18
|
+
#
|
19
|
+
def initialize(name, attributes)
|
20
|
+
@name = name
|
21
|
+
@text = attributes[:text] || @name
|
22
|
+
@help = attributes[:help]
|
23
|
+
@action = attributes[:action]
|
24
|
+
end
|
25
|
+
|
26
|
+
def item_help
|
27
|
+
return {} unless help
|
28
|
+
{ name.to_s.downcase => help }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|