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
@@ -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