command_kit 0.1.0.pre1 → 0.2.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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +15 -0
  3. data/.rubocop.yml +138 -0
  4. data/ChangeLog.md +34 -2
  5. data/Gemfile +3 -0
  6. data/README.md +135 -214
  7. data/Rakefile +3 -2
  8. data/command_kit.gemspec +4 -4
  9. data/examples/colors.rb +30 -0
  10. data/examples/command.rb +65 -0
  11. data/examples/pager.rb +30 -0
  12. data/gemspec.yml +10 -2
  13. data/lib/command_kit/arguments/argument.rb +16 -44
  14. data/lib/command_kit/arguments/argument_value.rb +3 -30
  15. data/lib/command_kit/arguments.rb +66 -20
  16. data/lib/command_kit/colors.rb +253 -45
  17. data/lib/command_kit/command.rb +50 -3
  18. data/lib/command_kit/command_name.rb +9 -0
  19. data/lib/command_kit/commands/auto_load/subcommand.rb +3 -0
  20. data/lib/command_kit/commands/auto_load.rb +16 -0
  21. data/lib/command_kit/commands/auto_require.rb +16 -0
  22. data/lib/command_kit/commands/command.rb +3 -0
  23. data/lib/command_kit/commands/help.rb +2 -0
  24. data/lib/command_kit/commands/parent_command.rb +7 -0
  25. data/lib/command_kit/commands/subcommand.rb +15 -0
  26. data/lib/command_kit/commands.rb +40 -4
  27. data/lib/command_kit/description.rb +15 -2
  28. data/lib/command_kit/env/home.rb +9 -0
  29. data/lib/command_kit/env/path.rb +15 -0
  30. data/lib/command_kit/env.rb +4 -0
  31. data/lib/command_kit/examples.rb +15 -2
  32. data/lib/command_kit/exception_handler.rb +4 -0
  33. data/lib/command_kit/help/man.rb +74 -47
  34. data/lib/command_kit/help.rb +10 -1
  35. data/lib/command_kit/inflector.rb +49 -17
  36. data/lib/command_kit/interactive.rb +239 -0
  37. data/lib/command_kit/main.rb +20 -9
  38. data/lib/command_kit/man.rb +44 -0
  39. data/lib/command_kit/open_app.rb +69 -0
  40. data/lib/command_kit/options/option.rb +36 -9
  41. data/lib/command_kit/options/option_value.rb +42 -3
  42. data/lib/command_kit/options/parser.rb +44 -17
  43. data/lib/command_kit/options/quiet.rb +3 -0
  44. data/lib/command_kit/options/verbose.rb +5 -0
  45. data/lib/command_kit/options/version.rb +6 -0
  46. data/lib/command_kit/options.rb +59 -10
  47. data/lib/command_kit/os/linux.rb +157 -0
  48. data/lib/command_kit/os.rb +165 -11
  49. data/lib/command_kit/package_manager.rb +200 -0
  50. data/lib/command_kit/pager.rb +84 -9
  51. data/lib/command_kit/printing/indent.rb +25 -2
  52. data/lib/command_kit/printing.rb +23 -0
  53. data/lib/command_kit/program_name.rb +7 -0
  54. data/lib/command_kit/stdio.rb +24 -0
  55. data/lib/command_kit/sudo.rb +40 -0
  56. data/lib/command_kit/terminal.rb +159 -0
  57. data/lib/command_kit/usage.rb +14 -0
  58. data/lib/command_kit/version.rb +1 -1
  59. data/lib/command_kit/xdg.rb +21 -1
  60. data/lib/command_kit.rb +1 -0
  61. data/spec/arguments/argument_spec.rb +5 -41
  62. data/spec/arguments/argument_value_spec.rb +1 -61
  63. data/spec/arguments_spec.rb +8 -25
  64. data/spec/colors_spec.rb +277 -13
  65. data/spec/command_name_spec.rb +1 -1
  66. data/spec/command_spec.rb +4 -1
  67. data/spec/commands/auto_load/subcommand_spec.rb +1 -1
  68. data/spec/commands/auto_load_spec.rb +1 -1
  69. data/spec/commands/auto_require_spec.rb +2 -2
  70. data/spec/commands/help_spec.rb +1 -1
  71. data/spec/commands/parent_command_spec.rb +1 -1
  72. data/spec/commands/subcommand_spec.rb +1 -1
  73. data/spec/commands_spec.rb +2 -2
  74. data/spec/description_spec.rb +1 -25
  75. data/spec/env/home_spec.rb +1 -1
  76. data/spec/env/path_spec.rb +1 -1
  77. data/spec/examples_spec.rb +1 -25
  78. data/spec/exception_handler_spec.rb +1 -1
  79. data/spec/help/man_spec.rb +316 -0
  80. data/spec/help_spec.rb +0 -25
  81. data/spec/inflector_spec.rb +71 -9
  82. data/spec/interactive_spec.rb +415 -0
  83. data/spec/main_spec.rb +7 -7
  84. data/spec/man_spec.rb +46 -0
  85. data/spec/open_app_spec.rb +85 -0
  86. data/spec/options/option_spec.rb +48 -9
  87. data/spec/options/option_value_spec.rb +53 -4
  88. data/spec/options_spec.rb +1 -1
  89. data/spec/os/linux_spec.rb +154 -0
  90. data/spec/os_spec.rb +201 -14
  91. data/spec/package_manager_spec.rb +806 -0
  92. data/spec/pager_spec.rb +78 -15
  93. data/spec/printing/indent_spec.rb +1 -1
  94. data/spec/printing_spec.rb +10 -2
  95. data/spec/program_name_spec.rb +1 -1
  96. data/spec/spec_helper.rb +0 -3
  97. data/spec/sudo_spec.rb +51 -0
  98. data/spec/{console_spec.rb → terminal_spec.rb} +65 -35
  99. data/spec/usage_spec.rb +2 -2
  100. data/spec/xdg_spec.rb +1 -1
  101. metadata +32 -13
  102. data/lib/command_kit/arguments/usage.rb +0 -6
  103. data/lib/command_kit/console.rb +0 -141
  104. data/lib/command_kit/options/usage.rb +0 -6
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/command_name'
3
3
 
4
- describe CommandName do
4
+ describe CommandKit::CommandName do
5
5
  module TestCommandName
6
6
  class ImplicitCmd
7
7
  include CommandKit::CommandName
data/spec/command_spec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/command'
3
3
 
4
- describe Command do
4
+ describe CommandKit::Command do
5
5
  it "must include CommandKit::Main" do
6
6
  expect(described_class).to include(CommandKit::Main)
7
7
  end
@@ -46,4 +46,7 @@ describe Command do
46
46
  expect(described_class).to include(CommandKit::ExceptionHandler)
47
47
  end
48
48
 
49
+ it "must include FileUtils" do
50
+ expect(described_class).to include(FileUtils)
51
+ end
49
52
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/commands/auto_load/subcommand'
3
3
 
4
- describe Commands::AutoLoad::Subcommand do
4
+ describe CommandKit::Commands::AutoLoad::Subcommand do
5
5
  let(:fixtures_dir) { File.expand_path('../../fixtures',__FILE__) }
6
6
 
7
7
  let(:file) { 'test1.rb' }
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/commands/auto_load'
3
3
 
4
- describe Commands::AutoLoad do
4
+ describe CommandKit::Commands::AutoLoad do
5
5
  let(:fixtures_dir) { File.expand_path('../fixtures',__FILE__) }
6
6
 
7
7
  let(:dir) { File.join(fixtures_dir,'test_auto_load','cli','commands') }
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/commands/auto_require'
3
3
 
4
- describe Commands::AutoRequire do
4
+ describe CommandKit::Commands::AutoRequire do
5
5
  let(:fixtures_dir) { File.expand_path('../fixtures',__FILE__) }
6
6
  let(:lib_dir) { File.join(fixtures_dir,'test_auto_require','lib') }
7
7
  let(:dir) { File.join('test_auto_require','cli','commands') }
@@ -126,7 +126,7 @@ describe Commands::AutoRequire do
126
126
 
127
127
  it "the .commands.default_proc must auto-require commands and return a Subcommand" do
128
128
  expect(command_class.commands[command_name]).to_not be(nil)
129
- expect(command_class.commands[command_name]).to be_kind_of(Commands::Subcommand)
129
+ expect(command_class.commands[command_name]).to be_kind_of(CommandKit::Commands::Subcommand)
130
130
  expect(command_class.commands[command_name].command).to eq(TestAutoRequire::CLI::Commands::Test1)
131
131
  end
132
132
 
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'command_kit/commands/help'
3
3
  require 'command_kit/commands'
4
4
 
5
- describe Commands::Help do
5
+ describe CommandKit::Commands::Help do
6
6
  module TestHelpCommand
7
7
  class CLI
8
8
  include CommandKit::Commands
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'command_kit/commands'
3
3
  require 'command_kit/commands/parent_command'
4
4
 
5
- describe Commands::ParentCommand do
5
+ describe CommandKit::Commands::ParentCommand do
6
6
  module TestParentCommand
7
7
  class TestCommands
8
8
 
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'command_kit/commands/subcommand'
3
3
  require 'command_kit/command'
4
4
 
5
- describe Commands::Subcommand do
5
+ describe CommandKit::Commands::Subcommand do
6
6
  module TestSubcommands
7
7
  class TestCommand < CommandKit::Command
8
8
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/commands'
3
3
 
4
- describe Commands do
4
+ describe CommandKit::Commands do
5
5
  module TestCommands
6
6
  class TestEmptyCommands
7
7
 
@@ -191,7 +191,7 @@ describe Commands do
191
191
  it "must contain the mapping of aliases to command names" do
192
192
  expect(subject.command_aliases).to eq({
193
193
  't1' => 'test1',
194
- 't2' => 'test2',
194
+ 't2' => 'test2'
195
195
  })
196
196
  end
197
197
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/description'
3
3
 
4
- describe Description do
4
+ describe CommandKit::Description do
5
5
  module TestDescription
6
6
  class ImplicitCmd
7
7
  include CommandKit::Description
@@ -175,29 +175,5 @@ describe Description do
175
175
 
176
176
  subject.help
177
177
  end
178
-
179
- context "when the superclass defines it's own #help method" do
180
- module TestDescription
181
- class SuperclassHelpMethod
182
- def help
183
- puts 'superclass'
184
- end
185
- end
186
-
187
- class InheritedHelpMethod < SuperclassHelpMethod
188
- include CommandKit::Description
189
- end
190
- end
191
-
192
- let(:super_command_class) { TestDescription::SuperclassHelpMethod }
193
- let(:command_class) { TestDescription::InheritedHelpMethod }
194
-
195
- it "must call the superclass'es #help method first" do
196
- expect_any_instance_of(super_command_class).to receive(:help)
197
- expect(subject).to receive(:help_description)
198
-
199
- subject.help
200
- end
201
- end
202
178
  end
203
179
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/env/home'
3
3
 
4
- describe Env::Home do
4
+ describe CommandKit::Env::Home do
5
5
  module TestEnvHome
6
6
  class TestCommand
7
7
  include CommandKit::Env::Home
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/env/path'
3
3
 
4
- describe Env::Path do
4
+ describe CommandKit::Env::Path do
5
5
  module TestEnvPath
6
6
  class TestCommand
7
7
 
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/examples'
3
3
 
4
- describe Examples do
4
+ describe CommandKit::Examples do
5
5
  module TestExamples
6
6
  class ImplicitCmd
7
7
  include CommandKit::Examples
@@ -207,29 +207,5 @@ describe Examples do
207
207
 
208
208
  subject.help
209
209
  end
210
-
211
- context "when the superclass defines it's own #help method" do
212
- module TestDescription
213
- class SuperclassHelpMethod
214
- def help
215
- puts 'superclass'
216
- end
217
- end
218
-
219
- class InheritedHelpMethod < SuperclassHelpMethod
220
- include CommandKit::Examples
221
- end
222
- end
223
-
224
- let(:super_command_class) { TestDescription::SuperclassHelpMethod }
225
- let(:command_class) { TestDescription::InheritedHelpMethod }
226
-
227
- it "must call the superclass'es #help method first" do
228
- expect_any_instance_of(super_command_class).to receive(:help)
229
- expect(subject).to receive(:help_examples)
230
-
231
- subject.help
232
- end
233
- end
234
210
  end
235
211
  end
@@ -73,7 +73,7 @@ describe CommandKit::ExceptionHandler do
73
73
  include CommandKit::ExceptionHandler
74
74
 
75
75
  def run
76
- raise(RuntimeError.new("error"))
76
+ raise("error")
77
77
  end
78
78
 
79
79
  end
@@ -0,0 +1,316 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/help/man'
3
+
4
+ describe CommandKit::Help::Man do
5
+ module TestHelpMan
6
+ class TestCommand
7
+ include CommandKit::Help::Man
8
+
9
+ man_dir "#{__dir__}/fixtures/man"
10
+ end
11
+
12
+ class TestCommandWithManPage
13
+ include CommandKit::Help::Man
14
+
15
+ man_dir "#{__dir__}/fixtures/man"
16
+ man_page 'foo.1'
17
+ end
18
+
19
+ class EmptyCommand
20
+ include CommandKit::Help::Man
21
+ end
22
+ end
23
+
24
+ let(:command_class) { TestHelpMan::TestCommand }
25
+
26
+ describe ".included" do
27
+ subject { command_class }
28
+
29
+ it "must include CommandName" do
30
+ expect(subject).to include(CommandKit::CommandName)
31
+ end
32
+
33
+ it "must include Help" do
34
+ expect(subject).to include(CommandKit::Help)
35
+ end
36
+
37
+ it "must include Stdio" do
38
+ expect(subject).to include(CommandKit::Stdio)
39
+ end
40
+ end
41
+
42
+ describe ".man_dir" do
43
+ context "when no man_dir have been set" do
44
+ subject { TestHelpMan::EmptyCommand }
45
+
46
+ it "should default to nil" do
47
+ expect(subject.man_dir).to be_nil
48
+ end
49
+ end
50
+
51
+ context "when a man_dir is explicitly set" do
52
+ subject { TestHelpMan::TestCommand }
53
+
54
+ it "must return the explicitly set man_dir" do
55
+ expect(subject.man_dir).to eq(File.expand_path('../fixtures/man',__FILE__))
56
+ end
57
+ end
58
+
59
+ context "when the command class inherites from another class" do
60
+ context "but no man_dir is set" do
61
+ module TestHelpMan
62
+ class BaseCmd
63
+ include CommandKit::Help::Man
64
+ end
65
+
66
+ class InheritedCmd < BaseCmd
67
+ end
68
+ end
69
+
70
+ subject { TestHelpMan::InheritedCmd }
71
+
72
+ it "must search each class then return nil "do
73
+ expect(subject.man_dir).to be_nil
74
+ end
75
+ end
76
+
77
+ module TestHelpMan
78
+ class ExplicitBaseCmd
79
+ include CommandKit::Help::Man
80
+
81
+ man_dir 'set/in/baseclass'
82
+ end
83
+ end
84
+
85
+ context "when the superclass defines an explicit man_dir" do
86
+ module TestHelpMan
87
+ class ImplicitInheritedCmd < ExplicitBaseCmd
88
+ end
89
+ end
90
+
91
+ let(:super_subject) { TestHelpMan::ExplicitBaseCmd }
92
+ subject { TestHelpMan::ImplicitInheritedCmd }
93
+
94
+ it "must inherit the superclass'es man_dir" do
95
+ expect(subject.man_dir).to eq(super_subject.man_dir)
96
+ end
97
+
98
+ it "must not change the superclass'es man_dir" do
99
+ expect(super_subject.man_dir).to eq('set/in/baseclass')
100
+ end
101
+ end
102
+
103
+ context "when the subclass defines an explicit man_dir" do
104
+ module TestHelpMan
105
+ class ImplicitBaseCmd
106
+ include CommandKit::Help::Man
107
+ end
108
+
109
+ class ExplicitInheritedCmd < ImplicitBaseCmd
110
+ man_dir 'set/in/subclass'
111
+ end
112
+ end
113
+
114
+ let(:super_subject) { TestHelpMan::ImplicitBaseCmd }
115
+ subject { TestHelpMan::ExplicitInheritedCmd }
116
+
117
+ it "must return the subclass'es man_dir" do
118
+ expect(subject.man_dir).to eq('set/in/subclass')
119
+ end
120
+
121
+ it "must not change the superclass'es man_dir" do
122
+ expect(super_subject.man_dir).to be_nil
123
+ end
124
+ end
125
+
126
+ context "when both the subclass overrides the superclass's man_dirs" do
127
+ module TestHelpMan
128
+ class ExplicitOverridingInheritedCmd < ExplicitBaseCmd
129
+ man_dir 'set/in/subclass'
130
+ end
131
+ end
132
+
133
+ let(:super_subject) { TestHelpMan::ExplicitBaseCmd }
134
+ subject { TestHelpMan::ExplicitOverridingInheritedCmd }
135
+
136
+ it "must return the subclass'es man_dir" do
137
+ expect(subject.man_dir).to eq('set/in/subclass')
138
+ end
139
+
140
+ it "must not change the superclass'es man_dir" do
141
+ expect(super_subject.man_dir).to eq('set/in/baseclass')
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ describe ".man_page" do
148
+ context "when no man_page has been set" do
149
+ subject { TestHelpMan::TestCommand }
150
+
151
+ it "should default to \"\#{command_name}.1\"" do
152
+ expect(subject.man_page).to eq("#{subject.command_name}.1")
153
+ end
154
+ end
155
+
156
+ context "when a man_page is explicitly set" do
157
+ module TestHelpMan
158
+ class ExplicitCmd
159
+ include CommandKit::Help::Man
160
+ man_page 'explicit.1'
161
+ end
162
+ end
163
+
164
+ subject { TestHelpMan::ExplicitCmd }
165
+
166
+ it "must return the explicitly set man_page" do
167
+ expect(subject.man_page).to eq('explicit.1')
168
+ end
169
+ end
170
+
171
+ context "when the command class inherites from another class" do
172
+ module TestHelpMan
173
+ class BaseCmd
174
+ include CommandKit::Help::Man
175
+ end
176
+
177
+ class InheritedCmd < BaseCmd
178
+ end
179
+ end
180
+
181
+ subject { TestHelpMan::InheritedCmd }
182
+
183
+ it "should underscore the class'es name" do
184
+ expect(subject.man_page).to eq('inherited_cmd.1')
185
+ end
186
+
187
+ context "when the superclass defines an explicit man_page" do
188
+ module TestHelpMan
189
+ class ExplicitBaseCmd
190
+ include CommandKit::Help::Man
191
+ man_page 'explicit.1'
192
+ end
193
+
194
+ class ImplicitInheritedCmd < ExplicitBaseCmd
195
+ end
196
+ end
197
+
198
+ let(:super_subject) { TestHelpMan::ExplicitBaseCmd }
199
+ subject { TestHelpMan::ImplicitInheritedCmd }
200
+
201
+ it "must return the subclass'es man_page, not the superclass'es" do
202
+ expect(subject.man_page).to eq('implicit_inherited_cmd.1')
203
+ end
204
+
205
+ it "must not change the superclass'es man_page" do
206
+ expect(super_subject.man_page).to eq('explicit.1')
207
+ end
208
+ end
209
+
210
+ context "when the subclass defines an explicit man_page" do
211
+ module TestHelpMan
212
+ class ImplicitBaseCmd
213
+ include CommandKit::Help::Man
214
+ end
215
+
216
+ class ExplicitInheritedCmd < ImplicitBaseCmd
217
+ man_page 'explicit.1'
218
+ end
219
+ end
220
+
221
+ let(:super_subject) { TestHelpMan::ImplicitBaseCmd }
222
+ subject { TestHelpMan::ExplicitInheritedCmd }
223
+
224
+ it "must return the subclass'es man_page, not the superclass'es" do
225
+ expect(subject.man_page).to eq('explicit.1')
226
+ end
227
+
228
+ it "must not change the superclass'es man_page" do
229
+ expect(super_subject.man_page).to eq('implicit_base_cmd.1')
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+ subject { command_class.new }
236
+
237
+ describe "#help_man" do
238
+ context "when .man_dir is not set" do
239
+ let(:command_class) { TestHelpMan::EmptyCommand }
240
+ subject { command_class.new }
241
+
242
+ it do
243
+ expect { subject.help_man }.to raise_error(NotImplementedError)
244
+ end
245
+ end
246
+
247
+ let(:man_page_path) do
248
+ File.join(subject.class.man_dir,subject.class.man_page)
249
+ end
250
+
251
+ it "must open the .man_page within the .man_dir" do
252
+ expect(subject).to receive(:system).with('man',man_page_path)
253
+
254
+ subject.help_man
255
+ end
256
+
257
+ context "when given a custom man page" do
258
+ let(:man_page) { 'bar.1' }
259
+ let(:man_page_path) { File.join(subject.class.man_dir,man_page) }
260
+
261
+ it "must open the custom man-page within the .man_dir" do
262
+ expect(subject).to receive(:system).with('man',man_page_path)
263
+
264
+ subject.help_man(man_page)
265
+ end
266
+ end
267
+ end
268
+
269
+ describe "#help" do
270
+ let(:normal_help_output) do
271
+ stdout = StringIO.new
272
+
273
+ command_class.new(stdout: stdout).tap do |command|
274
+ command.method(:help).super_method.call
275
+ end
276
+
277
+ stdout.string
278
+ end
279
+
280
+ let(:stdout) { StringIO.new }
281
+
282
+ subject { command_class.new(stdout: stdout) }
283
+
284
+ context "when stdout is a TTY" do
285
+ before do
286
+ expect(subject.stdout).to receive(:tty?).and_return(true)
287
+ end
288
+
289
+ it "must open the command's man-page" do
290
+ expect(subject).to receive(:help_man).and_return(true)
291
+
292
+ subject.help
293
+ end
294
+
295
+ context "but when the man command is not installed" do
296
+ before do
297
+ expect(subject).to receive(:help_man).and_return(nil)
298
+ end
299
+
300
+ it "must call the super help() method" do
301
+ subject.help
302
+
303
+ expect(subject.stdout.string).to eq(normal_help_output)
304
+ end
305
+ end
306
+ end
307
+
308
+ context "when stdout is not a TTY" do
309
+ it "must call the super help() method" do
310
+ subject.help
311
+
312
+ expect(stdout.string).to eq(normal_help_output)
313
+ end
314
+ end
315
+ end
316
+ end