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
@@ -30,4 +30,4 @@ describe TTY::Shell::Question::Modifier, '#whitespace' do
30
30
 
31
31
  it { should == "texttomodify" }
32
32
  end
33
- end
33
+ end # whitespace
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#modify' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'preserves answer for unkown modification' do
11
+ input << 'piotr'
12
+ input.rewind
13
+ q = shell.ask("What is your name?").modify(:none)
14
+ expect(q.read_string).to eql 'piotr'
15
+ end
16
+
17
+ it 'converts to upper case' do
18
+ input << 'piotr'
19
+ input.rewind
20
+ q = shell.ask("What is your name?").modify(:upcase)
21
+ expect(q.read_string).to eql 'PIOTR'
22
+ end
23
+
24
+ it 'trims whitespace' do
25
+ input << " Some white\t space\t \there! \n"
26
+ input.rewind
27
+ q = shell.ask("Enter some text: ").modify(:trim)
28
+ expect(q.read_string).to eql "Some white\t space\t \there!"
29
+ end
30
+
31
+ it 'collapses whitespace' do
32
+ input << " Some white\t space\t \there! \n"
33
+ input.rewind
34
+ q = shell.ask("Enter some text: ").modify(:collapse)
35
+ expect(q.read_string).to eql " Some white space here! "
36
+ end
37
+
38
+ it 'strips and collapses whitespace' do
39
+ input << " Some white\t space\t \there! \n"
40
+ input.rewind
41
+ q = shell.ask("Enter some text: ").modify(:strip, :collapse)
42
+ expect(q.read_string).to eql "Some white space here!"
43
+ end
44
+ end
@@ -0,0 +1,46 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#valid' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ let(:cards) { %w[ club diamond spade heart ] }
11
+
12
+ it 'reads valid optios with helper' do
13
+ input << 'club'
14
+ input.rewind
15
+ q = shell.ask("What is your card suit sir?").valid(cards)
16
+ expect(q.read_choice).to eql 'club'
17
+ end
18
+
19
+ it 'reads valid options with option hash' do
20
+ input << 'club'
21
+ input.rewind
22
+ q = shell.ask("What is your card suit sir?", :valid => cards)
23
+ expect(q.read_choice).to eql 'club'
24
+ end
25
+
26
+ it 'reads invalid option' do
27
+ input << 'clover'
28
+ input.rewind
29
+ q = shell.ask("What is your card suit sir?").valid(cards)
30
+ expect { q.read_choice }.to raise_error(TTY::InvalidArgument)
31
+ end
32
+
33
+ it 'needs argument' do
34
+ input << ''
35
+ input.rewind
36
+ q = shell.ask("What is your card suit sir?").valid(cards)
37
+ expect { q.read_choice }.to raise_error(TTY::ArgumentRequired)
38
+ end
39
+
40
+ it 'reads with default' do
41
+ input << ''
42
+ input.rewind
43
+ q = shell.ask("What is your card suit sir?").valid(cards).default('club')
44
+ expect(q.read_choice).to eql 'club'
45
+ end
46
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#validate' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'fails to validate input' do
11
+ input << 'piotrmurach'
12
+ input.rewind
13
+ q = shell.ask("What is your username?").validate(/^[^\.]+\.[^\.]+/)
14
+ expect { q.read_string }.to raise_error(ArgumentError)
15
+ end
16
+
17
+ it 'validates input with regex' do
18
+ input << 'piotr.murach'
19
+ input.rewind
20
+ q = shell.ask("What is your username?").validate(/^[^\.]+\.[^\.]+/)
21
+ expect(q.read_string).to eql 'piotr.murach'
22
+ end
23
+
24
+ it 'validates input in block' do
25
+ input << 'piotr.murach'
26
+ input.rewind
27
+ q = shell.ask("What is your username?").validate { |arg| arg =~ /^[^\.]+\.[^\.]+/ }
28
+ expect(q.read_string).to eql 'piotr.murach'
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Reader, '#getc' do
6
+ let(:instance) { described_class.new(shell) }
7
+
8
+ let(:input) { StringIO.new }
9
+ let(:output) { StringIO.new }
10
+ let(:shell) { TTY::Shell.new(input, output) }
11
+ let(:mask) { '*'}
12
+
13
+ subject(:reader) { instance.getc mask }
14
+
15
+ it 'masks characters' do
16
+ input << "password\n"
17
+ input.rewind
18
+ expect(reader).to eql "password"
19
+ expect(output.string).to eql("********")
20
+ end
21
+
22
+ context "without mask" do
23
+ let(:mask) { }
24
+
25
+ it 'masks characters' do
26
+ input << "password\n"
27
+ input.rewind
28
+ expect(reader).to eql "password"
29
+ expect(output.string).to eql("password")
30
+ end
31
+
32
+ end
33
+
34
+ it 'deletes characters when backspace pressed' do
35
+ input << "\b\b"
36
+ input.rewind
37
+ expect(reader).to eql ''
38
+ expect(output.string).to eql('')
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#read_bool' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'fails to read boolean' do
11
+ input << 'invalid'
12
+ input.rewind
13
+ q = shell.ask("Do you read books?")
14
+ expect { q.read_bool }.to raise_error(TTY::TypeError)
15
+ end
16
+
17
+ it 'reads negative boolean' do
18
+ input << 'No'
19
+ input.rewind
20
+ q = shell.ask("Do you read books?")
21
+ answer = q.read_bool
22
+ expect(answer).to eql false
23
+ end
24
+
25
+ it 'reads positive boolean' do
26
+ input << 'Yes'
27
+ input.rewind
28
+ q = shell.ask("Do you read books?")
29
+ answer = q.read_bool
30
+ expect(answer).to eql true
31
+ end
32
+
33
+ it 'reads single positive boolean' do
34
+ input << 'y'
35
+ input.rewind
36
+ q = shell.ask("Do you read books?")
37
+ answer = q.read_bool
38
+ expect(answer).to eql true
39
+ end
40
+
41
+ end
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#read_char' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'reads single character' do
11
+ input << "abcde"
12
+ input.rewind
13
+ q = shell.ask("What is your favourite letter?")
14
+ expect(q.read_char).to eql "a"
15
+ end
16
+
17
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#read_date' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'reads date' do
11
+ input << "20th April 1887"
12
+ input.rewind
13
+ q = shell.ask("When were your born?")
14
+ answer = q.read_date
15
+ expect(answer).to be_kind_of Date
16
+ expect(answer.day).to eql 20
17
+ expect(answer.month).to eql 4
18
+ expect(answer.year).to eql 1887
19
+ end
20
+ end
@@ -0,0 +1,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#read_email' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ context 'with valid email' do
11
+ it 'reads empty' do
12
+ input << ""
13
+ input.rewind
14
+ q = shell.ask("What is your email?")
15
+ expect { q.read_email }.to raise_error(TTY::InvalidArgument)
16
+ end
17
+
18
+ it 'reads valid email' do
19
+ input << "piotr@example.com"
20
+ input.rewind
21
+ q = shell.ask("What is your email?")
22
+ expect(q.read_email).to eql "piotr@example.com"
23
+ end
24
+ end
25
+
26
+ context 'with invalid email' do
27
+ it 'fails to read invalid email' do
28
+ input << "this will@neverwork"
29
+ input.rewind
30
+ q = shell.ask("What is your email?")
31
+ expect { q.read_email }.to raise_error(TTY::InvalidArgument)
32
+ end
33
+
34
+ it 'reads invalid and asks again' do
35
+ input << "this will@neverwork\nthis.will@example.com"
36
+ input.rewind
37
+ q = shell.ask("What is your email?").on_error(:retry)
38
+ expect(q.read_email).to eql "this.will@example.com"
39
+ expect(output.string).to eql "What is your email?\nWhat is your email?\n"
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#read_multiple' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'reads multiple lines' do
11
+ input << "First line\nSecond line\nThird line"
12
+ input.rewind
13
+ q = shell.ask("Provide description?")
14
+ expect(q.read_multiple).to eql "First line\nSecond line\nThird line"
15
+ end
16
+
17
+ it 'skips empty lines' do
18
+ input << "First line\n\nSecond line"
19
+ input.rewind
20
+ q = shell.ask("Provide description?")
21
+ expect(q.read_multiple).to eql "First line\nSecond line"
22
+ end
23
+
24
+ end
@@ -0,0 +1,29 @@
1
+
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'spec_helper'
5
+
6
+ describe TTY::Shell::Question, '#read_numbers' do
7
+ let(:input) { StringIO.new }
8
+ let(:output) { StringIO.new }
9
+ let(:shell) { TTY::Shell.new(input, output) }
10
+
11
+ it 'reads integer' do
12
+ input << 35
13
+ input.rewind
14
+ q = shell.ask("What temperature?")
15
+ answer = q.read_int
16
+ expect(answer).to be_kind_of Integer
17
+ expect(answer).to eql 35
18
+ end
19
+
20
+ it 'reads float' do
21
+ number = 6.666
22
+ input << number
23
+ input.rewind
24
+ q = shell.ask("How tall are you?")
25
+ answer = q.read_float
26
+ expect(answer).to be_kind_of Float
27
+ expect(answer).to eql number
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#read_range' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ subject {
11
+ input << value
12
+ input.rewind
13
+ shell.ask("Which age group?").read_range
14
+ }
15
+
16
+ context 'with valid range' do
17
+ let(:value) { "20-30" }
18
+
19
+ it { expect(subject).to be_kind_of Range }
20
+
21
+ it { expect(subject).to eql (20..30) }
22
+ end
23
+
24
+ context 'with invalid range' do
25
+ let(:value) { "abcd" }
26
+
27
+ it { expect { subject }.to raise_error(ArgumentError) }
28
+ end
29
+ end # read_range
@@ -0,0 +1,68 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#read_password' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ context 'with no mask' do
11
+ it 'asks with echo on' do
12
+ input << "password"
13
+ input.rewind
14
+ q = shell.ask("What is your password: ").echo(true)
15
+ expect(q.read).to eql("password")
16
+ expect(output.string).to eql('What is your password: ')
17
+ expect(q.mask?).to be_false
18
+ end
19
+
20
+ it 'asks with echo off' do
21
+ input << "password"
22
+ input.rewind
23
+ q = shell.ask("What is your password: ").echo(false)
24
+ expect(q.read).to eql("password")
25
+ expect(output.string).to eql('What is your password: ')
26
+ expect(q.mask?).to be_false
27
+ end
28
+ end
29
+
30
+ context 'with mask' do
31
+ it 'masks output with character' do
32
+ input << "password\n"
33
+ input.rewind
34
+ q = shell.ask("What is your password: ").mask('*')
35
+ expect(q.read).to eql("password")
36
+ expect(output.string).to eql('What is your password: ********')
37
+ expect(q.mask?).to be_true
38
+ end
39
+
40
+ it 'ignores mask if echo is off' do
41
+ input << "password"
42
+ input.rewind
43
+ q = shell.ask("What is your password: ").echo(false).mask('*')
44
+ expect(q.read).to eql("password")
45
+ expect(output.string).to eql('What is your password: ')
46
+ expect(q.mask?).to be_true
47
+ end
48
+ end
49
+
50
+ context 'with mask and echo as options' do
51
+ it 'asks with options' do
52
+ input << "password"
53
+ input.rewind
54
+ q = shell.ask("What is your password: ", :echo => false, :mask => '*')
55
+ expect(q.read_password).to eql("password")
56
+ end
57
+
58
+ it 'asks with block' do
59
+ input << "password"
60
+ input.rewind
61
+ q = shell.ask "What is your password: " do
62
+ echo false
63
+ mask '*'
64
+ end
65
+ expect(q.read_password).to eql("password")
66
+ end
67
+ end
68
+ end