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
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe TTY::Coercer::Float, '#coerce' do
4
+ let(:strict) { true }
5
+ subject { described_class.coerce(value, strict) }
6
+
7
+ context 'with empty' do
8
+ let(:value) { '' }
9
+
10
+ it { expect { subject }.to raise_error(TTY::InvalidArgument) }
11
+ end
12
+
13
+ context 'with 1 as string' do
14
+ let(:value) { '1' }
15
+
16
+ it { expect(subject).to eql 1.0 }
17
+ end
18
+
19
+ context 'with float' do
20
+ let(:value) { '1.2a' }
21
+
22
+ it { expect { subject }.to raise_error(TTY::InvalidArgument) }
23
+ end
24
+
25
+ context 'with float not strict' do
26
+ let(:value) { '1.2abc'}
27
+ let(:strict) { false }
28
+
29
+ it { expect(subject).to eql 1.2 }
30
+ end
31
+
32
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe TTY::Coercer::Integer, '#coerce' do
4
+ let(:strict) { true }
5
+ subject { described_class.coerce(value, strict) }
6
+
7
+ context 'with empty' do
8
+ let(:value) { '' }
9
+
10
+ it { expect { subject }.to raise_error(TTY::InvalidArgument) }
11
+ end
12
+
13
+ context 'with 1 as string' do
14
+ let(:value) { '1' }
15
+
16
+ it { expect(subject).to eql 1 }
17
+ end
18
+
19
+ context 'with float' do
20
+ let(:value) { 1.2 }
21
+
22
+ it { expect { subject }.to raise_error(TTY::InvalidArgument) }
23
+ end
24
+
25
+ context 'with float not strict' do
26
+ let(:value) { 1.2 }
27
+ let(:strict) { false }
28
+
29
+ it { expect(subject).to eql 1 }
30
+ end
31
+
32
+ context 'with letters not strict' do
33
+ let(:value) { '1abc' }
34
+ let(:strict) { false }
35
+
36
+ it { expect(subject).to eql 1 }
37
+ end
38
+
39
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe TTY::Coercer::Range, '#coerce' do
4
+
5
+ subject { described_class.coerce(value) }
6
+
7
+ context 'with empty' do
8
+ let(:value) { '' }
9
+
10
+ it { expect { subject }.to raise_error(TTY::InvalidArgument) }
11
+ end
12
+
13
+ context 'with 1' do
14
+ let(:value) { '1' }
15
+
16
+ it { should == (1..1) }
17
+ end
18
+
19
+ context 'with 1..10' do
20
+ let(:value) { '1..10' }
21
+
22
+ it { should == (1..10) }
23
+ end
24
+
25
+ context 'with 1-10' do
26
+ let(:value) { '1-10' }
27
+
28
+ it { should == (1..10) }
29
+ end
30
+
31
+ context 'with 1,10' do
32
+ let(:value) { '1,10' }
33
+
34
+ it { should == (1..10) }
35
+ end
36
+
37
+ context 'with 1...10' do
38
+ let(:value) { '1...10'}
39
+
40
+ it { should == (1...10) }
41
+ end
42
+
43
+ context 'with -1..10' do
44
+ let(:value) { '-1..10' }
45
+
46
+ it { should == (-1..10) }
47
+ end
48
+
49
+ context 'with 1..-10' do
50
+ let(:value) { '1..-10' }
51
+
52
+ it { should == (1..-10) }
53
+ end
54
+
55
+ context 'with a..z' do
56
+ let(:value) { 'a..z' }
57
+
58
+ it { should == ('a'..'z')}
59
+ end
60
+
61
+ context 'with a-z' do
62
+ let(:value) { 'a-z' }
63
+
64
+ it { should == ('a'..'z')}
65
+ end
66
+
67
+ context 'with A..Z' do
68
+ let(:value) { 'A..Z' }
69
+
70
+ it { should == ('A'..'Z')}
71
+ end
72
+
73
+ end # coerce
@@ -5,8 +5,10 @@ require 'spec_helper'
5
5
  describe TTY::Shell, '#ask' do
6
6
  let(:input) { StringIO.new }
7
7
  let(:output) { StringIO.new }
8
+ let(:prefix) { '' }
9
+ let(:options) { { :prefix => prefix } }
8
10
 
9
- subject(:shell) { TTY::Shell.new(input, output) }
11
+ subject(:shell) { TTY::Shell.new(input, output, options) }
10
12
 
11
13
  it 'prints message' do
12
14
  shell.ask "What is your name?"
@@ -25,6 +27,17 @@ describe TTY::Shell, '#ask' do
25
27
  expect(q.read).to eql nil
26
28
  end
27
29
 
30
+ context 'with a prompt prefix' do
31
+ let(:prefix) { ' > ' }
32
+
33
+ it "asks a question with '>'" do
34
+ input << ''
35
+ input.rewind
36
+ q = shell.ask "Are you Polish?"
37
+ expect(output.string).to eql " > Are you Polish?\n"
38
+ end
39
+ end
40
+
28
41
  it 'asks a question with block' do
29
42
  input << ''
30
43
  input.rewind
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#argument' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'requires value to be present with helper' do
11
+ input << ''
12
+ input.rewind
13
+ q = shell.ask("What is your name?").argument(:required)
14
+ expect { q.read }.to raise_error(ArgumentError)
15
+ end
16
+
17
+ it 'requires value to be present with option' do
18
+ input << ''
19
+ input.rewind
20
+ q = shell.ask("What is your name?", :required => true)
21
+ expect { q.read }.to raise_error(ArgumentError)
22
+ end
23
+
24
+ it "doesn't require value to be present" do
25
+ input << ''
26
+ input.rewind
27
+ q = shell.ask("What is your name?").argument(:optional)
28
+ expect(q.read).to be_nil
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#character' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'switches to character input' do
11
+ input << "abcd"
12
+ input.rewind
13
+ q = shell.ask("Which one do you prefer a, b, c or d?").character(true)
14
+ expect(q.read_string).to eql "abcd"
15
+ end
16
+ end # character
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#default' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'uses default value' do
11
+ name = 'Anonymous'
12
+ q = shell.ask("What is your name?").default(name)
13
+ answer = q.read
14
+ expect(answer).to eql name
15
+ end
16
+
17
+ it 'uses default value in block' do
18
+ name = 'Anonymous'
19
+ q = shell.ask "What is your name?" do
20
+ default name
21
+ end
22
+ answer = q.read
23
+ expect(answer).to eql name
24
+ end
25
+ end # default
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Shell::Question, '#in' do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:shell) { TTY::Shell.new(input, output) }
9
+
10
+ it 'reads number within range' do
11
+ input << 8
12
+ input.rewind
13
+ q = shell.ask("How do you like it on scale 1-10").in('1-10')
14
+ expect(q.read_int).to eql 8
15
+ end
16
+
17
+ it "reads number outside of range" do
18
+ input << 12
19
+ input.rewind
20
+ q = shell.ask("How do you like it on scale 1-10").in('1-10')
21
+ expect { q.read_int }.to raise_error(ArgumentError)
22
+ end
23
+ end # in
@@ -2,226 +2,26 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe TTY::Shell::Question, '#ask' do
6
-
5
+ describe TTY::Shell::Question, '#initialize' do
7
6
  let(:input) { StringIO.new }
8
7
  let(:output) { StringIO.new }
9
8
  let(:shell) { TTY::Shell.new(input, output) }
9
+ let(:message) { 'Do you like me?' }
10
10
 
11
- context 'with default' do
12
- it 'uses default value' do
13
- name = 'Anonymous'
14
- q = shell.ask("What is your name?").default(name)
15
- answer = q.read
16
- expect(answer).to eql name
17
- end
18
-
19
- it 'uses default value in block' do
20
- name = 'Anonymous'
21
- q = shell.ask "What is your name?" do
22
- default name
23
- end
24
- answer = q.read
25
- expect(answer).to eql name
26
- end
27
- end
28
-
29
- context 'with argument' do
30
- it 'requires value to be present with helper' do
31
- input << ''
32
- input.rewind
33
- q = shell.ask("What is your name?").argument(:required)
34
- expect { q.read }.to raise_error(ArgumentError)
35
- end
36
-
37
- it 'requires value to be present with option' do
38
- input << ''
39
- input.rewind
40
- q = shell.ask("What is your name?", :required => true)
41
- expect { q.read }.to raise_error(ArgumentError)
42
- end
43
- end
44
-
45
- context 'with validation' do
46
- it 'fails to validate input' do
47
- input << 'piotrmurach'
48
- input.rewind
49
- q = shell.ask("What is your username?").validate(/^[^\.]+\.[^\.]+/)
50
- expect { q.read_string }.to raise_error(ArgumentError)
51
- end
52
-
53
- it 'validates input with regex' do
54
- input << 'piotr.murach'
55
- input.rewind
56
- q = shell.ask("What is your username?").validate(/^[^\.]+\.[^\.]+/)
57
- expect(q.read_string).to eql 'piotr.murach'
58
- end
59
-
60
- it 'validates input in block' do
61
- input << 'piotr.murach'
62
- input.rewind
63
- q = shell.ask("What is your username?").validate { |arg| arg =~ /^[^\.]+\.[^\.]+/ }
64
- expect(q.read_string).to eql 'piotr.murach'
65
- end
66
- end
67
-
68
- context 'with valid choice' do
69
- let(:cards) { %w[ club diamond spade heart ] }
70
-
71
- it 'reads valid optios with helper' do
72
- input << 'club'
73
- input.rewind
74
- q = shell.ask("What is your card suit sir?").valid(cards)
75
- expect(q.read_choice).to eql 'club'
76
- end
77
-
78
- it 'reads valid options with option hash' do
79
- input << 'club'
80
- input.rewind
81
- q = shell.ask("What is your card suit sir?", :valid => cards)
82
- expect(q.read_choice).to eql 'club'
83
- end
84
-
85
- it 'reads invalid option' do
86
- input << 'clover'
87
- input.rewind
88
- q = shell.ask("What is your card suit sir?").valid(cards)
89
- expect { q.read_choice }.to raise_error(TTY::InvalidArgument)
90
- end
91
-
92
- it 'needs argument' do
93
- input << ''
94
- input.rewind
95
- q = shell.ask("What is your card suit sir?").valid(cards)
96
- expect { q.read_choice }.to raise_error(TTY::ArgumentRequired)
97
- end
98
-
99
- it 'reads with default' do
100
- input << ''
101
- input.rewind
102
- q = shell.ask("What is your card suit sir?").valid(cards).default('club')
103
- expect(q.read_choice).to eql 'club'
104
- end
105
- end
106
-
107
- context 'with modification' do
108
- it 'preserves answer for unkown modification' do
109
- input << 'piotr'
110
- input.rewind
111
- q = shell.ask("What is your name?").modify(:none)
112
- expect(q.read_string).to eql 'piotr'
113
- end
114
-
115
- it 'converts to upper case' do
116
- input << 'piotr'
117
- input.rewind
118
- q = shell.ask("What is your name?").modify(:upcase)
119
- expect(q.read_string).to eql 'PIOTR'
120
- end
121
-
122
- it 'trims whitespace' do
123
- input << " Some white\t space\t \there! \n"
124
- input.rewind
125
- q = shell.ask("Enter some text: ").modify(:trim)
126
- expect(q.read_string).to eql "Some white\t space\t \there!"
127
- end
128
-
129
- it 'collapses whitespace' do
130
- input << " Some white\t space\t \there! \n"
131
- input.rewind
132
- q = shell.ask("Enter some text: ").modify(:collapse)
133
- expect(q.read_string).to eql " Some white space here! "
134
- end
135
-
136
- it 'strips and collapses whitespace' do
137
- input << " Some white\t space\t \there! \n"
138
- input.rewind
139
- q = shell.ask("Enter some text: ").modify(:strip, :collapse)
140
- expect(q.read_string).to eql "Some white space here!"
141
- end
142
- end
143
-
144
- context 'with type' do
145
- it 'reads string' do
146
- name = "Piotr"
147
- input << name
148
- input.rewind
149
- q = shell.ask("What is your name?")
150
- answer = q.read_string
151
- expect(answer).to eql name
152
- end
153
-
154
- it 'reads integer' do
155
- input << 5
156
- input.rewind
157
- q = shell.ask("What temperature?")
158
- answer = q.read_int
159
- expect(answer).to eql 5
160
- end
161
-
162
- it 'reads float' do
163
- input << '6.0'
164
- input.rewind
165
- q = shell.ask("How tall are you?")
166
- answer = q.read_float
167
- expect(answer).to eql 6.0
168
- end
11
+ subject { described_class.new shell }
169
12
 
170
- it 'fails to read boolean' do
171
- input << 'invalid'
172
- input.rewind
173
- q = shell.ask("Do you read books?")
174
- expect { q.read_bool }.to raise_error(ArgumentError)
175
- end
13
+ its(:shell) { should == shell }
176
14
 
177
- it 'reads negative boolean' do
178
- input << 'No'
179
- input.rewind
180
- q = shell.ask("Do you read books?")
181
- answer = q.read_bool
182
- expect(answer).to eql false
183
- end
15
+ its(:required) { should be_false }
184
16
 
185
- it 'reads positive boolean' do
186
- input << 'Yes'
187
- input.rewind
188
- q = shell.ask("Do you read books?")
189
- answer = q.read_bool
190
- expect(answer).to eql true
191
- end
192
- end
17
+ its(:echo) { should be_true }
193
18
 
194
- context 'with multiple line' do
195
- it 'reads multiple lines' do
196
- input << "First line\nSecond line\nThird line"
197
- input.rewind
198
- q = shell.ask("Provide description?")
199
- expect(q.read_multiple).to eql "First line\nSecond line\nThird line"
200
- end
201
- end
19
+ its(:mask) { should be_false }
202
20
 
203
- context 'with email' do
204
- it 'reads valid email' do
205
- input << "piotr@example.com"
206
- input.rewind
207
- q = shell.ask("What is your email?")
208
- expect(q.read_email).to eql "piotr@example.com"
209
- end
21
+ its(:character) { should be_false }
210
22
 
211
- it 'fails to read invalid email' do
212
- input << "this will@neverwork"
213
- input.rewind
214
- q = shell.ask("What is your email?")
215
- expect { q.read_email }.to raise_error(TTY::InvalidArgument)
216
- end
23
+ its(:modifier) { should be_kind_of TTY::Shell::Question::Modifier }
217
24
 
218
- it 'asks again' do
219
- input << "this will@neverwork\nthis.will@example.com"
220
- input.rewind
221
- q = shell.ask("What is your email?").on_error(:retry)
222
- expect(q.read_email).to eql "this.will@example.com"
223
- expect(output.string).to eql "What is your email?\nWhat is your email?\n"
224
- end
225
- end
25
+ its(:validation) { should be_kind_of TTY::Shell::Question::Validation }
226
26
 
227
- end
27
+ end # initialize