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
@@ -98,7 +98,7 @@ module TTY
98
98
  #
99
99
  # @api public
100
100
  def remove(string)
101
- string.gsub(/\e\[\d+(;\d+)*m/, '')
101
+ string.to_s.gsub(/(\[)?\033(\[)?[;?\d]*[\dA-Za-z](\])?/, '')
102
102
  end
103
103
 
104
104
  # Return raw color code without embeding it into a string.
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Terminal
5
+
6
+ # A class responsible for toggling echo.
7
+ class Echo
8
+
9
+ # Turn echo on
10
+ #
11
+ # @api public
12
+ def on
13
+ %x{stty echo} if TTY::System.unix?
14
+ end
15
+
16
+ # Turn echo off
17
+ #
18
+ # @api public
19
+ def off
20
+ %x{stty -echo} if TTY::System.unix?
21
+ end
22
+
23
+ # Wrap code block inside echo
24
+ #
25
+ # @api public
26
+ def echo(is_on=true, &block)
27
+ value = nil
28
+ begin
29
+ self.off unless is_on
30
+ value = block.call if block_given?
31
+ self.on
32
+ return value
33
+ rescue NoMethodError, Interrupt => e
34
+ self.on
35
+ exit
36
+ end
37
+ end
38
+
39
+ end # Echo
40
+ end # Terminal
41
+ end # TTY
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Terminal
5
+
6
+ # A class responsible for locating user home
7
+ class Home
8
+
9
+ # Find user home
10
+ #
11
+ # @api public
12
+ def home
13
+ if (env_home = ENV['HOME'])
14
+ env_home
15
+ else
16
+ begin
17
+ require 'etc'
18
+ File.expand_path("~#{Etc.getlogin}")
19
+ rescue
20
+ if TTY::System.windows?
21
+ "C:/"
22
+ else
23
+ "/"
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ end #Home
30
+ end # Terminal
31
+ end # TTY
@@ -0,0 +1,85 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+
5
+ # A class responsible for text manipulations
6
+ class Text
7
+
8
+ SPACE = " ".freeze
9
+
10
+ NEWLINE = "\n".freeze
11
+
12
+ DEFAULT_WIDTH = 80.freeze
13
+
14
+ # Specifies the split mode for words
15
+ def split_mode
16
+ end
17
+
18
+ # Wrap a text into lines no longer than provided length
19
+ #
20
+ # @param [String] text
21
+ # the text to be wrapped
22
+ #
23
+ # @overload wrap(text, value)
24
+ # wraps text at given value
25
+ #
26
+ # @param [Integer] value
27
+ #
28
+ # @overload wrap(text, value, options)
29
+ # @param [Integer] value
30
+ # @param [Hash] options
31
+ # @option options [Symbol] :indent the indentation
32
+ #
33
+ # @example
34
+ # wrap("Some longish text", 8)
35
+ # # => "Some\nlongish\ntext"
36
+ #
37
+ # wrap("Some longish text", :length => 8)
38
+ # # => "Some\nlongish\ntext"
39
+ #
40
+ # wrap("Some longish text", 8, :indent => 4)
41
+ # # => > Some
42
+ # > longish
43
+ # > text
44
+ #
45
+ # @api public
46
+ def self.wrap(text, *args)
47
+ Wrapping.new(text, *args).wrap
48
+ end
49
+
50
+ # Truncate a text at a given length (defaults to 30)
51
+ #
52
+ # @param [String] text
53
+ # the text to be truncated
54
+ #
55
+ # @overload truncate(text, value)
56
+ # truncates text at given value
57
+ #
58
+ # @param [Integer] value
59
+ #
60
+ # @overload truncate(text, value, options)
61
+ # @param [Integer] value
62
+ # @param [Hash] options
63
+ # @option options [Symbol] :separator the separation character
64
+ # @option options [Symbol] :trailing the trailing characters
65
+ #
66
+ # @example
67
+ # truncate("The sovereignest thing on earth is parmacetti for an inward bruise.")
68
+ # # => "The sovereignest thing on ear…"
69
+ #
70
+ # truncate("The sovereignest thing on earth is parmacetti for an inward bruise.", length: 20)
71
+ # # => "The sovereignest th…"
72
+ #
73
+ # truncate("The sovereignest thing on earth is parmacetti for an inward bruise.", length: 20, separator: ' ' )
74
+ # # => "The sovereignest…"
75
+ #
76
+ # truncate("The sovereignest thing on earth is parmacetti for an inward bruise.", length: 40, trailing: '... (see more)' )
77
+ # # => "The sovereignest thing on... (see more)"
78
+ #
79
+ # @api public
80
+ def self.truncate(text, *args)
81
+ Truncation.new(text, *args).truncate
82
+ end
83
+
84
+ end # Text
85
+ end # TTY
@@ -0,0 +1,83 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Text
5
+
6
+ # A class responsible for text truncation operations
7
+ class Truncation
8
+ include Unicode
9
+
10
+ DEFAULT_TRAILING = '…'.freeze
11
+
12
+ DEFAULT_TRUNCATION_LENGTH = 30.freeze
13
+
14
+ attr_reader :text
15
+
16
+ attr_reader :length
17
+
18
+ attr_reader :separator
19
+
20
+ attr_reader :trailing
21
+
22
+ # Initialize a Truncation
23
+ #
24
+ # @param [String] text
25
+ # the text to be truncated
26
+ #
27
+ # @overload new(text, value)
28
+ # truncates text at given value
29
+ #
30
+ # @param [Integer] value
31
+ #
32
+ # @overload new(text, value, options)
33
+ # @param [Integer] value
34
+ #
35
+ # @param [Hash] options
36
+ # @option options [Symbol] :length the desired length
37
+ # @option options [Symbol] :separator the character for splitting words
38
+ # @option options [Symbol] :trailing the character for ending sentence
39
+ #
40
+ # @api private
41
+ def initialize(text, *args)
42
+ options = Utils.extract_options!(args)
43
+ @text = text
44
+ @length = options.fetch(:length) { DEFAULT_TRUNCATION_LENGTH }
45
+ @length = args[0] unless args.empty?
46
+ @separator = options.fetch(:separator) { nil }
47
+ @trailing = options.fetch(:trailing) { DEFAULT_TRAILING }
48
+ end
49
+
50
+ # Truncate a text
51
+ #
52
+ # @see TTY::Text.truncate
53
+ #
54
+ # @api private
55
+ def truncate
56
+ return text unless length && length > 0
57
+
58
+ as_unicode do
59
+ chars = text.chars.to_a
60
+ return chars.join if chars.length < length
61
+ stop = chars[0, length_without_trailing].rindex(separator)
62
+
63
+ chars[0, stop || length_without_trailing].join + trailing
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ # Leave space for the trailing characters
70
+ #
71
+ # @return [Integer]
72
+ #
73
+ # @api private
74
+ def length_without_trailing
75
+ as_unicode do
76
+ trailing_size = trailing.chars.to_a.size
77
+ length - trailing_size
78
+ end
79
+ end
80
+
81
+ end # Truncation
82
+ end # Text
83
+ end # TTY
@@ -0,0 +1,96 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Text
5
+
6
+ # A class responsible for text wrapping operations
7
+ class Wrapping
8
+ include Unicode
9
+
10
+ attr_reader :text
11
+
12
+ attr_reader :length
13
+
14
+ attr_reader :indent
15
+
16
+ # Initialize a Wrapping
17
+ #
18
+ # @param [String] text
19
+ # the text to be wrapped
20
+ #
21
+ # @overload new(text, value)
22
+ # wraps text at given value
23
+ #
24
+ # @param [Integer] value
25
+ #
26
+ # @overload new(text, value, options)
27
+ # @param [Integer] value
28
+ # @param [Hash] options
29
+ # @option options [Symbol] :indent the indentation
30
+ # @option options [Symbol] :length the desired length
31
+ #
32
+ # @api private
33
+ def initialize(text, *args)
34
+ options = Utils.extract_options!(args)
35
+ @text = text
36
+ @length = options.fetch(:length) { DEFAULT_WIDTH }
37
+ @indent = options.fetch(:indent) { 0 }
38
+ @length = args[0] unless args.empty?
39
+ end
40
+
41
+ # Wrap a text into lines no longer than length
42
+ #
43
+ # @see TTY::Text#wrap
44
+ #
45
+ # @api private
46
+ def wrap
47
+ return text unless length && length > 0
48
+
49
+ as_unicode do
50
+ text.split(NEWLINE).map do |line|
51
+ modified_line = wrap_line line
52
+ indent_line modified_line
53
+ end * NEWLINE
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ # Calculate string length without color escapes
60
+ #
61
+ # @param [String] string
62
+ #
63
+ # @api private
64
+ def actual_length(string)
65
+ length + (string.length - TTY.terminal.color.remove(string).length)
66
+ end
67
+
68
+ # Wrap line at given length
69
+ #
70
+ # @param [String] line
71
+ #
72
+ # @return [String]
73
+ #
74
+ # @api private
75
+ def wrap_line(line)
76
+ wrap_at = actual_length line
77
+ line.strip.gsub(/\n/,' ').squeeze(' ').
78
+ gsub(/(.{1,#{wrap_at}})(?:\s+|$\n?)|(.{1,#{wrap_at}})/, "\\1\\2\n").strip
79
+ end
80
+
81
+ # Indent string by given value
82
+ #
83
+ # @param [String] text
84
+ #
85
+ # @return [String]
86
+ #
87
+ # @api private
88
+ def indent_line(text)
89
+ text.split(NEWLINE).each do |line|
90
+ line.insert(0, SPACE * indent)
91
+ end
92
+ end
93
+
94
+ end # Wrapping
95
+ end # Text
96
+ end # TTY
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  module TTY
4
- VERSION = "0.0.6"
4
+ VERSION = "0.0.7"
5
5
  end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ describe TTY::Coercer::Boolean, '#coerce' do
4
+ subject { described_class.coerce(value) }
5
+
6
+ context "with empty" do
7
+ let(:value) { '' }
8
+
9
+ it { expect { subject }.to raise_error(TTY::TypeError) }
10
+ end
11
+
12
+ context "with true" do
13
+ let(:value) { true }
14
+
15
+ it { expect(subject).to be_true }
16
+ end
17
+
18
+ context "with 'true'" do
19
+ let(:value) { 'true' }
20
+
21
+ it { expect(subject).to be_true }
22
+ end
23
+
24
+ context "with TRUE" do
25
+ let(:value) { TRUE }
26
+
27
+ it { expect(subject).to be_true }
28
+ end
29
+
30
+ context "with 'TRUE'" do
31
+ let(:value) { 'TRUE' }
32
+
33
+ it { expect(subject).to be_true }
34
+ end
35
+
36
+ context "with 't'" do
37
+ let(:value) { 't' }
38
+
39
+ it { expect(subject).to be_true }
40
+ end
41
+
42
+ context "with 'T'" do
43
+ let(:value) { 'T' }
44
+
45
+ it { expect(subject).to be_true }
46
+ end
47
+
48
+ context "with 1" do
49
+ let(:value) { 1 }
50
+
51
+ it { expect(subject).to be_true }
52
+ end
53
+
54
+ context "with '1'" do
55
+ let(:value) { '1' }
56
+
57
+ it { expect(subject).to be_true }
58
+ end
59
+
60
+ context "with false" do
61
+ let(:value) { false }
62
+
63
+ it { expect(subject).to be_false }
64
+ end
65
+
66
+ context "with 'false'" do
67
+ let(:value) { 'false' }
68
+
69
+ it { expect(subject).to be_false }
70
+ end
71
+
72
+ context "with FALSE" do
73
+ let(:value) { FALSE }
74
+
75
+ it { expect(subject).to be_false }
76
+ end
77
+
78
+ context "with 'FALSE'" do
79
+ let(:value) { 'FALSE' }
80
+
81
+ it { expect(subject).to be_false }
82
+ end
83
+
84
+ context "with 'f'" do
85
+ let(:value) { 'f' }
86
+
87
+ it { expect(subject).to be_false }
88
+ end
89
+
90
+ context "with 'F'" do
91
+ let(:value) { 'F' }
92
+
93
+ it { expect(subject).to be_false }
94
+ end
95
+
96
+ context "with 0" do
97
+ let(:value) { 0 }
98
+
99
+ it { expect(subject).to be_false }
100
+ end
101
+
102
+ context "with '0'" do
103
+ let(:value) { '0' }
104
+
105
+ it { expect(subject).to be_false }
106
+ end
107
+
108
+ context "with FOO" do
109
+ let(:value) { 'FOO' }
110
+
111
+ it { expect { subject }.to raise_error(TTY::TypeError) }
112
+ end
113
+ end