command_kit 0.3.0 → 0.4.1

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +6 -6
  3. data/.rubocop.yml +16 -0
  4. data/ChangeLog.md +30 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE.txt +1 -1
  7. data/README.md +18 -9
  8. data/command_kit.gemspec +0 -1
  9. data/examples/printing/tables.rb +141 -0
  10. data/examples/subcommands/cli/config/get.rb +47 -0
  11. data/examples/subcommands/cli/config/set.rb +44 -0
  12. data/examples/subcommands/cli/config.rb +23 -0
  13. data/examples/subcommands/cli/list.rb +35 -0
  14. data/examples/subcommands/cli/update.rb +47 -0
  15. data/examples/subcommands/cli.rb +55 -0
  16. data/gemspec.yml +3 -3
  17. data/lib/command_kit/bug_report.rb +105 -0
  18. data/lib/command_kit/colors.rb +4 -4
  19. data/lib/command_kit/edit.rb +54 -0
  20. data/lib/command_kit/env/home.rb +1 -1
  21. data/lib/command_kit/env.rb +1 -1
  22. data/lib/command_kit/inflector.rb +1 -1
  23. data/lib/command_kit/options/option.rb +5 -1
  24. data/lib/command_kit/options/option_value.rb +2 -2
  25. data/lib/command_kit/options/parser.rb +2 -2
  26. data/lib/command_kit/options/quiet.rb +1 -1
  27. data/lib/command_kit/options/verbose.rb +2 -2
  28. data/lib/command_kit/options/version.rb +10 -0
  29. data/lib/command_kit/options.rb +1 -1
  30. data/lib/command_kit/os/linux.rb +1 -1
  31. data/lib/command_kit/os.rb +2 -2
  32. data/lib/command_kit/printing/fields.rb +56 -0
  33. data/lib/command_kit/printing/indent.rb +1 -1
  34. data/lib/command_kit/printing/lists.rb +91 -0
  35. data/lib/command_kit/printing/tables/border_style.rb +169 -0
  36. data/lib/command_kit/printing/tables/cell_builder.rb +93 -0
  37. data/lib/command_kit/printing/tables/row_builder.rb +111 -0
  38. data/lib/command_kit/printing/tables/style.rb +198 -0
  39. data/lib/command_kit/printing/tables/table_builder.rb +145 -0
  40. data/lib/command_kit/printing/tables/table_formatter.rb +254 -0
  41. data/lib/command_kit/printing/tables.rb +208 -0
  42. data/lib/command_kit/stdio.rb +5 -1
  43. data/lib/command_kit/version.rb +1 -1
  44. data/lib/command_kit/xdg.rb +1 -1
  45. data/spec/bug_report_spec.rb +266 -0
  46. data/spec/colors_spec.rb +6 -0
  47. data/spec/command_name_spec.rb +1 -1
  48. data/spec/commands_spec.rb +26 -0
  49. data/spec/edit_spec.rb +72 -0
  50. data/spec/options/option_spec.rb +12 -2
  51. data/spec/options/parser_spec.rb +19 -0
  52. data/spec/options/quiet_spec.rb +51 -0
  53. data/spec/options/verbose_spec.rb +51 -0
  54. data/spec/options/version_spec.rb +146 -0
  55. data/spec/pager_spec.rb +1 -1
  56. data/spec/printing/fields_spec.rb +167 -0
  57. data/spec/printing/lists_spec.rb +99 -0
  58. data/spec/printing/tables/border_style.rb +43 -0
  59. data/spec/printing/tables/cell_builer_spec.rb +135 -0
  60. data/spec/printing/tables/row_builder_spec.rb +165 -0
  61. data/spec/printing/tables/style_spec.rb +377 -0
  62. data/spec/printing/tables/table_builder_spec.rb +252 -0
  63. data/spec/printing/tables/table_formatter_spec.rb +1190 -0
  64. data/spec/printing/tables_spec.rb +1069 -0
  65. metadata +39 -7
@@ -0,0 +1,266 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/bug_report'
3
+
4
+ describe CommandKit::BugReport do
5
+ module TestBugReport
6
+ class CommandWithoutBugReportURLSet
7
+ include CommandKit::BugReport
8
+ end
9
+
10
+ class CommandWithBugReportURLSet
11
+ include CommandKit::BugReport
12
+
13
+ bug_report_url 'https://github.com/org/repo/issues/new'
14
+ end
15
+
16
+ class CommandWithInheritedBugReportURL < CommandWithBugReportURLSet
17
+ end
18
+ end
19
+
20
+ let(:command_class) { TestBugReport::CommandWithBugReportURLSet }
21
+
22
+ describe ".included" do
23
+ it { expect(command_class).to include(CommandKit::ExceptionHandler) }
24
+ it { expect(command_class).to include(CommandKit::Printing) }
25
+ end
26
+
27
+ describe ".bug_report_url" do
28
+ subject { TestBugReport::CommandWithoutBugReportURLSet }
29
+
30
+ context "when no bug_report_url has been set" do
31
+ it "should default to nil" do
32
+ expect(subject.bug_report_url).to be_nil
33
+ end
34
+ end
35
+
36
+ context "when a bug_report_url is explicitly set" do
37
+ subject { TestBugReport::CommandWithBugReportURLSet }
38
+
39
+ it "must return the explicitly set bug_report_url" do
40
+ expect(subject.bug_report_url).to eq("https://github.com/org/repo/issues/new")
41
+ end
42
+ end
43
+
44
+ context "when the command class inherites from another class" do
45
+ context "but no bug_report_url is set" do
46
+ module TestBugReport
47
+ class BaseCmd
48
+ include CommandKit::BugReport
49
+ end
50
+
51
+ class InheritedCmd < BaseCmd
52
+ end
53
+ end
54
+
55
+ subject { TestBugReport::InheritedCmd }
56
+
57
+ it "must search each class then return nil "do
58
+ expect(subject.bug_report_url).to be_nil
59
+ end
60
+ end
61
+
62
+ module TestBugReport
63
+ class ExplicitBaseCmd
64
+ include CommandKit::BugReport
65
+ bug_report_url 'https://github.com/org/repo/issues/new'
66
+ end
67
+ end
68
+
69
+ context "when the superclass defines an explicit bug_report_url" do
70
+ module TestBugReport
71
+ class ImplicitInheritedCmd < ExplicitBaseCmd
72
+ end
73
+ end
74
+
75
+ let(:super_subject) { TestBugReport::ExplicitBaseCmd }
76
+ subject { TestBugReport::ImplicitInheritedCmd }
77
+
78
+ it "must inherit the superclass'es bug_report_url" do
79
+ expect(subject.bug_report_url).to eq(super_subject.bug_report_url)
80
+ end
81
+
82
+ it "must not change the superclass'es bug_report_url" do
83
+ expect(super_subject.bug_report_url).to eq('https://github.com/org/repo/issues/new')
84
+ end
85
+ end
86
+
87
+ context "when the subclass defines an explicit bug_report_url" do
88
+ module TestBugReport
89
+ class ImplicitBaseCmd
90
+ include CommandKit::BugReport
91
+ end
92
+
93
+ class ExplicitInheritedCmd < ImplicitBaseCmd
94
+ bug_report_url 'https://github.com/other_org/other_repo/issues/new'
95
+ end
96
+ end
97
+
98
+ let(:super_subject) { TestBugReport::ImplicitBaseCmd }
99
+ subject { TestBugReport::ExplicitInheritedCmd }
100
+
101
+ it "must return the subclass'es bug_report_url" do
102
+ expect(subject.bug_report_url).to eq('https://github.com/other_org/other_repo/issues/new')
103
+ end
104
+
105
+ it "must not change the superclass'es bug_report_url" do
106
+ expect(super_subject.bug_report_url).to be_nil
107
+ end
108
+ end
109
+
110
+ context "when both the subclass overrides the superclass's bug_report_urls" do
111
+ module TestBugReport
112
+ class ExplicitOverridingInheritedCmd < ExplicitBaseCmd
113
+ bug_report_url 'https://github.com/other_org/other_repo/issues/new'
114
+ end
115
+ end
116
+
117
+ let(:super_subject) { TestBugReport::ExplicitBaseCmd }
118
+ subject { TestBugReport::ExplicitOverridingInheritedCmd }
119
+
120
+ it "must return the subclass'es bug_report_url" do
121
+ expect(subject.bug_report_url).to eq("https://github.com/other_org/other_repo/issues/new")
122
+ end
123
+
124
+ it "must not change the superclass'es bug_report_url" do
125
+ expect(super_subject.bug_report_url).to eq("https://github.com/org/repo/issues/new")
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ subject { command_class.new }
132
+
133
+ describe "#bug_report_url" do
134
+ context "when the command has bug_report_url set" do
135
+ let(:command_class) { TestBugReport::CommandWithBugReportURLSet }
136
+
137
+ it "must return the bug_report_url" do
138
+ expect(subject.bug_report_url).to eq(command_class.bug_report_url)
139
+ end
140
+ end
141
+
142
+ context "when the command does not have bug_report_url set" do
143
+ let(:command_class) { TestBugReport::CommandWithoutBugReportURLSet }
144
+
145
+ it "must return nil" do
146
+ expect(subject.bug_report_url).to be(nil)
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "#print_bug_report" do
152
+ let(:message) { "error!" }
153
+ let(:backtrace) do
154
+ [
155
+ "/path/to/test1.rb:1 in `test1'",
156
+ "/path/to/test2.rb:2 in `test2'",
157
+ "/path/to/test3.rb:3 in `test3'",
158
+ "/path/to/test4.rb:4 in `test4'"
159
+ ]
160
+ end
161
+ let(:exception) do
162
+ error = RuntimeError.new(message)
163
+ error.set_backtrace(backtrace)
164
+ error
165
+ end
166
+
167
+ subject { command_class.new(stderr: StringIO.new) }
168
+
169
+ context "when the command has bug_report_url set" do
170
+ let(:command_class) { TestBugReport::CommandWithBugReportURLSet }
171
+
172
+ context "when stderr is a TTY" do
173
+ before { expect(subject.stderr).to receive(:tty?).and_return(true) }
174
+
175
+ it "must print a message, bug_report_url, and a highlighted exception" do
176
+ subject.print_bug_report(exception)
177
+
178
+ expect(subject.stderr.string).to eq(
179
+ [
180
+ '',
181
+ 'Oops! Looks like you have found a bug. Please report it!',
182
+ command_class.bug_report_url,
183
+ '',
184
+ '```',
185
+ exception.full_message(highlight: true).chomp,
186
+ '```',
187
+ ''
188
+ ].join($/)
189
+ )
190
+ end
191
+ end
192
+
193
+ context "when stderr is not a TTY" do
194
+ it "must print a message, bug_report_url, and print an unhighlighted exception" do
195
+ subject.print_bug_report(exception)
196
+
197
+ expect(subject.stderr.string).to eq(
198
+ [
199
+ '',
200
+ 'Oops! Looks like you have found a bug. Please report it!',
201
+ command_class.bug_report_url,
202
+ '',
203
+ '```',
204
+ exception.full_message(highlight: false).chomp,
205
+ '```',
206
+ ''
207
+ ].join($/)
208
+ )
209
+ end
210
+ end
211
+ end
212
+
213
+ context "when the command does not have bug_report_url set" do
214
+ let(:command_class) { TestBugReport::CommandWithoutBugReportURLSet }
215
+
216
+ context "when stderr is a TTY" do
217
+ before { expect(subject.stderr).to receive(:tty?).and_return(true) }
218
+
219
+ it "must print a message and a highlighted exception" do
220
+ subject.print_bug_report(exception)
221
+
222
+ expect(subject.stderr.string).to eq(
223
+ [
224
+ '',
225
+ 'Oops! Looks like you have found a bug. Please report it!',
226
+ '',
227
+ '```',
228
+ exception.full_message(highlight: true).chomp,
229
+ '```',
230
+ ''
231
+ ].join($/)
232
+ )
233
+ end
234
+ end
235
+
236
+ context "when stderr is not a TTY" do
237
+ it "must print a message and print an unhighlighted exception" do
238
+ subject.print_bug_report(exception)
239
+
240
+ expect(subject.stderr.string).to eq(
241
+ [
242
+ '',
243
+ 'Oops! Looks like you have found a bug. Please report it!',
244
+ '',
245
+ '```',
246
+ exception.full_message(highlight: false).chomp,
247
+ '```',
248
+ ''
249
+ ].join($/)
250
+ )
251
+ end
252
+ end
253
+ end
254
+ end
255
+
256
+ describe "#on_exception" do
257
+ let(:exception) { RuntimeError.new('error!') }
258
+
259
+ it "must call print_bug_report with the exception and then exit(-1)" do
260
+ expect(subject).to receive(:print_bug_report).with(exception)
261
+ expect(subject).to receive(:exit).with(-1)
262
+
263
+ subject.on_exception(exception)
264
+ end
265
+ end
266
+ end
data/spec/colors_spec.rb CHANGED
@@ -656,6 +656,12 @@ describe CommandKit::Colors do
656
656
  it { expect(subject.ansi?).to be(false) }
657
657
  end
658
658
 
659
+ context "when NO_COLOR is set" do
660
+ subject { command_class.new(env: {'NO_COLOR' => 'true'}) }
661
+
662
+ it { expect(subject.ansi?).to be(false) }
663
+ end
664
+
659
665
  context "when stdout is a TTY" do
660
666
  let(:stdout) { StringIO.new }
661
667
  subject { command_class.new(stdout: stdout) }
@@ -19,7 +19,7 @@ describe CommandKit::CommandName do
19
19
  end
20
20
  end
21
21
 
22
- context "when a command_name is explicitly set" do
22
+ context "when a command_name has been explicitly set" do
23
23
  module TestCommandName
24
24
  class ExplicitCmd
25
25
  include CommandKit::CommandName
@@ -155,6 +155,32 @@ describe CommandKit::Commands do
155
155
 
156
156
  let(:command_class) { TestCommands::TestCommands }
157
157
 
158
+ describe ".included" do
159
+ subject { command_class }
160
+
161
+ it "must set .usage to '[options] [COMMAND [ARGS...]]'" do
162
+ expect(subject.usage).to eq('[options] [COMMAND [ARGS...]]')
163
+ end
164
+
165
+ it "must add a 'command' argument" do
166
+ expect(subject.arguments[:command]).to_not be_nil
167
+ expect(subject.arguments[:command].required?).to be(false)
168
+ expect(subject.arguments[:command].desc).to eq('The command name to run')
169
+ end
170
+
171
+ it "must add a 'args' argument" do
172
+ expect(subject.arguments[:args]).to_not be_nil
173
+ expect(subject.arguments[:args].required?).to be(false)
174
+ expect(subject.arguments[:args].repeats?).to be(true)
175
+ expect(subject.arguments[:args].desc).to eq('Additional arguments for the command')
176
+ end
177
+
178
+ it "must add a 'help' command" do
179
+ expect(subject.commands['help']).to_not be(nil)
180
+ expect(subject.commands['help'].command).to be(described_class::Help)
181
+ end
182
+ end
183
+
158
184
  describe ".commands" do
159
185
  subject { command_class }
160
186
 
data/spec/edit_spec.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/edit'
3
+
4
+ describe CommandKit::Edit do
5
+ module TestEdit
6
+ class TestCommand
7
+ include CommandKit::Edit
8
+ end
9
+ end
10
+
11
+ let(:command_class) { TestEdit::TestCommand }
12
+
13
+ it "must also include CommandKit::Env" do
14
+ expect(command_class).to include(CommandKit::Env)
15
+ end
16
+
17
+ describe "#editor" do
18
+ subject { command_class.new(env: env) }
19
+
20
+ context "when env['EDITOR'] is set" do
21
+ let(:editor) { 'vim' }
22
+ let(:env) do
23
+ {'EDITOR' => editor}
24
+ end
25
+
26
+ it "must return env['EDITOR']" do
27
+ expect(subject.editor).to eq(env['EDITOR'])
28
+ end
29
+ end
30
+
31
+ context "when env['EDITOR'] is not set" do
32
+ let(:env) do
33
+ {}
34
+ end
35
+
36
+ it "must return 'nano'" do
37
+ expect(subject.editor).to eq('nano')
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "#edit" do
43
+ subject { command_class.new(env: env) }
44
+
45
+ let(:arguments) { ['file.txt'] }
46
+
47
+ context "when env['EDITOR'] is set" do
48
+ let(:editor) { 'vim' }
49
+ let(:env) do
50
+ {'EDITOR' => editor}
51
+ end
52
+
53
+ it "must invoke system with #editor and the additional arguments" do
54
+ expect(subject).to receive(:system).with(subject.editor,*arguments)
55
+
56
+ subject.edit(*arguments)
57
+ end
58
+ end
59
+
60
+ context "when env['EDITOR'] is not set" do
61
+ let(:env) do
62
+ {}
63
+ end
64
+
65
+ it "must invoke system with 'nano' and the additional arguments" do
66
+ expect(subject).to receive(:system).with('nano',*arguments)
67
+
68
+ subject.edit(*arguments)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -6,10 +6,12 @@ describe CommandKit::Options::Option do
6
6
  let(:short) { nil }
7
7
  let(:long) { '--foo' }
8
8
  let(:equals) { false }
9
+ let(:value_usage) { 'FOO' }
10
+ let(:value_required) { true }
9
11
  let(:value) do
10
12
  {
11
- usage: 'FOO',
12
- required: true
13
+ usage: value_usage,
14
+ required: value_required
13
15
  }
14
16
  end
15
17
  let(:desc) { 'Foo option' }
@@ -228,6 +230,14 @@ describe CommandKit::Options::Option do
228
230
  it "must return '--option=USAGE'" do
229
231
  expect(subject.usage.last).to eq("#{long}=#{subject.value.usage}")
230
232
  end
233
+
234
+ context "but the #value is also optional?" do
235
+ let(:value_required) { false }
236
+
237
+ it "must return '--option[=USAGE]'" do
238
+ expect(subject.usage.last).to eq("#{long}[=#{subject.value.usage}]")
239
+ end
240
+ end
231
241
  end
232
242
  end
233
243
 
@@ -19,6 +19,25 @@ describe CommandKit::Options::Parser do
19
19
  it { expect(subject).to include(CommandKit::Main) }
20
20
  it { expect(subject).to include(CommandKit::Usage) }
21
21
  it { expect(subject.usage).to eq('[options]') }
22
+
23
+ context "when the command class already defines a usage string" do
24
+ module TestOptionParser
25
+ class TestCommandWithUsage
26
+ include CommandKit::Usage
27
+
28
+ usage '[options] ARGS...'
29
+
30
+ include CommandKit::Options::Parser
31
+ end
32
+ end
33
+
34
+ let(:command_class) { TestOptionParser::TestCommandWithUsage }
35
+ subject { command_class }
36
+
37
+ it "must not override the usage" do
38
+ expect(subject.usage).to eq('[options] ARGS...')
39
+ end
40
+ end
22
41
  end
23
42
 
24
43
  subject { command_class.new }
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/options/quiet'
3
+
4
+ describe CommandKit::Options::Quiet do
5
+ module TestOptionsQuiet
6
+ class TestCommand
7
+ include CommandKit::Options::Quiet
8
+ end
9
+ end
10
+
11
+ let(:command_class) { TestOptionsQuiet::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 quiet option" do
21
+ expect(subject.options[:quiet]).to_not be(nil)
22
+ expect(subject.options[:quiet].short).to eq('-q')
23
+ expect(subject.options[:quiet].long).to eq('--quiet')
24
+ expect(subject.options[:quiet].desc).to eq('Enables quiet output')
25
+ end
26
+ end
27
+
28
+ subject { command_class.new }
29
+
30
+ describe "#quiet?" do
31
+ context "when @quiet is true" do
32
+ before do
33
+ subject.instance_variable_set('@quiet',true)
34
+ end
35
+
36
+ it "must return true" do
37
+ expect(subject.quiet?).to be(true)
38
+ end
39
+ end
40
+
41
+ context "when @quiet is false" do
42
+ before do
43
+ subject.instance_variable_set('@quiet',false)
44
+ end
45
+
46
+ it "must return false" do
47
+ expect(subject.quiet?).to be(false)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -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