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.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +5 -0
  3. data/.rubocop.yml +84 -0
  4. data/.simplecov +5 -0
  5. data/.travis.yml +35 -9
  6. data/Changelog.md +214 -15
  7. data/Gemfile +16 -5
  8. data/README.md +202 -0
  9. data/Rakefile +8 -20
  10. data/appveyor.yml +37 -0
  11. data/examples/ansi_colors.rb +6 -11
  12. data/examples/asking_for_arrays.rb +6 -2
  13. data/examples/basic_usage.rb +31 -21
  14. data/examples/color_scheme.rb +11 -10
  15. data/examples/get_character.rb +8 -4
  16. data/examples/limit.rb +4 -0
  17. data/examples/menus.rb +16 -10
  18. data/examples/overwrite.rb +9 -5
  19. data/examples/page_and_wrap.rb +5 -4
  20. data/examples/password.rb +4 -0
  21. data/examples/repeat_entry.rb +10 -5
  22. data/examples/trapping_eof.rb +2 -1
  23. data/examples/using_readline.rb +2 -1
  24. data/highline.gemspec +25 -27
  25. data/lib/highline/builtin_styles.rb +129 -0
  26. data/lib/highline/color_scheme.rb +49 -32
  27. data/lib/highline/compatibility.rb +11 -4
  28. data/lib/highline/custom_errors.rb +57 -0
  29. data/lib/highline/import.rb +19 -12
  30. data/lib/highline/io_console_compatible.rb +37 -0
  31. data/lib/highline/list.rb +177 -0
  32. data/lib/highline/list_renderer.rb +261 -0
  33. data/lib/highline/menu/item.rb +32 -0
  34. data/lib/highline/menu.rb +306 -111
  35. data/lib/highline/paginator.rb +52 -0
  36. data/lib/highline/question/answer_converter.rb +103 -0
  37. data/lib/highline/question.rb +281 -131
  38. data/lib/highline/question_asker.rb +150 -0
  39. data/lib/highline/simulate.rb +24 -13
  40. data/lib/highline/statement.rb +88 -0
  41. data/lib/highline/string.rb +36 -0
  42. data/lib/highline/string_extensions.rb +83 -64
  43. data/lib/highline/style.rb +196 -63
  44. data/lib/highline/template_renderer.rb +62 -0
  45. data/lib/highline/terminal/io_console.rb +36 -0
  46. data/lib/highline/terminal/ncurses.rb +38 -0
  47. data/lib/highline/terminal/unix_stty.rb +51 -0
  48. data/lib/highline/terminal.rb +190 -0
  49. data/lib/highline/version.rb +3 -1
  50. data/lib/highline/wrapper.rb +53 -0
  51. data/lib/highline.rb +390 -788
  52. metadata +56 -35
  53. data/INSTALL +0 -59
  54. data/README.rdoc +0 -74
  55. data/lib/highline/system_extensions.rb +0 -254
  56. data/setup.rb +0 -1360
  57. data/test/string_methods.rb +0 -32
  58. data/test/tc_color_scheme.rb +0 -96
  59. data/test/tc_highline.rb +0 -1402
  60. data/test/tc_import.rb +0 -52
  61. data/test/tc_menu.rb +0 -439
  62. data/test/tc_simulator.rb +0 -33
  63. data/test/tc_string_extension.rb +0 -33
  64. data/test/tc_string_highline.rb +0 -38
  65. 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