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