tty 0.0.6 → 0.0.7

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 (81) hide show
  1. data/README.md +78 -12
  2. data/benchmarks/shell.rb +26 -0
  3. data/benchmarks/table.rb +35 -0
  4. data/lib/tty.rb +23 -1
  5. data/lib/tty/coercer.rb +13 -0
  6. data/lib/tty/coercer/boolean.rb +39 -0
  7. data/lib/tty/coercer/float.rb +23 -0
  8. data/lib/tty/coercer/integer.rb +23 -0
  9. data/lib/tty/coercer/range.rb +33 -0
  10. data/lib/tty/shell.rb +6 -2
  11. data/lib/tty/shell/question.rb +158 -138
  12. data/lib/tty/shell/reader.rb +92 -0
  13. data/lib/tty/shell/response.rb +219 -0
  14. data/lib/tty/shell/response_delegation.rb +53 -0
  15. data/lib/tty/table.rb +90 -16
  16. data/lib/tty/table/border.rb +34 -8
  17. data/lib/tty/table/border/ascii.rb +16 -25
  18. data/lib/tty/table/border/null.rb +0 -6
  19. data/lib/tty/table/border/unicode.rb +16 -25
  20. data/lib/tty/table/column_set.rb +1 -1
  21. data/lib/tty/table/error.rb +10 -0
  22. data/lib/tty/table/operation/wrapped.rb +0 -6
  23. data/lib/tty/table/orientation.rb +57 -0
  24. data/lib/tty/table/orientation/horizontal.rb +19 -0
  25. data/lib/tty/table/orientation/vertical.rb +19 -0
  26. data/lib/tty/table/renderer.rb +7 -0
  27. data/lib/tty/table/renderer/ascii.rb +1 -1
  28. data/lib/tty/table/renderer/basic.rb +2 -2
  29. data/lib/tty/table/renderer/unicode.rb +1 -1
  30. data/lib/tty/table/validatable.rb +20 -0
  31. data/lib/tty/terminal.rb +15 -14
  32. data/lib/tty/terminal/color.rb +1 -1
  33. data/lib/tty/terminal/echo.rb +41 -0
  34. data/lib/tty/terminal/home.rb +31 -0
  35. data/lib/tty/text.rb +85 -0
  36. data/lib/tty/text/truncation.rb +83 -0
  37. data/lib/tty/text/wrapping.rb +96 -0
  38. data/lib/tty/version.rb +1 -1
  39. data/spec/tty/coercer/boolean/coerce_spec.rb +113 -0
  40. data/spec/tty/coercer/float/coerce_spec.rb +32 -0
  41. data/spec/tty/coercer/integer/coerce_spec.rb +39 -0
  42. data/spec/tty/coercer/range/coerce_spec.rb +73 -0
  43. data/spec/tty/shell/ask_spec.rb +14 -1
  44. data/spec/tty/shell/question/argument_spec.rb +30 -0
  45. data/spec/tty/shell/question/character_spec.rb +16 -0
  46. data/spec/tty/shell/question/default_spec.rb +25 -0
  47. data/spec/tty/shell/question/in_spec.rb +23 -0
  48. data/spec/tty/shell/question/initialize_spec.rb +11 -211
  49. data/spec/tty/shell/question/modifier/whitespace_spec.rb +1 -1
  50. data/spec/tty/shell/question/modify_spec.rb +44 -0
  51. data/spec/tty/shell/question/valid_spec.rb +46 -0
  52. data/spec/tty/shell/question/validate_spec.rb +30 -0
  53. data/spec/tty/shell/reader/getc_spec.rb +40 -0
  54. data/spec/tty/shell/response/read_bool_spec.rb +41 -0
  55. data/spec/tty/shell/response/read_char_spec.rb +17 -0
  56. data/spec/tty/shell/response/read_date_spec.rb +20 -0
  57. data/spec/tty/shell/response/read_email_spec.rb +43 -0
  58. data/spec/tty/shell/response/read_multiple_spec.rb +24 -0
  59. data/spec/tty/shell/response/read_number_spec.rb +29 -0
  60. data/spec/tty/shell/response/read_range_spec.rb +29 -0
  61. data/spec/tty/shell/response/read_spec.rb +68 -0
  62. data/spec/tty/shell/response/read_string_spec.rb +19 -0
  63. data/spec/tty/table/access_spec.rb +6 -0
  64. data/spec/tty/table/border/new_spec.rb +3 -3
  65. data/spec/tty/table/initialize_spec.rb +17 -1
  66. data/spec/tty/table/options_spec.rb +7 -1
  67. data/spec/tty/table/orientation_spec.rb +98 -0
  68. data/spec/tty/table/renders_with_spec.rb +76 -0
  69. data/spec/tty/table/rotate_spec.rb +72 -0
  70. data/spec/tty/table/to_s_spec.rb +13 -1
  71. data/spec/tty/table/validatable/validate_options_spec.rb +34 -0
  72. data/spec/tty/terminal/color/remove_spec.rb +34 -1
  73. data/spec/tty/terminal/echo_spec.rb +22 -0
  74. data/spec/tty/text/truncate_spec.rb +13 -0
  75. data/spec/tty/text/truncation/initialize_spec.rb +29 -0
  76. data/spec/tty/text/truncation/truncate_spec.rb +73 -0
  77. data/spec/tty/text/wrap_spec.rb +14 -0
  78. data/spec/tty/text/wrapping/initialize_spec.rb +25 -0
  79. data/spec/tty/text/wrapping/wrap_spec.rb +80 -0
  80. data/tty.gemspec +1 -0
  81. metadata +101 -8
@@ -7,8 +7,6 @@ module TTY
7
7
  class Border
8
8
  include Unicode
9
9
 
10
- NEWLINE = "\n"
11
-
12
10
  # The row cell widths
13
11
  #
14
12
  # @api private
@@ -21,26 +19,53 @@ module TTY
21
19
  attr_reader :row
22
20
  private :row
23
21
 
22
+ class << self
23
+ # Store characters for border
24
+ #
25
+ # @api private
26
+ attr_accessor :characters
27
+ end
28
+
24
29
  # Instantiate a new object
25
30
  #
26
31
  # @return [Object]
27
32
  #
28
33
  # @api private
29
- def initialize(*)
34
+ def initialize(row=nil)
30
35
  if self.class == Border
31
36
  raise NotImplementedError, "#{self} is an abstract class"
32
37
  else
33
- super
38
+ @row = row
39
+ @widths = row.map { |cell| cell.chars.to_a.size }
34
40
  end
35
41
  end
36
42
 
43
+ # Define border characters
44
+ #
45
+ # @api public
46
+ def self.def_border(&block)
47
+ @characters = block
48
+ end
49
+
50
+ # Retrive individula character by type
51
+ #
52
+ # @param [String] type
53
+ # the character type
54
+ #
55
+ # @return [String]
56
+ #
57
+ # @api private
58
+ def [](type)
59
+ self.class.characters.call[type] || ''
60
+ end
61
+
37
62
  # A line spanning all columns marking top of a table.
38
63
  #
39
64
  # @return [String]
40
65
  #
41
66
  # @api private
42
67
  def top_line
43
- render :top
68
+ (result = render(:top)).empty? ? nil : result
44
69
  end
45
70
 
46
71
  # A line spanning all columns delemeting rows in a table.
@@ -49,7 +74,7 @@ module TTY
49
74
  #
50
75
  # @api private
51
76
  def separator
52
- render :mid
77
+ (result = render(:mid)).empty? ? nil : result
53
78
  end
54
79
 
55
80
  # A line spanning all columns delemeting cells in a row.
@@ -58,7 +83,8 @@ module TTY
58
83
  #
59
84
  # @api private
60
85
  def row_line
61
- self['left'] + row.join(self['right']) + self['right']
86
+ result = self['left'] + row.join(self['right']) + self['right']
87
+ result.empty? ? nil : result
62
88
  end
63
89
 
64
90
  # A line spannig all columns marking bottom of a table.
@@ -67,7 +93,7 @@ module TTY
67
93
  #
68
94
  # @api private
69
95
  def bottom_line
70
- render :bottom
96
+ (result = render(:bottom)).empty? ? nil : result
71
97
  end
72
98
 
73
99
  protected
@@ -7,32 +7,23 @@ module TTY
7
7
  # A class that represents an ascii border.
8
8
  class ASCII < Border
9
9
 
10
- BORDER_TYPE = {
11
- 'top' => '-',
12
- 'top_mid' => '+',
13
- 'top_left' => '+',
14
- 'top_right' => '+',
15
- 'bottom' => '-',
16
- 'bottom_mid' => '+',
17
- 'bottom_left' => '+',
18
- 'bottom_right' => '+',
19
- 'mid' => '-',
20
- 'mid_mid' => '+',
21
- 'mid_left' => '+',
22
- 'mid_right' => '+',
23
- 'left' => '|',
24
- 'right' => '|'
10
+ def_border do
11
+ {
12
+ 'top' => '-',
13
+ 'top_mid' => '+',
14
+ 'top_left' => '+',
15
+ 'top_right' => '+',
16
+ 'bottom' => '-',
17
+ 'bottom_mid' => '+',
18
+ 'bottom_left' => '+',
19
+ 'bottom_right' => '+',
20
+ 'mid' => '-',
21
+ 'mid_mid' => '+',
22
+ 'mid_left' => '+',
23
+ 'mid_right' => '+',
24
+ 'left' => '|',
25
+ 'right' => '|'
25
26
  }
26
-
27
- # @api private
28
- def [](type)
29
- BORDER_TYPE[type]
30
- end
31
-
32
- # @api private
33
- def initialize(row)
34
- @row = row
35
- @widths = row.map { |cell| cell.chars.to_a.size }
36
27
  end
37
28
 
38
29
  end # ASCII
@@ -7,12 +7,6 @@ module TTY
7
7
  # A class that represents no border.
8
8
  class Null < Border
9
9
 
10
- # @api private
11
- def initialize(row)
12
- @row = row
13
- @widths = row.map { |cell| cell.chars.to_a.size }
14
- end
15
-
16
10
  # A stub top line
17
11
  #
18
12
  # @api private
@@ -7,32 +7,23 @@ module TTY
7
7
  # A class that represents a unicode border.
8
8
  class Unicode < Border
9
9
 
10
- BORDER_TYPE = {
11
- 'top' => '─',
12
- 'top_mid' => '',
13
- 'top_left' => '',
14
- 'top_right' => '',
15
- 'bottom' => '',
16
- 'bottom_mid' => '',
17
- 'bottom_left' => '',
18
- 'bottom_right' => '',
19
- 'mid' => '',
20
- 'mid_mid' => '',
21
- 'mid_left' => '',
22
- 'mid_right' => '',
23
- 'left' => '',
24
- 'right' => '│'
10
+ def_border do
11
+ {
12
+ 'top' => '',
13
+ 'top_mid' => '',
14
+ 'top_left' => '',
15
+ 'top_right' => '',
16
+ 'bottom' => '',
17
+ 'bottom_mid' => '',
18
+ 'bottom_left' => '',
19
+ 'bottom_right' => '',
20
+ 'mid' => '',
21
+ 'mid_mid' => '',
22
+ 'mid_left' => '',
23
+ 'mid_right' => '',
24
+ 'left' => '│',
25
+ 'right' => '│'
25
26
  }
26
-
27
- # @api private
28
- def [](type)
29
- BORDER_TYPE[type]
30
- end
31
-
32
- # @api private
33
- def initialize(row)
34
- @row = row
35
- @widths = row.map { |cell| cell.chars.to_a.size }
36
27
  end
37
28
 
38
29
  end # Unicode
@@ -31,7 +31,7 @@ module TTY
31
31
  #
32
32
  # @api private
33
33
  def extract_widths!
34
- return column_widths unless column_widths.empty?
34
+ return column_widths if (column_widths && !column_widths.empty?)
35
35
 
36
36
  rows = table.to_a
37
37
  data = table.header ? rows + [table.header] : rows
@@ -6,5 +6,15 @@ module TTY
6
6
  # Raised when inserting into table with a mismatching row(s)
7
7
  class DimensionMismatchError < ArgumentError; end
8
8
 
9
+ # Raised when reading non-existent element from a table
10
+ class TupleMissing < IndexError
11
+ attr_reader :i, :j
12
+
13
+ def initialize(i, j)
14
+ @i, @j = i, j
15
+ super("element at(#{i},#{j}) not found")
16
+ end
17
+ end
18
+
9
19
  end # Table
10
20
  end # TTY
@@ -27,12 +27,6 @@ module TTY
27
27
  end
28
28
  end
29
29
 
30
- private
31
-
32
- def actual_length(string)
33
- string.to_s.gsub(/\e\[\d{1,2}m/, '').length
34
- end
35
-
36
30
  end # Wrapped
37
31
  end # Operation
38
32
  end # Table
@@ -0,0 +1,57 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Table
5
+
6
+ # A class representing table orientation
7
+ class Orientation
8
+
9
+ # The name for the orientation
10
+ #
11
+ # @api public
12
+ attr_reader :name
13
+
14
+ # Initialize an Orientation
15
+ #
16
+ # @api public
17
+ def initialize(name)
18
+ @name = name
19
+ end
20
+
21
+ # Coerce the name argument into an orientation
22
+ #
23
+ # @param [Symbol] name
24
+ #
25
+ # @api public
26
+ def self.coerce(name)
27
+ case name.to_s
28
+ when /h|horiz(ontal)?/i
29
+ Horizontal.new :horizontal
30
+ when /v|ert(ical)?/i
31
+ Vertical.new :vertical
32
+ else
33
+ raise InvalidOrientationError, "orientation must be one of :horizontal, :vertical"
34
+ end
35
+ end
36
+
37
+ # Check if orientation is vertical
38
+ #
39
+ # @return [Boolean]
40
+ #
41
+ # @api public
42
+ def vertical?
43
+ name == :vertical
44
+ end
45
+
46
+ # Check if orientation is horizontal
47
+ #
48
+ # @return [Boolean]
49
+ #
50
+ # @api public
51
+ def horizontal?
52
+ name == :horizontal
53
+ end
54
+
55
+ end # Orientation
56
+ end # Table
57
+ end # TTY
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Table
5
+
6
+ # A class representing table orientation
7
+ class Orientation
8
+
9
+ class Horizontal < Orientation
10
+
11
+ def transform(table)
12
+ table.rotate_horizontal
13
+ end
14
+
15
+ end # Horizontal
16
+
17
+ end # Orientation
18
+ end # Table
19
+ end # TTY
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Table
5
+
6
+ # A class representing table orientation
7
+ class Orientation
8
+
9
+ class Vertical < Orientation
10
+
11
+ def transform(table)
12
+ table.rotate_vertical
13
+ end
14
+
15
+ end # Vertical
16
+
17
+ end # Orientation
18
+ end # Table
19
+ end # TTY
@@ -80,6 +80,13 @@ module TTY
80
80
  @renderer = renderer
81
81
  end
82
82
 
83
+ # Add custom border for the renderer
84
+ #
85
+ # @api public
86
+ def renders_with(klass)
87
+ @border_class = klass
88
+ end
89
+
83
90
  delegatable_method :renderer, *RENDERER_DELEGATED_METHODS
84
91
 
85
92
  end # Renderer
@@ -5,7 +5,7 @@ module TTY
5
5
  module Renderer
6
6
  class ASCII < Basic
7
7
 
8
- def render(table, border=nil)
8
+ def render(table)
9
9
  super table, TTY::Table::Border::ASCII
10
10
  end
11
11
 
@@ -87,7 +87,7 @@ module TTY
87
87
  # @api public
88
88
  def render(table, border_class=Border::Null)
89
89
  @table = table
90
- @border_class = border_class
90
+ @border_class = table.border_class || border_class
91
91
 
92
92
  return if table.to_a.empty?
93
93
  # setup(options)
@@ -113,7 +113,7 @@ module TTY
113
113
  # @api private
114
114
  def render_header
115
115
  header = table.header
116
- if header
116
+ if header && !header.empty?
117
117
  aligned = alignments.align_header header,
118
118
  :column_widths => column_widths
119
119
  border = border_class.new(aligned)
@@ -5,7 +5,7 @@ module TTY
5
5
  module Renderer
6
6
  class Unicode < Basic
7
7
 
8
- def render(table, border=nil)
8
+ def render(table)
9
9
  super table, TTY::Table::Border::Unicode
10
10
  end
11
11
 
@@ -29,6 +29,26 @@ module TTY
29
29
  def assert_string_values(rows)
30
30
  end
31
31
 
32
+ # Check if options are of required type
33
+ #
34
+ # @api private
35
+ def validate_options!(options)
36
+ if (header = options[:header]) &&
37
+ (!header.kind_of?(Array) || header.empty?)
38
+ raise InvalidArgument, ":header must be a non-empty array"
39
+ end
40
+
41
+ if (rows = options[:rows]) &&
42
+ !(rows.kind_of?(Array) || rows.kind_of?(Hash))
43
+ raise InvalidArgument, ":rows must be a non-empty array or hash"
44
+ end
45
+
46
+ if (column_widths = options[:column_widths]) &&
47
+ (!column_widths.kind_of?(Array) || column_widths.empty?)
48
+ raise InvalidArgument, ":column_widths must be a non-empty array"
49
+ end
50
+ end
51
+
32
52
  end # Validatable
33
53
  end # Table
34
54
  end # TTY
@@ -28,6 +28,7 @@ module TTY
28
28
 
29
29
  def initialize
30
30
  @color = TTY::Terminal::Color.new(self.color?)
31
+ @echo = TTY::Terminal::Echo.new
31
32
  @default_width = 80
32
33
  @default_height = 24
33
34
  end
@@ -148,26 +149,26 @@ module TTY
148
149
  %x{tput colors 2>/dev/null}.to_i > 2
149
150
  end
150
151
 
152
+ def echo_on
153
+ @echo.on
154
+ end
155
+
156
+ def echo_off
157
+ @echo.off
158
+ end
159
+
160
+ # @api public
161
+ def echo(is_on=true, &block)
162
+ @echo.echo(is_on, &block)
163
+ end
164
+
151
165
  # Find user home directory
152
166
  #
153
167
  # @return [String]
154
168
  #
155
169
  # @api public
156
170
  def home
157
- @home ||= if (env_home = ENV['HOME'])
158
- env_home
159
- else
160
- begin
161
- require 'etc'
162
- File.expand_path("~#{Etc.getlogin}")
163
- rescue
164
- if TTY::System.windows?
165
- "C:/"
166
- else
167
- "/"
168
- end
169
- end
170
- end
171
+ @home ||= Home.new.home
171
172
  end
172
173
 
173
174
  end # Terminal