highline 1.7.10 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
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