command_kit 0.1.0 → 0.3.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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +18 -3
  3. data/.rubocop.yml +141 -0
  4. data/ChangeLog.md +165 -0
  5. data/Gemfile +3 -0
  6. data/README.md +186 -118
  7. data/Rakefile +3 -2
  8. data/command_kit.gemspec +4 -4
  9. data/examples/command.rb +1 -1
  10. data/gemspec.yml +7 -0
  11. data/lib/command_kit/arguments/argument.rb +2 -2
  12. data/lib/command_kit/arguments.rb +36 -7
  13. data/lib/command_kit/colors.rb +702 -53
  14. data/lib/command_kit/command.rb +2 -3
  15. data/lib/command_kit/commands/auto_load.rb +8 -1
  16. data/lib/command_kit/commands/help.rb +3 -2
  17. data/lib/command_kit/commands/subcommand.rb +1 -1
  18. data/lib/command_kit/commands.rb +24 -9
  19. data/lib/command_kit/env/path.rb +1 -1
  20. data/lib/command_kit/file_utils.rb +46 -0
  21. data/lib/command_kit/help/man.rb +17 -33
  22. data/lib/command_kit/inflector.rb +47 -17
  23. data/lib/command_kit/interactive.rb +9 -0
  24. data/lib/command_kit/main.rb +7 -9
  25. data/lib/command_kit/man.rb +44 -0
  26. data/lib/command_kit/open_app.rb +69 -0
  27. data/lib/command_kit/options/option.rb +41 -27
  28. data/lib/command_kit/options/option_value.rb +3 -2
  29. data/lib/command_kit/options/parser.rb +17 -22
  30. data/lib/command_kit/options.rb +102 -14
  31. data/lib/command_kit/os/linux.rb +157 -0
  32. data/lib/command_kit/os.rb +159 -11
  33. data/lib/command_kit/package_manager.rb +200 -0
  34. data/lib/command_kit/pager.rb +46 -4
  35. data/lib/command_kit/printing/indent.rb +4 -4
  36. data/lib/command_kit/printing.rb +14 -3
  37. data/lib/command_kit/program_name.rb +9 -0
  38. data/lib/command_kit/sudo.rb +40 -0
  39. data/lib/command_kit/terminal.rb +5 -0
  40. data/lib/command_kit/version.rb +1 -1
  41. data/spec/arguments/argument_spec.rb +1 -1
  42. data/spec/arguments_spec.rb +84 -1
  43. data/spec/colors_spec.rb +357 -70
  44. data/spec/command_spec.rb +77 -6
  45. data/spec/commands/auto_load_spec.rb +33 -2
  46. data/spec/commands_spec.rb +101 -29
  47. data/spec/env/path_spec.rb +6 -0
  48. data/spec/exception_handler_spec.rb +1 -1
  49. data/spec/file_utils_spec.rb +59 -0
  50. data/spec/fixtures/template.erb +5 -0
  51. data/spec/help/man_spec.rb +54 -57
  52. data/spec/inflector_spec.rb +70 -8
  53. data/spec/man_spec.rb +46 -0
  54. data/spec/open_app_spec.rb +85 -0
  55. data/spec/options/option_spec.rb +38 -2
  56. data/spec/options/option_value_spec.rb +55 -0
  57. data/spec/options/parser_spec.rb +0 -10
  58. data/spec/options_spec.rb +328 -0
  59. data/spec/os/linux_spec.rb +164 -0
  60. data/spec/os_spec.rb +200 -13
  61. data/spec/package_manager_spec.rb +806 -0
  62. data/spec/pager_spec.rb +71 -6
  63. data/spec/printing/indent_spec.rb +7 -5
  64. data/spec/printing_spec.rb +23 -1
  65. data/spec/program_name_spec.rb +8 -0
  66. data/spec/sudo_spec.rb +51 -0
  67. data/spec/terminal_spec.rb +30 -0
  68. data/spec/usage_spec.rb +1 -1
  69. metadata +23 -4
@@ -54,16 +54,27 @@ describe CommandKit::Commands::AutoLoad do
54
54
  end
55
55
 
56
56
  module TestAutoLoad
57
- class CLI
57
+ class TestCommand
58
58
  include CommandKit::Commands
59
59
  include CommandKit::Commands::AutoLoad.new(
60
60
  dir: File.expand_path('../fixtures/test_auto_load/cli/commands',__FILE__),
61
61
  namespace: "#{self}::Commands"
62
62
  )
63
63
  end
64
+
65
+ class TestCommandWithBlock
66
+ include CommandKit::Commands
67
+ include(CommandKit::Commands::AutoLoad.new(
68
+ dir: File.expand_path('../fixtures/test_auto_load/cli/commands',__FILE__),
69
+ namespace: "#{self}::Commands"
70
+ ) { |autoload|
71
+ autoload.command 'test-1', 'Test1', 'test1.rb', aliases: %w[test_1]
72
+ autoload.command 'test-2', 'Test2', 'test2.rb', aliases: %w[test_2]
73
+ })
74
+ end
64
75
  end
65
76
 
66
- let(:command_class) { TestAutoLoad::CLI }
77
+ let(:command_class) { TestAutoLoad::TestCommand }
67
78
  let(:autoload_module) { command_class.included_modules.first }
68
79
 
69
80
  describe "#included" do
@@ -76,6 +87,26 @@ describe CommandKit::Commands::AutoLoad do
76
87
  it "must merge the module's #commands into the class'es #commands" do
77
88
  expect(command_class.commands).to include(autoload_module.commands)
78
89
  end
90
+
91
+ context "when CommandKit::Commands::AutoLoad has an explicit mapping" do
92
+ let(:command_class) { TestAutoLoad::TestCommandWithBlock }
93
+
94
+ it "must merge the module's #commands into the class'es #commands" do
95
+ expect(command_class.commands).to include(autoload_module.commands)
96
+ end
97
+
98
+ it "must also merge the any aliases into the class'es #command_aliases" do
99
+ expected_command_aliases = {}
100
+
101
+ autoload_module.commands.each do |name,subcommand|
102
+ subcommand.aliases.each do |alias_name|
103
+ expected_command_aliases[alias_name] = name
104
+ end
105
+ end
106
+
107
+ expect(command_class.command_aliases).to include(expected_command_aliases)
108
+ end
109
+ end
79
110
  end
80
111
 
81
112
  describe "#join" do
@@ -19,7 +19,6 @@ describe CommandKit::Commands do
19
19
  class Test2 < CommandKit::Command
20
20
  end
21
21
 
22
- p method(:command).source_location
23
22
  command Test1
24
23
  command Test2
25
24
 
@@ -126,6 +125,32 @@ describe CommandKit::Commands do
126
125
  command Test2
127
126
 
128
127
  end
128
+
129
+ class TestCommandsWithCommandArguments
130
+
131
+ include CommandKit::Commands
132
+
133
+ class Test1 < CommandKit::Command
134
+ argument :arg1, required: false,
135
+ desc: 'Argument 1'
136
+
137
+ argument :arg2, required: false,
138
+ desc: 'Argument 2'
139
+ end
140
+
141
+ class Test2 < CommandKit::Command
142
+ argument :arg1, required: false,
143
+ desc: 'Argument 1'
144
+
145
+ argument :arg2, required: false,
146
+ desc: 'Argument 2'
147
+ end
148
+
149
+ command Test1
150
+ command Test2
151
+
152
+ end
153
+
129
154
  end
130
155
 
131
156
  let(:command_class) { TestCommands::TestCommands }
@@ -191,7 +216,7 @@ describe CommandKit::Commands do
191
216
  it "must contain the mapping of aliases to command names" do
192
217
  expect(subject.command_aliases).to eq({
193
218
  't1' => 'test1',
194
- 't2' => 'test2',
219
+ 't2' => 'test2'
195
220
  })
196
221
  end
197
222
  end
@@ -569,7 +594,7 @@ describe CommandKit::Commands do
569
594
  expect(subject).to receive(:exit).with(1)
570
595
 
571
596
  expect { subject.command_not_found(unknown_command) }.to output(
572
- "'#{unknown_command}' is not a #{subject.command_name} command. See `#{subject.command_name} help`" + $/
597
+ "#{subject.command_name}: '#{unknown_command}' is not a #{subject.command_name} command. See `#{subject.command_name} help`" + $/
573
598
  ).to_stderr
574
599
  end
575
600
  end
@@ -582,6 +607,44 @@ describe CommandKit::Commands do
582
607
  end
583
608
  end
584
609
 
610
+ describe "#option_parser" do
611
+ let(:command_name) { 'test1' }
612
+ let(:command_argv) { %w[foo bar baz] }
613
+ let(:argv) { [command_name, *command_argv] }
614
+
615
+ it "must stop before the first non-option argument" do
616
+ expect(subject.option_parser.parse(argv)).to eq(
617
+ [command_name, *command_argv]
618
+ )
619
+ end
620
+
621
+ context "when an unknown command name is given" do
622
+ let(:command_argv) { %w[bar baz] }
623
+ let(:argv) { ['foo', command_name, *command_argv] }
624
+
625
+ it "must stop before the first non-option argument" do
626
+ expect(subject.option_parser.parse(argv)).to eq(argv)
627
+ end
628
+ end
629
+
630
+ context "when additional global options are defined" do
631
+ let(:command_class) { TestCommands::TestCommandsWithGlobalOptions }
632
+ let(:bar) { '2' }
633
+ let(:argv) do
634
+ ['--foo', '--bar', bar.to_s, command_name, *command_argv]
635
+ end
636
+
637
+ it "must parse the global options, but stop before the first non-option associated argument" do
638
+ expect(subject.option_parser.parse(argv)).to eq(
639
+ [command_name, *command_argv]
640
+ )
641
+
642
+ expect(subject.options[:foo]).to be(true)
643
+ expect(subject.options[:bar]).to eq(bar)
644
+ end
645
+ end
646
+ end
647
+
585
648
  describe "#run" do
586
649
  context "when a command name is the first argument" do
587
650
  let(:command) { 'test1' }
@@ -607,48 +670,45 @@ describe CommandKit::Commands do
607
670
  end
608
671
 
609
672
  context "when given no arguments" do
610
- it "must default to calling #help" do
673
+ let(:exit_status) { 1 }
674
+
675
+ it "must default to calling #help and exit with 1" do
611
676
  expect(subject).to receive(:help)
677
+ expect(subject).to receive(:exit).with(exit_status)
612
678
 
613
679
  subject.run()
614
680
  end
615
681
  end
616
682
  end
617
683
 
618
- describe "#option_parser" do
619
- let(:command_name) { 'test1' }
620
- let(:command_argv) { %w[foo bar baz] }
621
- let(:argv) { [command_name, *command_argv] }
684
+ describe "#main" do
685
+ let(:command_class) { TestCommands::TestCommandsWithCommandArguments }
622
686
 
623
- it "must stop before the first non-option argument" do
624
- expect(subject.option_parser.parse(argv)).to eq(
625
- [command_name, *command_argv]
626
- )
687
+ context "when a command name is the first argument" do
688
+ let(:command) { 'test1' }
689
+ let(:argv) { [command] }
690
+
691
+ it "must return 0" do
692
+ expect(subject.main(argv)).to eq(0)
693
+ end
627
694
  end
628
695
 
629
- context "when an unknown command name is given" do
630
- let(:command_argv) { %w[bar baz] }
631
- let(:argv) { ['foo', command_name, *command_argv] }
696
+ context "when given additional command arguments" do
697
+ let(:argv) { %w[test1 arg1 arg2] }
632
698
 
633
- it "must stop before the first non-option argument" do
634
- expect(subject.option_parser.parse(argv)).to eq(argv)
699
+ it "must pass them to the command" do
700
+ expect(subject.main(argv)).to eq(0)
635
701
  end
636
702
  end
637
703
 
638
- context "when additional global options are defined" do
639
- let(:command_class) { TestCommands::TestCommandsWithGlobalOptions }
640
- let(:bar) { '2' }
641
- let(:argv) do
642
- ['--foo', '--bar', bar.to_s, command_name, *command_argv]
643
- end
704
+ context "when given no arguments" do
705
+ let(:exit_status) { 1 }
706
+ let(:argv) { %w[] }
644
707
 
645
- it "must parse the global options, but stop before the first non-option associated argument" do
646
- expect(subject.option_parser.parse(argv)).to eq(
647
- [command_name, *command_argv]
648
- )
708
+ it "must call #help and return 1" do
709
+ expect(subject).to receive(:help)
649
710
 
650
- expect(subject.options[:foo]).to be(true)
651
- expect(subject.options[:bar]).to eq(bar)
711
+ expect(subject.main(argv)).to eq(exit_status)
652
712
  end
653
713
  end
654
714
  end
@@ -711,6 +771,10 @@ describe CommandKit::Commands do
711
771
  "Options:",
712
772
  " -h, --help Print help information",
713
773
  "",
774
+ "Arguments:",
775
+ " [COMMAND] The command name to run",
776
+ " [ARGS ...] Additional arguments for the command",
777
+ "",
714
778
  "Commands:",
715
779
  " help",
716
780
  " test1",
@@ -731,6 +795,10 @@ describe CommandKit::Commands do
731
795
  "Options:",
732
796
  " -h, --help Print help information",
733
797
  "",
798
+ "Arguments:",
799
+ " [COMMAND] The command name to run",
800
+ " [ARGS ...] Additional arguments for the command",
801
+ "",
734
802
  "Commands:",
735
803
  " help",
736
804
  " test1, t1",
@@ -754,6 +822,10 @@ describe CommandKit::Commands do
754
822
  " -b, --bar BAR Global --bar option",
755
823
  " -h, --help Print help information",
756
824
  "",
825
+ "Arguments:",
826
+ " [COMMAND] The command name to run",
827
+ " [ARGS ...] Additional arguments for the command",
828
+ "",
757
829
  "Commands:",
758
830
  " help",
759
831
  " test1",
@@ -13,6 +13,12 @@ describe CommandKit::Env::Path do
13
13
  let(:command_class) { TestEnvPath::TestCommand }
14
14
  subject { command_class.new }
15
15
 
16
+ describe ".included" do
17
+ it "must include CommandKit::Env" do
18
+ expect(command_class).to be_include(CommandKit::Env)
19
+ end
20
+ end
21
+
16
22
  describe "#initialize" do
17
23
  it "must split ENV['PATH'] into an Array of directories" do
18
24
  expect(subject.path_dirs).to eq(ENV['PATH'].split(File::PATH_SEPARATOR))
@@ -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,59 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/file_utils'
3
+ require 'tempfile'
4
+
5
+ describe CommandKit::FileUtils do
6
+ module TestFileUtils
7
+ class Command
8
+ include CommandKit::FileUtils
9
+
10
+ attr_reader :var
11
+
12
+ def initialize(var: nil)
13
+ super()
14
+
15
+ @var = var
16
+ end
17
+
18
+ def test_method
19
+ 'some method'
20
+ end
21
+ end
22
+ end
23
+
24
+ let(:var) { 42 }
25
+
26
+ let(:command_class) { TestFileUtils::Command }
27
+ subject { command_class.new(var: var) }
28
+
29
+ let(:fixtures_dir) { File.expand_path(File.join(__dir__,'fixtures')) }
30
+ let(:template_path) { File.join(fixtures_dir,'template.erb') }
31
+
32
+ describe "#erb" do
33
+ let(:expected_result) do
34
+ [
35
+ "Raw text",
36
+ '',
37
+ "variable = #{var}",
38
+ '',
39
+ "method = #{subject.test_method}"
40
+ ].join($/)
41
+ end
42
+
43
+ context "when only given a source file argument" do
44
+ it "must render the erb template and return the result" do
45
+ expect(subject.erb(template_path)).to eq(expected_result)
46
+ end
47
+ end
48
+
49
+ context "when given an additional destination file argument" do
50
+ let(:dest_path) { Tempfile.new.path }
51
+
52
+ before { subject.erb(template_path,dest_path) }
53
+
54
+ it "must render the erb template and write the result to the destination" do
55
+ expect(File.read(dest_path)).to eq(expected_result)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,5 @@
1
+ Raw text
2
+
3
+ variable = <%= @var %>
4
+
5
+ method = <%= test_method -%>
@@ -16,7 +16,13 @@ describe CommandKit::Help::Man do
16
16
  man_page 'foo.1'
17
17
  end
18
18
 
19
- class EmptyCommand
19
+ class TestCommandWithRelativeManDir
20
+ include CommandKit::Help::Man
21
+
22
+ man_dir File.join(__dir__,'..','..','..','man')
23
+ end
24
+
25
+ class TestCommandWithManDirNotSet
20
26
  include CommandKit::Help::Man
21
27
  end
22
28
  end
@@ -41,7 +47,7 @@ describe CommandKit::Help::Man do
41
47
 
42
48
  describe ".man_dir" do
43
49
  context "when no man_dir have been set" do
44
- subject { TestHelpMan::EmptyCommand }
50
+ subject { TestHelpMan::TestCommandWithManDirNotSet }
45
51
 
46
52
  it "should default to nil" do
47
53
  expect(subject.man_dir).to be_nil
@@ -52,7 +58,17 @@ describe CommandKit::Help::Man do
52
58
  subject { TestHelpMan::TestCommand }
53
59
 
54
60
  it "must return the explicitly set man_dir" do
55
- expect(subject.man_dir).to eq(File.expand_path('../fixtures/man',__FILE__))
61
+ expect(subject.man_dir).to eq(File.join(__dir__,'fixtures','man'))
62
+ end
63
+
64
+ context "but it's a relative path" do
65
+ subject { TestHelpMan::TestCommandWithRelativeManDir }
66
+
67
+ it "must expand the given man_dir path" do
68
+ expect(subject.man_dir).to eq(
69
+ File.expand_path(File.join(__dir__,'..','..','..','man'))
70
+ )
71
+ end
56
72
  end
57
73
  end
58
74
 
@@ -96,7 +112,7 @@ describe CommandKit::Help::Man do
96
112
  end
97
113
 
98
114
  it "must not change the superclass'es man_dir" do
99
- expect(super_subject.man_dir).to eq('set/in/baseclass')
115
+ expect(super_subject.man_dir).to eq(File.expand_path('set/in/baseclass'))
100
116
  end
101
117
  end
102
118
 
@@ -115,7 +131,7 @@ describe CommandKit::Help::Man do
115
131
  subject { TestHelpMan::ExplicitInheritedCmd }
116
132
 
117
133
  it "must return the subclass'es man_dir" do
118
- expect(subject.man_dir).to eq('set/in/subclass')
134
+ expect(subject.man_dir).to eq(File.expand_path('set/in/subclass'))
119
135
  end
120
136
 
121
137
  it "must not change the superclass'es man_dir" do
@@ -134,11 +150,11 @@ describe CommandKit::Help::Man do
134
150
  subject { TestHelpMan::ExplicitOverridingInheritedCmd }
135
151
 
136
152
  it "must return the subclass'es man_dir" do
137
- expect(subject.man_dir).to eq('set/in/subclass')
153
+ expect(subject.man_dir).to eq(File.expand_path('set/in/subclass'))
138
154
  end
139
155
 
140
156
  it "must not change the superclass'es man_dir" do
141
- expect(super_subject.man_dir).to eq('set/in/baseclass')
157
+ expect(super_subject.man_dir).to eq(File.expand_path('set/in/baseclass'))
142
158
  end
143
159
  end
144
160
  end
@@ -234,48 +250,7 @@ describe CommandKit::Help::Man do
234
250
 
235
251
  subject { command_class.new }
236
252
 
237
- describe "#man" do
238
- let(:man_page) { 'foo' }
239
-
240
- it "must call system() with the given man page" do
241
- expect(subject).to receive(:system).with('man',man_page)
242
-
243
- subject.man(man_page)
244
- end
245
-
246
- context "when given a non-String man-page argument" do
247
- let(:man_page_arg) { double(:non_string_arg) }
248
-
249
- it "must call #to_s on the man-page argument" do
250
- expect(man_page_arg).to receive(:to_s).and_return(man_page)
251
-
252
- expect(subject).to receive(:system).with('man',man_page)
253
-
254
- subject.man(man_page_arg)
255
- end
256
- end
257
-
258
- context "when given the section: keyword argument" do
259
- let(:section) { 7 }
260
-
261
- it "must call system() with the given section number and man page" do
262
- expect(subject).to receive(:system).with('man',section.to_s,man_page)
263
-
264
- subject.man(man_page, section: section)
265
- end
266
- end
267
- end
268
-
269
253
  describe "#help_man" do
270
- context "when .man_dir is not set" do
271
- let(:command_class) { TestHelpMan::EmptyCommand }
272
- subject { command_class.new }
273
-
274
- it do
275
- expect { subject.help_man }.to raise_error(NotImplementedError)
276
- end
277
- end
278
-
279
254
  let(:man_page_path) do
280
255
  File.join(subject.class.man_dir,subject.class.man_page)
281
256
  end
@@ -296,6 +271,16 @@ describe CommandKit::Help::Man do
296
271
  subject.help_man(man_page)
297
272
  end
298
273
  end
274
+
275
+ context "but the man_dir is not set" do
276
+ let(:command_class) { TestHelpMan::TestCommandWithManDirNotSet }
277
+
278
+ it "must call the super help() mehtod" do
279
+ expect {
280
+ subject.help_man
281
+ }.to raise_error(NotImplementedError,"man_dir was not set in #{command_class}")
282
+ end
283
+ end
299
284
  end
300
285
 
301
286
  describe "#help" do
@@ -318,21 +303,33 @@ describe CommandKit::Help::Man do
318
303
  expect(subject.stdout).to receive(:tty?).and_return(true)
319
304
  end
320
305
 
321
- it "must open the command's man-page" do
322
- expect(subject).to receive(:help_man).and_return(true)
306
+ context "and man_dir is set" do
307
+ it "must open the command's man-page" do
308
+ expect(subject).to receive(:help_man).and_return(true)
323
309
 
324
- subject.help
325
- end
310
+ subject.help
311
+ end
312
+
313
+ context "but when the man command is not installed" do
314
+ before do
315
+ expect(subject).to receive(:help_man).and_return(nil)
316
+ end
317
+
318
+ it "must call the super help() method" do
319
+ subject.help
326
320
 
327
- context "but when the man command is not installed" do
328
- before do
329
- expect(subject).to receive(:help_man).and_return(nil)
321
+ expect(subject.stdout.string).to eq(normal_help_output)
322
+ end
330
323
  end
324
+ end
325
+
326
+ context "but the man_dir is not set" do
327
+ let(:command_class) { TestHelpMan::TestCommandWithManDirNotSet }
331
328
 
332
- it "must call the super help() method" do
329
+ it "must call the super help() mehtod" do
333
330
  subject.help
334
331
 
335
- expect(subject.stdout.string).to eq(normal_help_output)
332
+ expect(stdout.string).to eq(normal_help_output)
336
333
  end
337
334
  end
338
335
  end
@@ -28,6 +28,10 @@ describe CommandKit::Inflector do
28
28
  end
29
29
  end
30
30
 
31
+ ascii = (0..255).map(&:chr)
32
+ alpha = ('a'..'z').to_a + ('A'..'Z').to_a
33
+ numeric = ('0'..'9').to_a
34
+
31
35
  describe ".underscore" do
32
36
  it "must convert CamelCase to camel_case" do
33
37
  expect(subject.underscore('CamelCase')).to eq('camel_case')
@@ -37,18 +41,48 @@ describe CommandKit::Inflector do
37
41
  expect(subject.underscore('camelCase')).to eq('camel_case')
38
42
  end
39
43
 
40
- it "must convert Camel to camel" do
41
- expect(subject.underscore('Camel')).to eq('camel')
44
+ it "must convert Camelcase to camelcase" do
45
+ expect(subject.underscore('Camelcase')).to eq('camelcase')
42
46
  end
43
47
 
44
- it "must convert CAMEL to camel" do
45
- expect(subject.underscore('CAMEL')).to eq('camel')
48
+ it "must convert CAMELCASE to camelcase" do
49
+ expect(subject.underscore('CAMELCASE')).to eq('camelcase')
46
50
  end
47
51
 
48
- context "when given a String containing '/' characters" do
49
- it "must replace dashes with underscores" do
50
- expect(subject.underscore('foo-bar')).to eq('foo_bar')
51
- end
52
+ it "must convert CAMELCase to camel_case" do
53
+ expect(subject.underscore('CAMELCase')).to eq('camel_case')
54
+ end
55
+
56
+ it "must convert CamelCASE to camel_case" do
57
+ expect(subject.underscore('CAMELCase')).to eq('camel_case')
58
+ end
59
+
60
+ it "must convert FooBARBaz to foo_bar_baz" do
61
+ expect(subject.underscore('FooBARBaz')).to eq('foo_bar_baz')
62
+ end
63
+
64
+ it "must convert foo_bar_baz to foo_bar_baz" do
65
+ expect(subject.underscore('foo_bar_baz')).to eq('foo_bar_baz')
66
+ end
67
+
68
+ it "must convert foo___bar___baz to foo___bar___baz" do
69
+ expect(subject.underscore('foo___bar___baz')).to eq('foo___bar___baz')
70
+ end
71
+
72
+ it "must convert foo-bar-baz to foo_bar_baz" do
73
+ expect(subject.underscore('foo-bar-baz')).to eq('foo_bar_baz')
74
+ end
75
+
76
+ it "must convert foo---bar---baz to foo___bar___baz" do
77
+ expect(subject.underscore('foo---bar---baz')).to eq('foo___bar___baz')
78
+ end
79
+
80
+ it "must convert foo_BAR_baz to foo_bar_baz" do
81
+ expect(subject.underscore('foo_BAR_baz')).to eq('foo_bar_baz')
82
+ end
83
+
84
+ it "must convert foo-BAR-baz to foo_bar_baz" do
85
+ expect(subject.underscore('foo-BAR-baz')).to eq('foo_bar_baz')
52
86
  end
53
87
 
54
88
  context "when given a non-String" do
@@ -56,6 +90,20 @@ describe CommandKit::Inflector do
56
90
  expect(subject.underscore(:CamelCase)).to eq('camel_case')
57
91
  end
58
92
  end
93
+
94
+ separators = %w[_ -]
95
+
96
+ (ascii - alpha - numeric - separators).each do |char|
97
+ context "when the given String contains a #{char.inspect} character" do
98
+ let(:string) { "Foo#{char}Bar" }
99
+
100
+ it do
101
+ expect {
102
+ subject.underscore(string)
103
+ }.to raise_error(ArgumentError,"cannot convert string to underscored: #{string.inspect}")
104
+ end
105
+ end
106
+ end
59
107
  end
60
108
 
61
109
  describe ".dasherize" do
@@ -100,5 +148,19 @@ describe CommandKit::Inflector do
100
148
  expect(subject.camelize(:foo_bar)).to eq('FooBar')
101
149
  end
102
150
  end
151
+
152
+ separators = %w[_ - /]
153
+
154
+ (ascii - alpha - numeric - separators).each do |char|
155
+ context "when the given String contains a #{char.inspect} character" do
156
+ let(:string) { "foo#{char}bar" }
157
+
158
+ it do
159
+ expect {
160
+ subject.camelize(string)
161
+ }.to raise_error(ArgumentError,"cannot convert string to CamelCase: #{string.inspect}")
162
+ end
163
+ end
164
+ end
103
165
  end
104
166
  end
data/spec/man_spec.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'command_kit/man'
3
+
4
+ describe CommandKit::Man do
5
+ module TestMan
6
+ class TestCommand
7
+ include CommandKit::Man
8
+ end
9
+ end
10
+
11
+ let(:command_class) { TestMan::TestCommand }
12
+
13
+ subject { command_class.new }
14
+
15
+ describe "#man" do
16
+ let(:man_page) { 'foo' }
17
+
18
+ it "must call system() with the given man page" do
19
+ expect(subject).to receive(:system).with('man',man_page)
20
+
21
+ subject.man(man_page)
22
+ end
23
+
24
+ context "when given a non-String man-page argument" do
25
+ let(:man_page_arg) { double(:non_string_arg) }
26
+
27
+ it "must call #to_s on the man-page argument" do
28
+ expect(man_page_arg).to receive(:to_s).and_return(man_page)
29
+
30
+ expect(subject).to receive(:system).with('man',man_page)
31
+
32
+ subject.man(man_page_arg)
33
+ end
34
+ end
35
+
36
+ context "when given the section: keyword argument" do
37
+ let(:section) { 7 }
38
+
39
+ it "must call system() with the given section number and man page" do
40
+ expect(subject).to receive(:system).with('man',section.to_s,man_page)
41
+
42
+ subject.man(man_page, section: section)
43
+ end
44
+ end
45
+ end
46
+ end