command_kit 0.4.0 → 0.5.0

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +2 -0
  3. data/.rubocop.yml +3 -0
  4. data/ChangeLog.md +18 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.md +4 -1
  7. data/command_kit.gemspec +7 -2
  8. data/examples/subcommands/cli/config/get.rb +47 -0
  9. data/examples/subcommands/cli/config/set.rb +44 -0
  10. data/examples/subcommands/cli/config.rb +23 -0
  11. data/examples/subcommands/cli/list.rb +35 -0
  12. data/examples/subcommands/cli/update.rb +47 -0
  13. data/examples/subcommands/cli.rb +55 -0
  14. data/lib/command_kit/completion/install.rb +276 -0
  15. data/lib/command_kit/env/home.rb +1 -1
  16. data/lib/command_kit/env/prefix.rb +41 -0
  17. data/lib/command_kit/env/shell.rb +58 -0
  18. data/lib/command_kit/inflector.rb +1 -1
  19. data/lib/command_kit/options/parser.rb +1 -1
  20. data/lib/command_kit/os/linux.rb +1 -1
  21. data/lib/command_kit/os.rb +1 -1
  22. data/lib/command_kit/printing/tables/table_formatter.rb +2 -2
  23. data/lib/command_kit/version.rb +1 -1
  24. data/lib/command_kit/xdg.rb +1 -1
  25. metadata +12 -66
  26. data/spec/arguments/argument_spec.rb +0 -133
  27. data/spec/arguments/argument_value_spec.rb +0 -66
  28. data/spec/arguments_spec.rb +0 -279
  29. data/spec/bug_report_spec.rb +0 -266
  30. data/spec/colors_spec.rb +0 -771
  31. data/spec/command_kit_spec.rb +0 -8
  32. data/spec/command_name_spec.rb +0 -130
  33. data/spec/command_spec.rb +0 -123
  34. data/spec/commands/auto_load/subcommand_spec.rb +0 -82
  35. data/spec/commands/auto_load_spec.rb +0 -159
  36. data/spec/commands/auto_require_spec.rb +0 -142
  37. data/spec/commands/fixtures/test_auto_load/cli/commands/test1.rb +0 -10
  38. data/spec/commands/fixtures/test_auto_load/cli/commands/test2.rb +0 -10
  39. data/spec/commands/fixtures/test_auto_require/lib/test_auto_require/cli/commands/test1.rb +0 -10
  40. data/spec/commands/help_spec.rb +0 -66
  41. data/spec/commands/parent_command_spec.rb +0 -40
  42. data/spec/commands/subcommand_spec.rb +0 -99
  43. data/spec/commands_spec.rb +0 -839
  44. data/spec/description_spec.rb +0 -179
  45. data/spec/edit_spec.rb +0 -72
  46. data/spec/env/home_spec.rb +0 -46
  47. data/spec/env/path_spec.rb +0 -84
  48. data/spec/env_spec.rb +0 -123
  49. data/spec/examples_spec.rb +0 -211
  50. data/spec/exception_handler_spec.rb +0 -103
  51. data/spec/file_utils_spec.rb +0 -59
  52. data/spec/fixtures/template.erb +0 -5
  53. data/spec/help/man_spec.rb +0 -345
  54. data/spec/help_spec.rb +0 -94
  55. data/spec/inflector_spec.rb +0 -166
  56. data/spec/interactive_spec.rb +0 -415
  57. data/spec/main_spec.rb +0 -179
  58. data/spec/man_spec.rb +0 -46
  59. data/spec/open_app_spec.rb +0 -85
  60. data/spec/options/option_spec.rb +0 -343
  61. data/spec/options/option_value_spec.rb +0 -171
  62. data/spec/options/parser_spec.rb +0 -255
  63. data/spec/options/quiet_spec.rb +0 -51
  64. data/spec/options/verbose_spec.rb +0 -51
  65. data/spec/options/version_spec.rb +0 -146
  66. data/spec/options_spec.rb +0 -465
  67. data/spec/os/linux_spec.rb +0 -164
  68. data/spec/os_spec.rb +0 -233
  69. data/spec/package_manager_spec.rb +0 -806
  70. data/spec/pager_spec.rb +0 -217
  71. data/spec/printing/fields_spec.rb +0 -167
  72. data/spec/printing/indent_spec.rb +0 -132
  73. data/spec/printing/lists_spec.rb +0 -99
  74. data/spec/printing/tables/border_style.rb +0 -43
  75. data/spec/printing/tables/cell_builer_spec.rb +0 -135
  76. data/spec/printing/tables/row_builder_spec.rb +0 -165
  77. data/spec/printing/tables/style_spec.rb +0 -377
  78. data/spec/printing/tables/table_builder_spec.rb +0 -252
  79. data/spec/printing/tables/table_formatter_spec.rb +0 -1180
  80. data/spec/printing/tables_spec.rb +0 -1069
  81. data/spec/printing_spec.rb +0 -106
  82. data/spec/program_name_spec.rb +0 -70
  83. data/spec/spec_helper.rb +0 -3
  84. data/spec/stdio_spec.rb +0 -264
  85. data/spec/sudo_spec.rb +0 -51
  86. data/spec/terminal_spec.rb +0 -231
  87. data/spec/usage_spec.rb +0 -237
  88. data/spec/xdg_spec.rb +0 -191
data/spec/pager_spec.rb DELETED
@@ -1,217 +0,0 @@
1
- require 'spec_helper'
2
- require 'command_kit/pager'
3
-
4
- require 'stringio'
5
-
6
- describe CommandKit::Pager do
7
- module TestPager
8
- class TestCommand
9
- include CommandKit::Pager
10
- end
11
- end
12
-
13
- let(:command_class) { TestPager::TestCommand }
14
- subject { command_class.new }
15
-
16
- describe "#initialize" do
17
- context "when the PAGER env variable is set" do
18
- let(:pager) { 'foo' }
19
-
20
- subject { command_class.new(env: {'PAGER' => pager}) }
21
-
22
- it "must set @pager_command to the PAGER env variable" do
23
- expect(subject.instance_variable_get('@pager_command')).to eq(pager)
24
- end
25
- end
26
-
27
- context "when the PAGER env variable is not set" do
28
- context "but the PATH env variable is" do
29
- subject { command_class.new(env: {'PATH' => ENV.fetch('PATH')}) }
30
-
31
- it "must search PATH for one of the pagers" do
32
- expect(subject.instance_variable_get('@pager_command')).to eq("less -r")
33
- end
34
- end
35
- end
36
- end
37
-
38
- describe "#pager" do
39
- context "when stdout is not a TTY" do
40
- subject { command_class.new(stdout: StringIO.new) }
41
-
42
- it "must yield stdout" do
43
- expect { |b|
44
- subject.pager(&b)
45
- }.to yield_with_args(subject.stdout)
46
- end
47
- end
48
-
49
- context "when @pager_command isn't initialized" do
50
- before do
51
- subject.instance_variable_set('@pager_command',nil)
52
- end
53
-
54
- it "must yield stdout" do
55
- expect { |b|
56
- subject.pager(&b)
57
- }.to yield_with_args(subject.stdout)
58
- end
59
- end
60
-
61
- context "when stdout is a TTY and @pager_command is initialized" do
62
- let(:pager) { 'less -r' }
63
-
64
- subject { command_class.new(env: {'PAGER' => pager}) }
65
-
66
- let(:pager_io) { double('less') }
67
- let(:pager_pid) { double('pid') }
68
-
69
- before do
70
- expect(subject.stdout).to receive(:tty?).and_return(true)
71
-
72
- expect(IO).to receive(:popen).with(pager,'w').and_return(pager_io)
73
- expect(pager_io).to receive(:pid).and_return(pager_pid)
74
-
75
- expect(pager_io).to receive(:close)
76
- expect(Process).to receive(:waitpid).with(pager_pid)
77
- end
78
-
79
- it "must spawn a new process and yield an IO object" do
80
- expect { |b|
81
- subject.pager(&b)
82
- }.to yield_with_args(pager_io)
83
- end
84
-
85
- context "when Errno::EPIPE is raised" do
86
- it "must return gracefully" do
87
- expect {
88
- subject.pager do
89
- raise(Errno::EPIPE,"pipe broken")
90
- end
91
- }.to_not raise_error
92
- end
93
- end
94
- end
95
- end
96
-
97
- describe "#print_or_page" do
98
- let(:terminal_height) { 10 }
99
-
100
- before do
101
- expect(subject).to receive(:terminal_height).and_return(terminal_height)
102
- end
103
-
104
- context "when given a String" do
105
- context "and the number of lines is less than the console's height" do
106
- let(:string) { "foo#{$/}bar#{$/}" }
107
-
108
- it "must puts the String to stdout" do
109
- expect(subject.stdout).to receive(:puts).with(string)
110
-
111
- subject.print_or_page(string)
112
- end
113
- end
114
-
115
- context "and the number of lines is greater than the console's height" do
116
- let(:string) { "foo#{$/}bar#{$/}" * terminal_height }
117
-
118
- it "must spawn a pager and puts the String to the pager" do
119
- pager = double('pager')
120
- expect(subject).to receive(:pager).and_yield(pager)
121
- expect(pager).to receive(:puts).with(string)
122
-
123
- subject.print_or_page(string)
124
- end
125
- end
126
- end
127
-
128
- context "when given an Array" do
129
- context "and the number of lines is less than the console's height" do
130
- let(:array) { ['foo', 'bar'] }
131
-
132
- it "must puts the Array of Strings to stdout" do
133
- expect(subject.stdout).to receive(:puts).with(array)
134
-
135
- subject.print_or_page(array)
136
- end
137
- end
138
-
139
- context "and the number of lines is greater than the console's height" do
140
- let(:array) { ['foo', 'bar'] * terminal_height }
141
-
142
- it "must spawn a pager and puts the Array of Strings to the pager" do
143
- pager = double('pager')
144
- expect(subject).to receive(:pager).and_yield(pager)
145
- expect(pager).to receive(:puts).with(array)
146
-
147
- subject.print_or_page(array)
148
- end
149
- end
150
- end
151
- end
152
-
153
- describe "#pipe_to_pager" do
154
- context "when @pager_command is initialized" do
155
- let(:pager) { 'less' }
156
-
157
- subject do
158
- command_class.new(env: {'PAGER' => pager})
159
- end
160
-
161
- context "and when given a single String" do
162
- let(:command) { "find ." }
163
-
164
- it "must run the command but piped into the pager" do
165
- expect(subject).to receive(:system).with("#{command} | #{pager}")
166
-
167
- subject.pipe_to_pager(command)
168
- end
169
- end
170
-
171
- context "and when given a String and additional arguments" do
172
- let(:command) { 'find' }
173
- let(:arguments) { %w[. -name *.md] }
174
-
175
- let(:escaped_command) do
176
- Shellwords.shelljoin([command,*arguments])
177
- end
178
-
179
- it "must shell escape the command and arguments" do
180
- expect(subject).to receive(:system).with(
181
- "#{escaped_command} | #{pager}"
182
- )
183
-
184
- subject.pipe_to_pager(command,*arguments)
185
- end
186
- end
187
- end
188
-
189
- context "when @pager_command is not initialized" do
190
- before do
191
- subject.instance_variable_set('@pager_command',nil)
192
- end
193
-
194
- let(:command) { 'find' }
195
- let(:arguments) { %w[. -name *.md] }
196
-
197
- it "must pass the command and any additional arguments to #system" do
198
- expect(subject).to receive(:system).with(command,*arguments)
199
-
200
- subject.pipe_to_pager(command,*arguments)
201
- end
202
-
203
- context "when one of the arguments is not a String" do
204
- let(:command) { :find }
205
- let(:arguments) { ['.', :"-name", "*.md"] }
206
-
207
- it "must convert the command to a String before calling #system" do
208
- expect(subject).to receive(:system).with(
209
- command.to_s, *arguments.map(&:to_s)
210
- )
211
-
212
- subject.pipe_to_pager(command,*arguments)
213
- end
214
- end
215
- end
216
- end
217
- end
@@ -1,167 +0,0 @@
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
@@ -1,132 +0,0 @@
1
- require 'spec_helper'
2
- require 'command_kit/printing/indent'
3
-
4
- describe CommandKit::Printing::Indent do
5
- module TestIndent
6
- class TestCommand
7
- include CommandKit::Printing::Indent
8
- end
9
- end
10
-
11
- let(:command_class) { TestIndent::TestCommand }
12
- subject { command_class.new }
13
-
14
- describe "#initialize" do
15
- it "must initialize #indent to 0" do
16
- expect(subject.indent).to eq(0)
17
- end
18
-
19
- context "when the class has a superclass" do
20
- module TestIndent
21
- class TestSuperCommand
22
-
23
- attr_reader :var
24
-
25
- def initialize(var: 'default')
26
- @var = var
27
- end
28
-
29
- end
30
-
31
- class TestSubCommand < TestSuperCommand
32
-
33
- include CommandKit::Printing::Indent
34
-
35
- end
36
- end
37
-
38
- let(:command_class) { TestIndent::TestSubCommand }
39
-
40
- it "must initialize @indent to 0" do
41
- expect(subject.indent).to eq(0)
42
- end
43
-
44
- it "must call super()" do
45
- expect(subject.var).to eq('default')
46
- end
47
-
48
- context "and additional keyword arguments are given" do
49
- let(:var) { 'foo' }
50
-
51
- subject { command_class.new(var: var) }
52
-
53
- it "must call super() with the additional keyword arguments" do
54
- expect(subject.var).to eq(var)
55
- end
56
- end
57
- end
58
- end
59
-
60
- describe "#indent" do
61
- context "when no block is given" do
62
- it "must return the indentation level" do
63
- expect(subject.indent).to eq(0)
64
- end
65
- end
66
-
67
- context "when a block is given" do
68
- it do
69
- expect { |b| subject.indent(&b) }.to yield_control
70
- end
71
-
72
- it "must increase the indent level by 2 then yield" do
73
- expect(subject.indent).to eq(0)
74
-
75
- subject.indent do
76
- expect(subject.indent).to eq(2)
77
- end
78
- end
79
-
80
- it "must restore the indententation level to it's original value" do
81
- subject.indent do
82
- expect(subject.indent).to eq(2)
83
- end
84
-
85
- expect(subject.indent).to eq(0)
86
- end
87
-
88
- context "when an exception occurrs within the given block" do
89
- it "must not rescue the exception" do
90
- expect {
91
- subject.indent do
92
- raise("error")
93
- end
94
- }.to raise_error(RuntimeError,"error")
95
- end
96
-
97
- it "must restore the indententation level to it's original value" do
98
- begin
99
- subject.indent do
100
- expect(subject.indent).to eq(2)
101
- raise("error")
102
- end
103
- rescue
104
- end
105
-
106
- expect(subject.indent).to eq(0)
107
- end
108
- end
109
- end
110
- end
111
-
112
- describe "#puts" do
113
- let(:nl) { $/ }
114
- let(:text) { 'hello world' }
115
-
116
- context "when the indententation level is 0" do
117
- it "must not add leading indentation" do
118
- expect { subject.puts(text) }.to output("#{text}#{nl}").to_stdout
119
- end
120
- end
121
-
122
- context "when the indententation level is > 0" do
123
- it "must add a number of spaces to the text" do
124
- expect {
125
- subject.indent do
126
- subject.puts(text)
127
- end
128
- }.to output(" #{text}#{nl}").to_stdout
129
- end
130
- end
131
- end
132
- end
@@ -1,99 +0,0 @@
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
@@ -1,43 +0,0 @@
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