command_kit 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +4 -6
- data/.rubocop.yml +13 -0
- data/ChangeLog.md +18 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +18 -9
- data/command_kit.gemspec +0 -1
- data/examples/printing/tables.rb +141 -0
- data/gemspec.yml +3 -3
- data/lib/command_kit/bug_report.rb +105 -0
- data/lib/command_kit/colors.rb +4 -4
- data/lib/command_kit/edit.rb +54 -0
- data/lib/command_kit/env.rb +1 -1
- data/lib/command_kit/options/option.rb +5 -1
- data/lib/command_kit/options/option_value.rb +2 -2
- data/lib/command_kit/options/parser.rb +1 -1
- data/lib/command_kit/options/quiet.rb +1 -1
- data/lib/command_kit/options/verbose.rb +2 -2
- data/lib/command_kit/options/version.rb +10 -0
- data/lib/command_kit/options.rb +1 -1
- data/lib/command_kit/os.rb +1 -1
- data/lib/command_kit/printing/fields.rb +56 -0
- data/lib/command_kit/printing/indent.rb +1 -1
- data/lib/command_kit/printing/lists.rb +91 -0
- data/lib/command_kit/printing/tables/border_style.rb +169 -0
- data/lib/command_kit/printing/tables/cell_builder.rb +93 -0
- data/lib/command_kit/printing/tables/row_builder.rb +111 -0
- data/lib/command_kit/printing/tables/style.rb +198 -0
- data/lib/command_kit/printing/tables/table_builder.rb +145 -0
- data/lib/command_kit/printing/tables/table_formatter.rb +254 -0
- data/lib/command_kit/printing/tables.rb +208 -0
- data/lib/command_kit/stdio.rb +5 -1
- data/lib/command_kit/version.rb +1 -1
- data/spec/bug_report_spec.rb +266 -0
- data/spec/colors_spec.rb +6 -0
- data/spec/command_name_spec.rb +1 -1
- data/spec/edit_spec.rb +72 -0
- data/spec/options/option_spec.rb +12 -2
- data/spec/options/quiet_spec.rb +51 -0
- data/spec/options/verbose_spec.rb +51 -0
- data/spec/options/version_spec.rb +146 -0
- data/spec/pager_spec.rb +1 -1
- data/spec/printing/fields_spec.rb +167 -0
- data/spec/printing/lists_spec.rb +99 -0
- data/spec/printing/tables/border_style.rb +43 -0
- data/spec/printing/tables/cell_builer_spec.rb +135 -0
- data/spec/printing/tables/row_builder_spec.rb +165 -0
- data/spec/printing/tables/style_spec.rb +377 -0
- data/spec/printing/tables/table_builder_spec.rb +252 -0
- data/spec/printing/tables/table_formatter_spec.rb +1180 -0
- data/spec/printing/tables_spec.rb +1069 -0
- metadata +33 -7
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/options/verbose'
|
3
|
+
|
4
|
+
describe CommandKit::Options::Verbose do
|
5
|
+
module TestOptionsVerbose
|
6
|
+
class TestCommand
|
7
|
+
include CommandKit::Options::Verbose
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:command_class) { TestOptionsVerbose::TestCommand }
|
12
|
+
|
13
|
+
describe ".included" do
|
14
|
+
subject { command_class }
|
15
|
+
|
16
|
+
it "must include CommandKit::Options" do
|
17
|
+
expect(subject).to include(CommandKit::Options)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "must define a verbose option" do
|
21
|
+
expect(subject.options[:verbose]).to_not be(nil)
|
22
|
+
expect(subject.options[:verbose].short).to eq('-v')
|
23
|
+
expect(subject.options[:verbose].long).to eq('--verbose')
|
24
|
+
expect(subject.options[:verbose].desc).to eq('Enables verbose output')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
subject { command_class.new }
|
29
|
+
|
30
|
+
describe "#verbose?" do
|
31
|
+
context "when @verbose is true" do
|
32
|
+
before do
|
33
|
+
subject.instance_variable_set('@verbose',true)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "must return true" do
|
37
|
+
expect(subject.verbose?).to be(true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when @verbose is false" do
|
42
|
+
before do
|
43
|
+
subject.instance_variable_set('@verbose',false)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "must return false" do
|
47
|
+
expect(subject.verbose?).to be(false)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/options/version'
|
3
|
+
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
describe CommandKit::Options::Version do
|
7
|
+
module TestOptionsVersion
|
8
|
+
class TestCommandWithoutVersion
|
9
|
+
|
10
|
+
include CommandKit::Options::Version
|
11
|
+
|
12
|
+
command_name 'test'
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class TestCommandWithVersion
|
17
|
+
|
18
|
+
include CommandKit::Options::Version
|
19
|
+
|
20
|
+
command_name 'test'
|
21
|
+
version '0.1.0'
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".included" do
|
27
|
+
subject { TestOptionsVersion::TestCommandWithVersion }
|
28
|
+
|
29
|
+
it "must include CommandKit::Options" do
|
30
|
+
expect(subject).to include(CommandKit::Options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe ".version" do
|
35
|
+
context "when no .version has been previously set" do
|
36
|
+
subject { TestOptionsVersion::TestCommandWithoutVersion }
|
37
|
+
|
38
|
+
it "must return nil" do
|
39
|
+
expect(subject.version).to be(nil)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when a .version has been set" do
|
44
|
+
subject { TestOptionsVersion::TestCommandWithVersion }
|
45
|
+
|
46
|
+
it "must return the set version" do
|
47
|
+
expect(subject.version).to eq('0.1.0')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when the command class inherites from another class" do
|
52
|
+
context "but no version are defined" do
|
53
|
+
module TestOptionsVersion
|
54
|
+
class InheritedCommandWithoutVersion < TestCommandWithoutVersion
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
subject { TestOptionsVersion::InheritedCommandWithoutVersion }
|
59
|
+
|
60
|
+
it "must return nil" do
|
61
|
+
expect(subject.version).to be(nil)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when the superclass defines the version" do
|
66
|
+
module TestOptionsVersion
|
67
|
+
class InheritedCommandWithInheritedVersion < TestCommandWithVersion
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:super_class) { TestOptionsVersion::TestCommandWithVersion }
|
72
|
+
subject { TestOptionsVersion::InheritedCommandWithInheritedVersion }
|
73
|
+
|
74
|
+
it "must return the version defined in the superclass" do
|
75
|
+
expect(subject.version).to eq(super_class.version)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when the subclass defines the version" do
|
80
|
+
module TestOptionsVersion
|
81
|
+
class InheritedCommandWithOwnVersion < TestCommandWithoutVersion
|
82
|
+
|
83
|
+
version '0.1.0'
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:super_subject) { TestOptionsVersion::TestCommandWithoutVersion }
|
89
|
+
subject { TestOptionsVersion::InheritedCommandWithOwnVersion }
|
90
|
+
|
91
|
+
it "must return the version set in the subclass" do
|
92
|
+
expect(subject.version).to eq('0.1.0')
|
93
|
+
end
|
94
|
+
|
95
|
+
it "must not change the superclass'es version" do
|
96
|
+
expect(super_subject.version).to be(nil)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when subclass overrides the superclass's version" do
|
101
|
+
module TestOptionsVersion
|
102
|
+
class InheritedCommandThatOverridesVersion < TestCommandWithVersion
|
103
|
+
|
104
|
+
version '0.2.0'
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
let(:super_subject) { TestOptionsVersion::TestCommandWithVersion }
|
110
|
+
subject { TestOptionsVersion::InheritedCommandThatOverridesVersion }
|
111
|
+
|
112
|
+
it "must return the version set in the subclass" do
|
113
|
+
expect(subject.version).to eq('0.2.0')
|
114
|
+
end
|
115
|
+
|
116
|
+
it "must not change the superclass'es version" do
|
117
|
+
expect(super_subject.version).to eq('0.1.0')
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
let(:command_class) { TestOptionsVersion::TestCommandWithVersion }
|
124
|
+
|
125
|
+
subject { command_class.new }
|
126
|
+
|
127
|
+
describe "#version" do
|
128
|
+
it "must return the class'es .version value" do
|
129
|
+
expect(subject.version).to eq(command_class.version)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "#print_version" do
|
134
|
+
let(:stdout) { StringIO.new }
|
135
|
+
|
136
|
+
subject { command_class.new(stdout: stdout) }
|
137
|
+
|
138
|
+
it "must print the #command_name and #version" do
|
139
|
+
subject.print_version
|
140
|
+
|
141
|
+
expect(stdout.string).to eq(
|
142
|
+
"#{subject.command_name} #{subject.version}#{$/}"
|
143
|
+
)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/spec/pager_spec.rb
CHANGED
@@ -26,7 +26,7 @@ describe CommandKit::Pager do
|
|
26
26
|
|
27
27
|
context "when the PAGER env variable is not set" do
|
28
28
|
context "but the PATH env variable is" do
|
29
|
-
subject { command_class.new(env: {'PATH' => ENV
|
29
|
+
subject { command_class.new(env: {'PATH' => ENV.fetch('PATH')}) }
|
30
30
|
|
31
31
|
it "must search PATH for one of the pagers" do
|
32
32
|
expect(subject.instance_variable_get('@pager_command')).to eq("less -r")
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/printing/fields'
|
3
|
+
|
4
|
+
describe CommandKit::Printing::Fields do
|
5
|
+
module TestPrintingFields
|
6
|
+
class TestCmd
|
7
|
+
|
8
|
+
include CommandKit::Printing::Fields
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:command_class) { TestPrintingFields::TestCmd }
|
14
|
+
subject { command_class.new }
|
15
|
+
|
16
|
+
let(:nl) { $/ }
|
17
|
+
|
18
|
+
describe "#print_fields" do
|
19
|
+
context "when given a Hash" do
|
20
|
+
context "and all key values are the same length" do
|
21
|
+
let(:name1) { 'A' }
|
22
|
+
let(:value1) { 'foo' }
|
23
|
+
let(:name2) { 'B' }
|
24
|
+
let(:value2) { 'bar' }
|
25
|
+
|
26
|
+
let(:hash) do
|
27
|
+
{
|
28
|
+
name1 => value1,
|
29
|
+
name2 => value2
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must not left-justify the Hash keys" do
|
34
|
+
expect {
|
35
|
+
subject.print_fields(hash)
|
36
|
+
}.to output("#{name1}: #{value1}#{nl}#{name2}: #{value2}#{nl}").to_stdout
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "but key values have different lengths" do
|
41
|
+
let(:name1) { 'A' }
|
42
|
+
let(:value1) { 'foo' }
|
43
|
+
let(:name2) { 'Bar' }
|
44
|
+
let(:value2) { 'bar' }
|
45
|
+
|
46
|
+
let(:hash) do
|
47
|
+
{
|
48
|
+
name1 => value1,
|
49
|
+
name2 => value2
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "must left-justify the Hash keys" do
|
54
|
+
expect {
|
55
|
+
subject.print_fields(hash)
|
56
|
+
}.to output("#{name1}: #{value1}#{nl}#{name2}: #{value2}#{nl}").to_stdout
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "but the key values are not Strings" do
|
61
|
+
let(:name1) { 1 }
|
62
|
+
let(:value1) { 'foo' }
|
63
|
+
let(:name2) { 100 }
|
64
|
+
let(:value2) { 'bar' }
|
65
|
+
|
66
|
+
let(:hash) do
|
67
|
+
{
|
68
|
+
name1 => value1,
|
69
|
+
name2 => value2
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
it "must convert them to Strings before calculating justification" do
|
74
|
+
expect {
|
75
|
+
subject.print_fields(hash)
|
76
|
+
}.to output("#{name1}: #{value1}#{nl}#{name2}: #{value2}#{nl}").to_stdout
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when given an Array of tuples" do
|
82
|
+
context "and all first tuple values are the same length" do
|
83
|
+
let(:name1) { 'A' }
|
84
|
+
let(:value1) { 'foo' }
|
85
|
+
let(:name2) { 'B' }
|
86
|
+
let(:value2) { 'bar' }
|
87
|
+
|
88
|
+
let(:array) do
|
89
|
+
[
|
90
|
+
[name1, value1],
|
91
|
+
[name2, value2]
|
92
|
+
]
|
93
|
+
end
|
94
|
+
|
95
|
+
it "must not left-justify the tuples" do
|
96
|
+
expect {
|
97
|
+
subject.print_fields(array)
|
98
|
+
}.to output("#{name1}: #{value1}#{nl}#{name2}: #{value2}#{nl}").to_stdout
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "but first tuple values have different lengths" do
|
103
|
+
let(:name1) { 'A' }
|
104
|
+
let(:value1) { 'foo' }
|
105
|
+
let(:name2) { 'Bar' }
|
106
|
+
let(:value2) { 'bar' }
|
107
|
+
|
108
|
+
let(:array) do
|
109
|
+
[
|
110
|
+
[name1, value1],
|
111
|
+
[name2, value2]
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
115
|
+
it "must left-justify the tuples" do
|
116
|
+
expect {
|
117
|
+
subject.print_fields(array)
|
118
|
+
}.to output("#{name1}: #{value1}#{nl}#{name2}: #{value2}#{nl}").to_stdout
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "but the first tuple values are not Strings" do
|
123
|
+
let(:name1) { 1 }
|
124
|
+
let(:value1) { 'foo' }
|
125
|
+
let(:name2) { 100 }
|
126
|
+
let(:value2) { 'bar' }
|
127
|
+
|
128
|
+
let(:array) do
|
129
|
+
[
|
130
|
+
[name1, value1],
|
131
|
+
[name2, value2]
|
132
|
+
]
|
133
|
+
end
|
134
|
+
|
135
|
+
it "must convert them to Strings before calculating justification" do
|
136
|
+
expect {
|
137
|
+
subject.print_fields(array)
|
138
|
+
}.to output("#{name1}: #{value1}#{nl}#{name2}: #{value2}#{nl}").to_stdout
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context "but the values contain multiple lines" do
|
144
|
+
let(:name1) { 'A' }
|
145
|
+
let(:value1) { 'foo' }
|
146
|
+
let(:name2) { 'Bar' }
|
147
|
+
let(:line1) { 'bar' }
|
148
|
+
let(:line2) { 'baz' }
|
149
|
+
let(:value2) do
|
150
|
+
[line1, line2].join($/)
|
151
|
+
end
|
152
|
+
|
153
|
+
let(:hash) do
|
154
|
+
{
|
155
|
+
name1 => value1,
|
156
|
+
name2 => value2
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
it "must print the header with the first line and then indent the other lines" do
|
161
|
+
expect {
|
162
|
+
subject.print_fields(hash)
|
163
|
+
}.to output("#{name1}: #{value1}#{nl}#{name2}: #{line1}#{nl} #{line2}#{nl}").to_stdout
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/printing/lists'
|
3
|
+
|
4
|
+
describe CommandKit::Printing::Lists do
|
5
|
+
module TestPrintingLists
|
6
|
+
class TestCmd
|
7
|
+
|
8
|
+
include CommandKit::Printing::Lists
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:command_class) { TestPrintingLists::TestCmd }
|
14
|
+
subject { command_class.new }
|
15
|
+
|
16
|
+
describe "#print_list" do
|
17
|
+
let(:list) { %w[foo bar baz] }
|
18
|
+
|
19
|
+
it "must print each item in the list with a '*' bullet" do
|
20
|
+
expect {
|
21
|
+
subject.print_list(list)
|
22
|
+
}.to output(
|
23
|
+
list.map { |item| "* #{item}" }.join($/) + $/
|
24
|
+
).to_stdout
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the list contins multi-line Strings" do
|
28
|
+
let(:item1) { "foo" }
|
29
|
+
let(:item2) do
|
30
|
+
[
|
31
|
+
"line 1",
|
32
|
+
"line 2",
|
33
|
+
"line 3"
|
34
|
+
].join($/)
|
35
|
+
end
|
36
|
+
let(:item3) { "bar" }
|
37
|
+
let(:list) { [item1, item2, item3] }
|
38
|
+
|
39
|
+
it "must print the bullet with the first line and then indent the other lines" do
|
40
|
+
expect {
|
41
|
+
subject.print_list(list)
|
42
|
+
}.to output(
|
43
|
+
[
|
44
|
+
"* #{item1}",
|
45
|
+
"* #{item2.lines[0].chomp}",
|
46
|
+
" #{item2.lines[1].chomp}",
|
47
|
+
" #{item2.lines[2].chomp}",
|
48
|
+
"* #{item3}",
|
49
|
+
''
|
50
|
+
].join($/)
|
51
|
+
).to_stdout
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when the list contains nested-lists" do
|
56
|
+
let(:item1) { 'item 1' }
|
57
|
+
let(:sub_item1) { 'sub-item 1' }
|
58
|
+
let(:sub_item2) { 'sub-item 2' }
|
59
|
+
let(:item2) { 'item 2' }
|
60
|
+
|
61
|
+
let(:list) do
|
62
|
+
[
|
63
|
+
'item 1',
|
64
|
+
[
|
65
|
+
'sub-item 1',
|
66
|
+
'sub-item 2'
|
67
|
+
],
|
68
|
+
'item 2'
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "must indent and print each sub-list" do
|
73
|
+
expect {
|
74
|
+
subject.print_list(list)
|
75
|
+
}.to output(
|
76
|
+
[
|
77
|
+
"* #{item1}",
|
78
|
+
" * #{sub_item1}",
|
79
|
+
" * #{sub_item2}",
|
80
|
+
"* #{item2}",
|
81
|
+
''
|
82
|
+
].join($/)
|
83
|
+
).to_stdout
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "when the bullet: keyowrd argument is given" do
|
88
|
+
let(:bullet) { '-' }
|
89
|
+
|
90
|
+
it "must print each item in the list with the bullet character" do
|
91
|
+
expect {
|
92
|
+
subject.print_list(list, bullet: bullet)
|
93
|
+
}.to output(
|
94
|
+
list.map { |item| "#{bullet} #{item}" }.join($/) + $/
|
95
|
+
).to_stdout
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/printing/tables/border_style'
|
3
|
+
|
4
|
+
describe CommandKit::Printing::Tables::BorderStyle do
|
5
|
+
describe "#initialize" do
|
6
|
+
[
|
7
|
+
:top_left_corner,
|
8
|
+
:top_border,
|
9
|
+
:top_joined_border,
|
10
|
+
:top_right_corner,
|
11
|
+
:left_border,
|
12
|
+
:left_joined_border,
|
13
|
+
:horizontal_separator,
|
14
|
+
:vertical_separator,
|
15
|
+
:inner_joined_border,
|
16
|
+
:right_border,
|
17
|
+
:right_joined_border,
|
18
|
+
:bottom_border,
|
19
|
+
:bottom_left_corner,
|
20
|
+
:bottom_joined_border,
|
21
|
+
:bottom_right_corner
|
22
|
+
].each do |keyword|
|
23
|
+
context "when #{keyword}: keyword is given" do
|
24
|
+
let(:keyword) { keyword }
|
25
|
+
let(:value) { 'x' }
|
26
|
+
|
27
|
+
subject { described_class.new(**{keyword => value}) }
|
28
|
+
|
29
|
+
it "must set ##{keyword}" do
|
30
|
+
expect(subject.send(keyword)).to eq(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when #{keyword}: keyword is not given" do
|
35
|
+
let(:keyword) { keyword }
|
36
|
+
|
37
|
+
it "must default ##{keyword} to ' '" do
|
38
|
+
expect(subject.send(keyword)).to eq(' ')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/printing/tables/cell_builder'
|
3
|
+
|
4
|
+
describe CommandKit::Printing::Tables::CellBuilder do
|
5
|
+
describe "#initialize" do
|
6
|
+
it "must initialize #lines to an empty Array" do
|
7
|
+
expect(subject.lines).to eq([])
|
8
|
+
end
|
9
|
+
|
10
|
+
it "must default #height to 0" do
|
11
|
+
expect(subject.height).to eq(0)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "must default #width to 0" do
|
15
|
+
expect(subject.width).to eq(0)
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when an initial value is given" do
|
19
|
+
subject { described_class.new(value) }
|
20
|
+
|
21
|
+
context "and it's a String" do
|
22
|
+
let(:value) do
|
23
|
+
<<~EOS
|
24
|
+
foo bar
|
25
|
+
baz qux
|
26
|
+
EOS
|
27
|
+
end
|
28
|
+
|
29
|
+
it "must split the value into separate lines and populate #lines" do
|
30
|
+
expect(subject.lines).to eq(value.lines(chomp: true))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "but it's not a String" do
|
35
|
+
let(:value) { 42 }
|
36
|
+
|
37
|
+
it "must convert it to a String before adding it to #lines" do
|
38
|
+
expect(subject.lines).to eq([value.to_s])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".line_width" do
|
45
|
+
subject { described_class }
|
46
|
+
|
47
|
+
context "when given a plain-text String" do
|
48
|
+
let(:line) { "foo bar baz" }
|
49
|
+
|
50
|
+
it "must return the line length" do
|
51
|
+
expect(subject.line_width(line)).to eq(line.length)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when given a String containing ANSI control sequences" do
|
56
|
+
let(:line_without_ansi) { "foo bar baz" }
|
57
|
+
let(:line) { "\e[1m\e[32m#{line_without_ansi}\e[0m" }
|
58
|
+
|
59
|
+
it "must return the length of the line without the ANSI control sequences" do
|
60
|
+
expect(subject.line_width(line)).to eq(line_without_ansi.length)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#<<" do
|
66
|
+
let(:line) { "foo bar baz" }
|
67
|
+
|
68
|
+
it "must increment #height by 1" do
|
69
|
+
expect(subject.height).to eq(0)
|
70
|
+
|
71
|
+
subject << line
|
72
|
+
expect(subject.height).to eq(1)
|
73
|
+
|
74
|
+
subject << line
|
75
|
+
expect(subject.height).to eq(2)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "must append the line to #lines" do
|
79
|
+
subject << line
|
80
|
+
|
81
|
+
expect(subject.lines.last).to eq(line)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "must return self" do
|
85
|
+
expect(subject << line).to be(subject)
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when the line's line-width is greater than #width" do
|
89
|
+
let(:previous_line) { "foo" }
|
90
|
+
|
91
|
+
it "must update #width" do
|
92
|
+
subject << previous_line
|
93
|
+
expect(subject.width).to eq(previous_line.length)
|
94
|
+
|
95
|
+
subject << line
|
96
|
+
expect(subject.width).to eq(line.length)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when the line's line-width is not greater than #width" do
|
101
|
+
let(:previous_line) { "foo bar baz" }
|
102
|
+
let(:line) { "foo" }
|
103
|
+
|
104
|
+
it "must update #width" do
|
105
|
+
subject << previous_line
|
106
|
+
expect(subject.width).to eq(previous_line.length)
|
107
|
+
|
108
|
+
subject << line
|
109
|
+
expect(subject.width).to eq(previous_line.length)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#[]" do
|
115
|
+
let(:line1) { "foo bar" }
|
116
|
+
let(:line2) { "baz qux" }
|
117
|
+
|
118
|
+
before do
|
119
|
+
subject << line1
|
120
|
+
subject << line2
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when the index is within the bounds of #lines" do
|
124
|
+
it "must return the line at the given index" do
|
125
|
+
expect(subject[1]).to eq(line2)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context "when the index is out of the bounds of #lines" do
|
130
|
+
it "must return ''" do
|
131
|
+
expect(subject[2]).to eq('')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|