command_kit 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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