command_kit 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.github/workflows/ruby.yml +29 -0
  4. data/.gitignore +7 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/ChangeLog.md +29 -0
  8. data/Gemfile +14 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +283 -0
  11. data/Rakefile +23 -0
  12. data/command_kit.gemspec +60 -0
  13. data/gemspec.yml +14 -0
  14. data/lib/command_kit.rb +1 -0
  15. data/lib/command_kit/arguments.rb +161 -0
  16. data/lib/command_kit/arguments/argument.rb +111 -0
  17. data/lib/command_kit/arguments/argument_value.rb +81 -0
  18. data/lib/command_kit/arguments/usage.rb +6 -0
  19. data/lib/command_kit/colors.rb +355 -0
  20. data/lib/command_kit/command.rb +42 -0
  21. data/lib/command_kit/command_name.rb +95 -0
  22. data/lib/command_kit/commands.rb +299 -0
  23. data/lib/command_kit/commands/auto_load.rb +153 -0
  24. data/lib/command_kit/commands/auto_load/subcommand.rb +90 -0
  25. data/lib/command_kit/commands/auto_require.rb +138 -0
  26. data/lib/command_kit/commands/command.rb +12 -0
  27. data/lib/command_kit/commands/help.rb +43 -0
  28. data/lib/command_kit/commands/parent_command.rb +21 -0
  29. data/lib/command_kit/commands/subcommand.rb +51 -0
  30. data/lib/command_kit/console.rb +141 -0
  31. data/lib/command_kit/description.rb +89 -0
  32. data/lib/command_kit/env.rb +43 -0
  33. data/lib/command_kit/env/home.rb +71 -0
  34. data/lib/command_kit/env/path.rb +71 -0
  35. data/lib/command_kit/examples.rb +99 -0
  36. data/lib/command_kit/exception_handler.rb +55 -0
  37. data/lib/command_kit/help.rb +62 -0
  38. data/lib/command_kit/help/man.rb +125 -0
  39. data/lib/command_kit/inflector.rb +84 -0
  40. data/lib/command_kit/main.rb +103 -0
  41. data/lib/command_kit/options.rb +179 -0
  42. data/lib/command_kit/options/option.rb +171 -0
  43. data/lib/command_kit/options/option_value.rb +90 -0
  44. data/lib/command_kit/options/parser.rb +227 -0
  45. data/lib/command_kit/options/quiet.rb +53 -0
  46. data/lib/command_kit/options/usage.rb +6 -0
  47. data/lib/command_kit/options/verbose.rb +55 -0
  48. data/lib/command_kit/options/version.rb +62 -0
  49. data/lib/command_kit/os.rb +47 -0
  50. data/lib/command_kit/pager.rb +115 -0
  51. data/lib/command_kit/printing.rb +32 -0
  52. data/lib/command_kit/printing/indent.rb +78 -0
  53. data/lib/command_kit/program_name.rb +57 -0
  54. data/lib/command_kit/stdio.rb +138 -0
  55. data/lib/command_kit/usage.rb +102 -0
  56. data/lib/command_kit/version.rb +4 -0
  57. data/lib/command_kit/xdg.rb +138 -0
  58. data/spec/arguments/argument_spec.rb +169 -0
  59. data/spec/arguments/argument_value_spec.rb +126 -0
  60. data/spec/arguments_spec.rb +213 -0
  61. data/spec/colors_spec.rb +470 -0
  62. data/spec/command_kit_spec.rb +8 -0
  63. data/spec/command_name_spec.rb +130 -0
  64. data/spec/command_spec.rb +49 -0
  65. data/spec/commands/auto_load/subcommand_spec.rb +82 -0
  66. data/spec/commands/auto_load_spec.rb +128 -0
  67. data/spec/commands/auto_require_spec.rb +142 -0
  68. data/spec/commands/fixtures/test_auto_load/cli/commands/test1.rb +10 -0
  69. data/spec/commands/fixtures/test_auto_load/cli/commands/test2.rb +10 -0
  70. data/spec/commands/fixtures/test_auto_require/lib/test_auto_require/cli/commands/test1.rb +10 -0
  71. data/spec/commands/help_spec.rb +66 -0
  72. data/spec/commands/parent_command_spec.rb +40 -0
  73. data/spec/commands/subcommand_spec.rb +99 -0
  74. data/spec/commands_spec.rb +767 -0
  75. data/spec/console_spec.rb +201 -0
  76. data/spec/description_spec.rb +203 -0
  77. data/spec/env/home_spec.rb +46 -0
  78. data/spec/env/path_spec.rb +78 -0
  79. data/spec/env_spec.rb +123 -0
  80. data/spec/examples_spec.rb +235 -0
  81. data/spec/exception_handler_spec.rb +103 -0
  82. data/spec/help_spec.rb +119 -0
  83. data/spec/inflector_spec.rb +104 -0
  84. data/spec/main_spec.rb +179 -0
  85. data/spec/options/option_spec.rb +258 -0
  86. data/spec/options/option_value_spec.rb +67 -0
  87. data/spec/options/parser_spec.rb +265 -0
  88. data/spec/options_spec.rb +137 -0
  89. data/spec/os_spec.rb +46 -0
  90. data/spec/pager_spec.rb +154 -0
  91. data/spec/printing/indent_spec.rb +130 -0
  92. data/spec/printing_spec.rb +76 -0
  93. data/spec/program_name_spec.rb +62 -0
  94. data/spec/spec_helper.rb +6 -0
  95. data/spec/stdio_spec.rb +264 -0
  96. data/spec/usage_spec.rb +237 -0
  97. data/spec/xdg_spec.rb +191 -0
  98. metadata +156 -0
@@ -0,0 +1,201 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/console'
3
+
4
+ require 'stringio'
5
+
6
+ describe Console do
7
+ module TestConsole
8
+ class TestCommand
9
+ include CommandKit::Console
10
+ end
11
+ end
12
+
13
+ let(:command_class) { TestConsole::TestCommand }
14
+ subject { command_class.new }
15
+
16
+ describe "#console?" do
17
+ context "when stdout is connected to a TTY" do
18
+ subject { command_class.new(stdout: STDOUT) }
19
+
20
+ it do
21
+ skip "STDOUT is not a TTY" unless STDOUT.tty?
22
+
23
+ expect(subject.console?).to be(true)
24
+ end
25
+ end
26
+
27
+ context "when stdout is not connected to a TTY" do
28
+ subject { command_class.new(stdout: StringIO.new) }
29
+
30
+ it do
31
+ expect(subject.console?).to be(false)
32
+ end
33
+ end
34
+
35
+ context "when IO.console is missing" do
36
+ before do
37
+ expect(IO).to receive(:respond_to?).with(:console).and_return(false)
38
+ end
39
+
40
+ it do
41
+ expect(subject.console?).to be(false)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "#console" 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.console).to eq(IO.console)
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.console).to eq(nil)
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.console).to be(nil)
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "#console_height" do
77
+ context "when stdout is connected to a TTY" do
78
+ subject { command_class.new(stdout: STDOUT) }
79
+
80
+ it do
81
+ skip "STDOUT is not a TTY" unless STDOUT.tty?
82
+
83
+ expect(subject.console_height).to eq(STDOUT.winsize[0])
84
+ end
85
+ end
86
+
87
+ context "when stdout is not connected to a TTY" do
88
+ subject { command_class.new(stdout: StringIO.new) }
89
+
90
+ it "must fallback to DEFAULT_HEIGHT" do
91
+ expect(subject.console_height).to eq(described_class::DEFAULT_HEIGHT)
92
+ end
93
+
94
+ context "but the LINES env variable was set" do
95
+ let(:lines) { 10 }
96
+ let(:env) { {'LINES' => lines.to_s} }
97
+
98
+ subject { command_class.new(stdout: StringIO.new, env: env) }
99
+
100
+ it "must fallback to the LINES environment variable" do
101
+ expect(subject.console_height).to eq(lines)
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "#console_width" do
108
+ context "when stdout is connected to a TTY" do
109
+ subject { command_class.new(stdout: STDOUT) }
110
+
111
+ it do
112
+ skip "STDOUT is not a TTY" unless STDOUT.tty?
113
+
114
+ expect(subject.console_width).to eq(STDOUT.winsize[1])
115
+ end
116
+ end
117
+
118
+ context "when stdout is not connected to a TTY" do
119
+ subject { command_class.new(stdout: StringIO.new) }
120
+
121
+ it "must fallback to DEFAULT_WIDTH" do
122
+ expect(subject.console_width).to eq(described_class::DEFAULT_WIDTH)
123
+ end
124
+
125
+ context "but the COLUMNS env variable was set" do
126
+ let(:columns) { 50 }
127
+ let(:env) { {'COLUMNS' => columns.to_s} }
128
+
129
+ subject { command_class.new(stdout: StringIO.new, env: env) }
130
+
131
+ it "must fallback to the COLUMNS environment variable" do
132
+ expect(subject.console_width).to eq(columns)
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ describe "#console_size" do
139
+ context "when stdout is connected to a TTY" do
140
+ subject { command_class.new(stdout: STDOUT) }
141
+
142
+ it do
143
+ skip "STDOUT is not a TTY" unless STDOUT.tty?
144
+
145
+ expect(subject.console_size).to eq(STDOUT.winsize)
146
+ end
147
+ end
148
+
149
+ context "when stdout is not connected to a TTY" do
150
+ subject { command_class.new(stdout: StringIO.new) }
151
+
152
+ it "must fallback to [DEFAULT_HEIGHT, DEFAULT_WIDTH]" do
153
+ expect(subject.console_size).to eq(
154
+ [described_class::DEFAULT_HEIGHT, described_class::DEFAULT_WIDTH]
155
+ )
156
+ end
157
+
158
+ context "but the LINES env variable was set" do
159
+ let(:lines) { 10 }
160
+ let(:env) { {'LINES' => lines.to_s} }
161
+
162
+ subject { command_class.new(stdout: StringIO.new, env: env) }
163
+
164
+ it "must fallback to the [$LINES, DEFAULT_WIDTH]" do
165
+ expect(subject.console_size).to eq(
166
+ [lines, described_class::DEFAULT_WIDTH]
167
+ )
168
+ end
169
+ end
170
+
171
+ context "but the COLUMNS env variable was set" do
172
+ let(:columns) { 50 }
173
+ let(:env) { {'COLUMNS' => columns.to_s} }
174
+
175
+ subject { command_class.new(stdout: StringIO.new, env: env) }
176
+
177
+ it "must fallback to the [DEFAULT_HEIGHT, COLUMNS]" do
178
+ expect(subject.console_size).to eq(
179
+ [described_class::DEFAULT_HEIGHT, columns]
180
+ )
181
+ end
182
+ end
183
+
184
+ context "but the LINES and COLUMNS env variable was set" do
185
+ let(:lines) { 10 }
186
+ let(:columns) { 50 }
187
+ let(:env) do
188
+ {'LINES' => lines.to_s, 'COLUMNS' => columns.to_s}
189
+ end
190
+
191
+ subject { command_class.new(stdout: StringIO.new, env: env) }
192
+
193
+ it "must fallback to the [LINES, COLUMNS]" do
194
+ expect(subject.console_size).to eq(
195
+ [lines, columns]
196
+ )
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,203 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/description'
3
+
4
+ describe Description do
5
+ module TestDescription
6
+ class ImplicitCmd
7
+ include CommandKit::Description
8
+ end
9
+ end
10
+
11
+ let(:command_class) { TestDescription::ImplicitCmd }
12
+
13
+ describe ".description" do
14
+ subject { TestDescription::ImplicitCmd }
15
+
16
+ context "when no description have been set" do
17
+ it "should default to nil" do
18
+ expect(subject.description).to be_nil
19
+ end
20
+ end
21
+
22
+ context "when a description is explicitly set" do
23
+ module TestDescription
24
+ class ExplicitCmd
25
+ include CommandKit::Description
26
+ description "Example command"
27
+ end
28
+ end
29
+
30
+ subject { TestDescription::ExplicitCmd }
31
+
32
+ it "must return the explicitly set description" do
33
+ expect(subject.description).to eq("Example command")
34
+ end
35
+ end
36
+
37
+ context "when the command class inherites from another class" do
38
+ context "but no description is set" do
39
+ module TestDescription
40
+ class BaseCmd
41
+ include CommandKit::Description
42
+ end
43
+
44
+ class InheritedCmd < BaseCmd
45
+ end
46
+ end
47
+
48
+ subject { TestDescription::InheritedCmd }
49
+
50
+ it "must search each class then return nil "do
51
+ expect(subject.description).to be_nil
52
+ end
53
+ end
54
+
55
+ module TestDescription
56
+ class ExplicitBaseCmd
57
+ include CommandKit::Description
58
+ description "Example base command"
59
+ end
60
+ end
61
+
62
+ context "when the superclass defines an explicit description" do
63
+ module TestDescription
64
+ class ImplicitInheritedCmd < ExplicitBaseCmd
65
+ end
66
+ end
67
+
68
+ let(:super_subject) { TestDescription::ExplicitBaseCmd }
69
+ subject { TestDescription::ImplicitInheritedCmd }
70
+
71
+ it "must inherit the superclass'es description" do
72
+ expect(subject.description).to eq(super_subject.description)
73
+ end
74
+
75
+ it "must not change the superclass'es description" do
76
+ expect(super_subject.description).to eq("Example base command")
77
+ end
78
+ end
79
+
80
+ context "when the subclass defines an explicit description" do
81
+ module TestDescription
82
+ class ImplicitBaseCmd
83
+ include CommandKit::Description
84
+ end
85
+
86
+ class ExplicitInheritedCmd < ImplicitBaseCmd
87
+ description "Example inherited command"
88
+ end
89
+ end
90
+
91
+ let(:super_subject) { TestDescription::ImplicitBaseCmd }
92
+ subject { TestDescription::ExplicitInheritedCmd }
93
+
94
+ it "must return the subclass'es description" do
95
+ expect(subject.description).to eq("Example inherited command")
96
+ end
97
+
98
+ it "must not change the superclass'es description" do
99
+ expect(super_subject.description).to be_nil
100
+ end
101
+ end
102
+
103
+ context "when both the subclass overrides the superclass's descriptions" do
104
+ module TestDescription
105
+ class ExplicitOverridingInheritedCmd < ExplicitBaseCmd
106
+ description "Example overrided description"
107
+ end
108
+ end
109
+
110
+ let(:super_subject) { TestDescription::ExplicitBaseCmd }
111
+ subject { TestDescription::ExplicitOverridingInheritedCmd }
112
+
113
+ it "must return the subclass'es description" do
114
+ expect(subject.description).to eq("Example overrided description")
115
+ end
116
+
117
+ it "must not change the superclass'es description" do
118
+ expect(super_subject.description).to eq("Example base command")
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ subject { command_class.new }
125
+
126
+ describe "#description" do
127
+ it "must be the same as .description" do
128
+ expect(subject.description).to eq(command_class.description)
129
+ end
130
+ end
131
+
132
+ describe "#help_description" do
133
+ context "when #description returns nil" do
134
+ module TestDescription
135
+ class NoDescription
136
+ include CommandKit::Description
137
+ end
138
+ end
139
+
140
+ let(:command_class) { TestDescription::NoDescription }
141
+ subject { command_class.new }
142
+
143
+ it "must print out the description" do
144
+ expect { subject.help_description }.to_not output.to_stdout
145
+ end
146
+ end
147
+
148
+ context "when #description returns a String" do
149
+ module TestDescription
150
+ class DefinesDescription
151
+ include CommandKit::Description
152
+
153
+ description "Example command"
154
+ end
155
+ end
156
+
157
+ let(:command_class) { TestDescription::DefinesDescription }
158
+ subject { command_class.new }
159
+
160
+ it "must print out the description" do
161
+ expect { subject.help_description }.to output(
162
+ [
163
+ '',
164
+ subject.description,
165
+ ''
166
+ ].join($/)
167
+ ).to_stdout
168
+ end
169
+ end
170
+ end
171
+
172
+ describe "#help" do
173
+ it "must call #help_description" do
174
+ expect(subject).to receive(:help_description)
175
+
176
+ subject.help
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
+ end
203
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/env/home'
3
+
4
+ describe Env::Home do
5
+ module TestEnvHome
6
+ class TestCommand
7
+ include CommandKit::Env::Home
8
+ end
9
+ end
10
+
11
+ let(:command_class) { TestEnvHome::TestCommand }
12
+
13
+ describe ".included" do
14
+ it "must include CommandKit::Env" do
15
+ expect(command_class).to be_include(CommandKit::Env)
16
+ end
17
+ end
18
+
19
+ describe ".home_dir" do
20
+ subject { command_class }
21
+
22
+ it "must return Gem.user_home" do
23
+ expect(subject.home_dir).to eq(Gem.user_home)
24
+ end
25
+ end
26
+
27
+ describe "#home_dir" do
28
+ context "when env['HOME'] is set" do
29
+ let(:home_dir) { '/path/to/home_dir' }
30
+
31
+ subject { command_class.new(env: {'HOME' => home_dir}) }
32
+
33
+ it "must return the env['HOME'] value" do
34
+ expect(subject.home_dir).to eq(home_dir)
35
+ end
36
+ end
37
+
38
+ context "when env['HOME'] is not set" do
39
+ subject { command_class.new(env: {}) }
40
+
41
+ it "must return .home_dir" do
42
+ expect(subject.home_dir).to eq(subject.class.home_dir)
43
+ end
44
+ end
45
+ end
46
+ end