command_kit 0.1.0.rc1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +17 -3
  3. data/.rubocop.yml +141 -0
  4. data/ChangeLog.md +102 -1
  5. data/Gemfile +3 -0
  6. data/README.md +187 -116
  7. data/Rakefile +3 -2
  8. data/command_kit.gemspec +4 -4
  9. data/examples/command.rb +1 -1
  10. data/gemspec.yml +8 -1
  11. data/lib/command_kit/arguments/argument.rb +2 -0
  12. data/lib/command_kit/arguments/argument_value.rb +2 -0
  13. data/lib/command_kit/arguments.rb +25 -6
  14. data/lib/command_kit/colors.rb +253 -45
  15. data/lib/command_kit/command.rb +6 -1
  16. data/lib/command_kit/command_name.rb +9 -0
  17. data/lib/command_kit/commands/auto_load.rb +24 -1
  18. data/lib/command_kit/commands/auto_require.rb +16 -0
  19. data/lib/command_kit/commands/command.rb +3 -0
  20. data/lib/command_kit/commands/help.rb +5 -2
  21. data/lib/command_kit/commands/parent_command.rb +7 -0
  22. data/lib/command_kit/commands/subcommand.rb +13 -1
  23. data/lib/command_kit/commands.rb +54 -9
  24. data/lib/command_kit/description.rb +12 -1
  25. data/lib/command_kit/env/home.rb +9 -0
  26. data/lib/command_kit/env/path.rb +16 -1
  27. data/lib/command_kit/env.rb +4 -0
  28. data/lib/command_kit/examples.rb +12 -1
  29. data/lib/command_kit/exception_handler.rb +4 -0
  30. data/lib/command_kit/help/man.rb +28 -31
  31. data/lib/command_kit/help.rb +7 -1
  32. data/lib/command_kit/inflector.rb +49 -17
  33. data/lib/command_kit/interactive.rb +71 -1
  34. data/lib/command_kit/main.rb +18 -9
  35. data/lib/command_kit/man.rb +44 -0
  36. data/lib/command_kit/open_app.rb +69 -0
  37. data/lib/command_kit/options/option.rb +3 -6
  38. data/lib/command_kit/options/option_value.rb +5 -2
  39. data/lib/command_kit/options/parser.rb +46 -19
  40. data/lib/command_kit/options/quiet.rb +3 -0
  41. data/lib/command_kit/options/verbose.rb +5 -0
  42. data/lib/command_kit/options/version.rb +6 -0
  43. data/lib/command_kit/options.rb +32 -7
  44. data/lib/command_kit/os/linux.rb +157 -0
  45. data/lib/command_kit/os.rb +165 -11
  46. data/lib/command_kit/package_manager.rb +200 -0
  47. data/lib/command_kit/pager.rb +73 -4
  48. data/lib/command_kit/printing/indent.rb +27 -4
  49. data/lib/command_kit/printing.rb +35 -1
  50. data/lib/command_kit/program_name.rb +7 -0
  51. data/lib/command_kit/stdio.rb +24 -0
  52. data/lib/command_kit/sudo.rb +40 -0
  53. data/lib/command_kit/terminal.rb +17 -0
  54. data/lib/command_kit/usage.rb +14 -0
  55. data/lib/command_kit/version.rb +1 -1
  56. data/lib/command_kit/xdg.rb +13 -0
  57. data/lib/command_kit.rb +1 -0
  58. data/spec/arguments/argument_spec.rb +2 -2
  59. data/spec/arguments_spec.rb +54 -28
  60. data/spec/colors_spec.rb +277 -13
  61. data/spec/command_name_spec.rb +1 -1
  62. data/spec/command_spec.rb +79 -5
  63. data/spec/commands/auto_load/subcommand_spec.rb +1 -1
  64. data/spec/commands/auto_load_spec.rb +34 -3
  65. data/spec/commands/auto_require_spec.rb +2 -2
  66. data/spec/commands/help_spec.rb +1 -1
  67. data/spec/commands/parent_command_spec.rb +1 -1
  68. data/spec/commands/subcommand_spec.rb +1 -1
  69. data/spec/commands_spec.rb +102 -30
  70. data/spec/description_spec.rb +1 -25
  71. data/spec/env/home_spec.rb +1 -1
  72. data/spec/env/path_spec.rb +7 -1
  73. data/spec/examples_spec.rb +1 -25
  74. data/spec/exception_handler_spec.rb +1 -1
  75. data/spec/help/man_spec.rb +55 -58
  76. data/spec/help_spec.rb +0 -25
  77. data/spec/inflector_spec.rb +71 -9
  78. data/spec/main_spec.rb +7 -7
  79. data/spec/man_spec.rb +46 -0
  80. data/spec/open_app_spec.rb +85 -0
  81. data/spec/options/option_spec.rb +5 -5
  82. data/spec/options/option_value_spec.rb +56 -1
  83. data/spec/options_spec.rb +283 -1
  84. data/spec/os/linux_spec.rb +164 -0
  85. data/spec/os_spec.rb +201 -14
  86. data/spec/package_manager_spec.rb +806 -0
  87. data/spec/pager_spec.rb +72 -7
  88. data/spec/printing/indent_spec.rb +8 -6
  89. data/spec/printing_spec.rb +33 -3
  90. data/spec/program_name_spec.rb +1 -1
  91. data/spec/spec_helper.rb +0 -3
  92. data/spec/sudo_spec.rb +51 -0
  93. data/spec/terminal_spec.rb +31 -1
  94. data/spec/usage_spec.rb +2 -2
  95. data/spec/xdg_spec.rb +1 -1
  96. metadata +21 -5
data/spec/pager_spec.rb CHANGED
@@ -3,7 +3,7 @@ require 'command_kit/pager'
3
3
 
4
4
  require 'stringio'
5
5
 
6
- describe Pager do
6
+ describe CommandKit::Pager do
7
7
  module TestPager
8
8
  class TestCommand
9
9
  include CommandKit::Pager
@@ -19,8 +19,8 @@ describe Pager do
19
19
 
20
20
  subject { command_class.new(env: {'PAGER' => pager}) }
21
21
 
22
- it "must set @pager to the PAGER env variable" do
23
- expect(subject.instance_variable_get('@pager')).to eq(pager)
22
+ it "must set @pager_command to the PAGER env variable" do
23
+ expect(subject.instance_variable_get('@pager_command')).to eq(pager)
24
24
  end
25
25
  end
26
26
 
@@ -29,7 +29,7 @@ describe Pager do
29
29
  subject { command_class.new(env: {'PATH' => ENV['PATH']}) }
30
30
 
31
31
  it "must search PATH for one of the pagers" do
32
- expect(subject.instance_variable_get('@pager')).to eq("less -r")
32
+ expect(subject.instance_variable_get('@pager_command')).to eq("less -r")
33
33
  end
34
34
  end
35
35
  end
@@ -46,9 +46,9 @@ describe Pager do
46
46
  end
47
47
  end
48
48
 
49
- context "when @pager isn't initialized" do
49
+ context "when @pager_command isn't initialized" do
50
50
  before do
51
- subject.instance_variable_set('@pager',nil)
51
+ subject.instance_variable_set('@pager_command',nil)
52
52
  end
53
53
 
54
54
  it "must yield stdout" do
@@ -58,7 +58,7 @@ describe Pager do
58
58
  end
59
59
  end
60
60
 
61
- context "when stdout is a TTY and @pager is initialized" do
61
+ context "when stdout is a TTY and @pager_command is initialized" do
62
62
  let(:pager) { 'less -r' }
63
63
 
64
64
  subject { command_class.new(env: {'PAGER' => pager}) }
@@ -149,4 +149,69 @@ describe Pager do
149
149
  end
150
150
  end
151
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
152
217
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/printing/indent'
3
3
 
4
- describe Printing::Indent do
4
+ describe CommandKit::Printing::Indent do
5
5
  module TestIndent
6
6
  class TestCommand
7
7
  include CommandKit::Printing::Indent
@@ -12,14 +12,16 @@ describe Printing::Indent do
12
12
  subject { command_class.new }
13
13
 
14
14
  describe "#initialize" do
15
- it "must initialize @indent to 0" do
16
- expect(subject.instance_variable_get('@indent')).to eq(0)
15
+ it "must initialize #indent to 0" do
16
+ expect(subject.indent).to eq(0)
17
17
  end
18
18
 
19
19
  context "when the class has a superclass" do
20
20
  module TestIndent
21
21
  class TestSuperCommand
22
22
 
23
+ attr_reader :var
24
+
23
25
  def initialize(var: 'default')
24
26
  @var = var
25
27
  end
@@ -36,11 +38,11 @@ describe Printing::Indent do
36
38
  let(:command_class) { TestIndent::TestSubCommand }
37
39
 
38
40
  it "must initialize @indent to 0" do
39
- expect(subject.instance_variable_get('@indent')).to eq(0)
41
+ expect(subject.indent).to eq(0)
40
42
  end
41
43
 
42
44
  it "must call super()" do
43
- expect(subject.instance_variable_get('@var')).to eq('default')
45
+ expect(subject.var).to eq('default')
44
46
  end
45
47
 
46
48
  context "and additional keyword arguments are given" do
@@ -49,7 +51,7 @@ describe Printing::Indent do
49
51
  subject { command_class.new(var: var) }
50
52
 
51
53
  it "must call super() with the additional keyword arguments" do
52
- expect(subject.instance_variable_get('@var')).to eq(var)
54
+ expect(subject.var).to eq(var)
53
55
  end
54
56
  end
55
57
  end
@@ -1,9 +1,10 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/printing'
3
+ require 'command_kit/command_name'
3
4
 
4
5
  require 'stringio'
5
6
 
6
- describe Printing do
7
+ describe CommandKit::Printing do
7
8
  module TestPrinting
8
9
  class TestCmd
9
10
 
@@ -14,11 +15,19 @@ describe Printing do
14
15
 
15
16
  let(:command_class) { TestPrinting::TestCmd }
16
17
  subject { command_class.new }
18
+
19
+ describe "EOL" do
20
+ subject { described_class::EOL }
21
+
22
+ it "must equal $/" do
23
+ expect(subject).to eq($/)
24
+ end
25
+ end
17
26
 
18
27
  describe ".included" do
19
28
  subject { command_class }
20
29
 
21
- it { expect(command_class).to include(Stdio) }
30
+ it { expect(command_class).to include(CommandKit::Stdio) }
22
31
  end
23
32
 
24
33
  let(:nl) { $/ }
@@ -26,11 +35,32 @@ describe Printing do
26
35
  describe "#print_error" do
27
36
  let(:message) { "oh no!" }
28
37
 
29
- it "must print a line to stderr" do
38
+ it "must print the error message to stderr" do
30
39
  expect {
31
40
  subject.print_error(message)
32
41
  }.to output("#{message}#{nl}").to_stderr
33
42
  end
43
+
44
+ context "and when CommandKit::CommandName is included" do
45
+ module TestPrinting
46
+ class TestCmdWithCommandName
47
+
48
+ include CommandKit::CommandName
49
+ include CommandKit::Printing
50
+
51
+ command_name 'foo'
52
+
53
+ end
54
+ end
55
+
56
+ let(:command_class) { TestPrinting::TestCmdWithCommandName }
57
+
58
+ it "must print the command_name and the error message" do
59
+ expect {
60
+ subject.print_error(message)
61
+ }.to output("#{subject.command_name}: #{message}#{nl}").to_stderr
62
+ end
63
+ end
34
64
  end
35
65
 
36
66
  describe "#print_exception" do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/program_name'
3
3
 
4
- describe ProgramName do
4
+ describe CommandKit::ProgramName do
5
5
  module TestProgramName
6
6
  class TestCmd
7
7
  include CommandKit::ProgramName
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,3 @@
1
1
  require 'rspec'
2
2
  require 'simplecov'
3
3
  SimpleCov.start
4
-
5
- require 'command_kit/version'
6
- include CommandKit
data/spec/sudo_spec.rb ADDED
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/sudo'
3
+
4
+ describe CommandKit::Sudo do
5
+ module TestSudo
6
+ class TestCommand
7
+ include CommandKit::Sudo
8
+ end
9
+ end
10
+
11
+ let(:command_class) { TestSudo::TestCommand }
12
+ subject { command_class.new }
13
+
14
+ describe "#sudo" do
15
+ let(:command) { "ls" }
16
+ let(:arguments) { ["-la", "~root"] }
17
+ let(:status) { double(:status) }
18
+
19
+ context "on UNIX" do
20
+ context "when the UID is 0" do
21
+ before { allow(Process).to receive(:uid).and_return(0) }
22
+
23
+ it "must execute the command without sudo" do
24
+ expect(subject).to receive(:system).with(command,*arguments).and_return(status)
25
+
26
+ expect(subject.sudo(command,*arguments)).to be(status)
27
+ end
28
+ end
29
+
30
+ context "when the UID is not 0" do
31
+ before { allow(Process).to receive(:uid).and_return(1000) }
32
+
33
+ it "must execute the command with 'sudo ...'" do
34
+ expect(subject).to receive(:system).with('sudo',command,*arguments).and_return(status)
35
+
36
+ expect(subject.sudo(command,*arguments)).to be(status)
37
+ end
38
+ end
39
+ end
40
+
41
+ context "on Windows" do
42
+ subject { command_class.new(os: :windows) }
43
+
44
+ it "must execute the command with 'runas /user:administrator ...'" do
45
+ expect(subject).to receive(:system).with('runas','/user:administrator',command,*arguments).and_return(status)
46
+
47
+ expect(subject.sudo(command,*arguments)).to be(status)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -3,7 +3,7 @@ require 'command_kit/terminal'
3
3
 
4
4
  require 'stringio'
5
5
 
6
- describe Terminal do
6
+ describe CommandKit::Terminal do
7
7
  module TestTerminal
8
8
  class TestCommand
9
9
  include CommandKit::Terminal
@@ -43,6 +43,36 @@ describe Terminal do
43
43
  end
44
44
  end
45
45
 
46
+ describe "#tty?" do
47
+ context "when stdout is connected to a TTY" do
48
+ subject { command_class.new(stdout: STDOUT) }
49
+
50
+ it do
51
+ skip "STDOUT is not a TTY" unless STDOUT.tty?
52
+
53
+ expect(subject.tty?).to be(true)
54
+ end
55
+ end
56
+
57
+ context "when stdout is not connected to a TTY" do
58
+ subject { command_class.new(stdout: StringIO.new) }
59
+
60
+ it do
61
+ expect(subject.tty?).to be(false)
62
+ end
63
+ end
64
+
65
+ context "when IO.console is missing" do
66
+ before do
67
+ expect(IO).to receive(:respond_to?).with(:console).and_return(false)
68
+ end
69
+
70
+ it do
71
+ expect(subject.tty?).to be(false)
72
+ end
73
+ end
74
+ end
75
+
46
76
  describe "#terminal" do
47
77
  context "when stdout is connected to a TTY" do
48
78
  subject { command_class.new(stdout: STDOUT) }
data/spec/usage_spec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/usage'
3
3
 
4
- describe Usage do
4
+ describe CommandKit::Usage do
5
5
  module TestUsage
6
6
  class ImplicitCmd
7
7
  include CommandKit::Usage
@@ -182,7 +182,7 @@ describe Usage do
182
182
  [
183
183
  "#{subject.command_name} #{command_class.usage[0]}",
184
184
  "#{subject.command_name} #{command_class.usage[1]}",
185
- "#{subject.command_name} #{command_class.usage[2]}",
185
+ "#{subject.command_name} #{command_class.usage[2]}"
186
186
  ]
187
187
  )
188
188
  end
data/spec/xdg_spec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'command_kit/xdg'
3
3
 
4
- describe XDG do
4
+ describe CommandKit::XDG do
5
5
  module TestXDG
6
6
  class TestCommand
7
7
  include CommandKit::XDG
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.rc1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Postmodern
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-02 00:00:00.000000000 Z
11
+ date: 2021-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,7 @@ files:
38
38
  - ".github/workflows/ruby.yml"
39
39
  - ".gitignore"
40
40
  - ".rspec"
41
+ - ".rubocop.yml"
41
42
  - ".yardopts"
42
43
  - ChangeLog.md
43
44
  - Gemfile
@@ -75,6 +76,8 @@ files:
75
76
  - lib/command_kit/inflector.rb
76
77
  - lib/command_kit/interactive.rb
77
78
  - lib/command_kit/main.rb
79
+ - lib/command_kit/man.rb
80
+ - lib/command_kit/open_app.rb
78
81
  - lib/command_kit/options.rb
79
82
  - lib/command_kit/options/option.rb
80
83
  - lib/command_kit/options/option_value.rb
@@ -83,11 +86,14 @@ files:
83
86
  - lib/command_kit/options/verbose.rb
84
87
  - lib/command_kit/options/version.rb
85
88
  - lib/command_kit/os.rb
89
+ - lib/command_kit/os/linux.rb
90
+ - lib/command_kit/package_manager.rb
86
91
  - lib/command_kit/pager.rb
87
92
  - lib/command_kit/printing.rb
88
93
  - lib/command_kit/printing/indent.rb
89
94
  - lib/command_kit/program_name.rb
90
95
  - lib/command_kit/stdio.rb
96
+ - lib/command_kit/sudo.rb
91
97
  - lib/command_kit/terminal.rb
92
98
  - lib/command_kit/usage.rb
93
99
  - lib/command_kit/version.rb
@@ -120,24 +126,34 @@ files:
120
126
  - spec/inflector_spec.rb
121
127
  - spec/interactive_spec.rb
122
128
  - spec/main_spec.rb
129
+ - spec/man_spec.rb
130
+ - spec/open_app_spec.rb
123
131
  - spec/options/option_spec.rb
124
132
  - spec/options/option_value_spec.rb
125
133
  - spec/options/parser_spec.rb
126
134
  - spec/options_spec.rb
135
+ - spec/os/linux_spec.rb
127
136
  - spec/os_spec.rb
137
+ - spec/package_manager_spec.rb
128
138
  - spec/pager_spec.rb
129
139
  - spec/printing/indent_spec.rb
130
140
  - spec/printing_spec.rb
131
141
  - spec/program_name_spec.rb
132
142
  - spec/spec_helper.rb
133
143
  - spec/stdio_spec.rb
144
+ - spec/sudo_spec.rb
134
145
  - spec/terminal_spec.rb
135
146
  - spec/usage_spec.rb
136
147
  - spec/xdg_spec.rb
137
- homepage: https://github.com/postmodern/command_kit#readme
148
+ homepage: https://github.com/postmodern/command_kit.rb#readme
138
149
  licenses:
139
150
  - MIT
140
- metadata: {}
151
+ metadata:
152
+ documentation_uri: https://rubydoc.info/gems/command_kit
153
+ source_code_uri: https://github.com/postmodern/command_kit.rb
154
+ bug_tracker_uri: https://github.com/postmodern/command_kit.rb/issues
155
+ changelog_uri: https://github.com/postmodern/command_kit.rb/blob/main/ChangeLog.md
156
+ rubygems_mfa_required: 'true'
141
157
  post_install_message:
142
158
  rdoc_options: []
143
159
  require_paths:
@@ -153,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
169
  - !ruby/object:Gem::Version
154
170
  version: '0'
155
171
  requirements: []
156
- rubygems_version: 3.2.15
172
+ rubygems_version: 3.2.22
157
173
  signing_key:
158
174
  specification_version: 4
159
175
  summary: A toolkit for building Ruby CLI commands