tty 0.0.6 → 0.0.7

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