cp 0.0.1.pre1 → 0.0.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.
- data/README.md +55 -0
- data/cp.gemspec +1 -2
- data/examples/net.rb +12 -9
- data/lib/cp.rb +23 -9
- data/lib/cp/app.rb +18 -4
- data/lib/cp/command.rb +38 -7
- data/lib/cp/errors.rb +4 -0
- data/lib/cp/has/commands.rb +34 -0
- data/lib/cp/has/options.rb +17 -0
- data/lib/cp/option.rb +22 -2
- data/lib/cp/options_struct.rb +7 -0
- data/lib/cp/runners/cmd_parse.rb +32 -11
- data/lib/cp/version.rb +1 -1
- data/spec/app_spec.rb +29 -16
- data/spec/command_spec.rb +10 -4
- data/spec/cp_spec.rb +1 -1
- data/spec/has/commands_spec.rb +10 -0
- data/spec/has/options_spec.rb +10 -0
- data/spec/option_spec.rb +43 -15
- data/spec/options_struct_spec.rb +7 -0
- data/spec/runners/cmd_parse_spec.rb +6 -38
- data/spec/support/lib/test_app_runner.rb +16 -0
- data/spec/support/shared_examples/commands_examples.rb +52 -0
- data/spec/support/shared_examples/options_examples.rb +23 -0
- data/spec/support/shared_examples/runner_examples.rb +173 -0
- data/spec/support/spec_helper.rb +38 -12
- metadata +25 -23
- data/lib/cp/commands.rb +0 -15
- data/lib/cp/options.rb +0 -15
- data/spec/options_spec.rb +0 -10
- data/spec/support/shared_helper.rb +0 -47
data/lib/cp/version.rb
CHANGED
data/spec/app_spec.rb
CHANGED
@@ -8,43 +8,56 @@ describe CP::App do
|
|
8
8
|
it_should_behave_like "it accepts commands"
|
9
9
|
it_should_behave_like "it accepts options"
|
10
10
|
|
11
|
-
describe "#
|
12
|
-
it "should
|
13
|
-
|
11
|
+
describe "#error" do
|
12
|
+
it "should take one argument" do
|
13
|
+
CP::App.instance.method( :error ).arity.should === 1
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should print the message" do
|
17
|
+
errors, output = trap_output do
|
18
|
+
CP::App.instance.error( "test error" )
|
19
|
+
end
|
20
|
+
|
21
|
+
errors.should match( /test error/ )
|
14
22
|
end
|
15
23
|
end
|
16
24
|
|
17
|
-
describe "#
|
18
|
-
it "should
|
19
|
-
@target.
|
25
|
+
describe "#instance" do
|
26
|
+
it "should always return the same object" do
|
27
|
+
@target.should == CP::App.instance
|
20
28
|
end
|
21
29
|
end
|
22
30
|
|
23
31
|
describe "#run" do
|
24
32
|
it "should exist" do
|
25
|
-
|
33
|
+
CP::App.methods.include?( :run ).should be_true
|
26
34
|
end
|
27
35
|
|
28
|
-
it "should
|
29
|
-
|
36
|
+
it "should take an number of arguments" do
|
37
|
+
CP::App.method( :run ).arity.should === -1
|
30
38
|
end
|
31
39
|
end
|
32
40
|
|
33
41
|
describe "properties" do
|
34
|
-
[:name, :version].each do |
|
35
|
-
it "should accept a #{
|
36
|
-
|
37
|
-
|
42
|
+
[:name, :version].each do |prop|
|
43
|
+
it "should accept a #{prop} property" do
|
44
|
+
value = "0.1.1"
|
38
45
|
lambda {
|
39
|
-
@target.app
|
40
|
-
}.should change( @target,
|
46
|
+
@target.app prop, value
|
47
|
+
}.should change( @target, prop ).from( @target.send( prop ) ).to( value )
|
41
48
|
end
|
42
49
|
end
|
43
50
|
|
44
51
|
it "should raise a ArgumentError when setting other properties" do
|
45
52
|
lambda {
|
46
|
-
|
53
|
+
@target.app :foo, "bar"
|
47
54
|
}.should raise_error( ArgumentError, /no such property/ )
|
48
55
|
end
|
56
|
+
|
57
|
+
describe "#name" do
|
58
|
+
it "should default to the name of the script" do
|
59
|
+
@target.name.should === File.basename( $0 )
|
60
|
+
end
|
61
|
+
end
|
49
62
|
end
|
50
63
|
end
|
data/spec/command_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require File.join( File.dirname( __FILE__ ), "support", "spec_helper" )
|
|
2
2
|
|
3
3
|
describe CP::Command do
|
4
4
|
before( :each ) do
|
5
|
-
@target =
|
5
|
+
@target = CP::Command.new( :test )
|
6
6
|
end
|
7
7
|
|
8
8
|
it_should_behave_like "it accepts commands"
|
@@ -12,7 +12,6 @@ describe CP::Command do
|
|
12
12
|
[
|
13
13
|
[:description, "description"],
|
14
14
|
[:summary, "summary"],
|
15
|
-
[:execute, lambda {}],
|
16
15
|
].each { |(attr, val)|
|
17
16
|
it "defines a ##{attr} accessor" do
|
18
17
|
lambda {
|
@@ -23,8 +22,8 @@ describe CP::Command do
|
|
23
22
|
end
|
24
23
|
|
25
24
|
describe "#new" do
|
26
|
-
it "takes
|
27
|
-
|
25
|
+
it "takes 1 or 2 parameters" do
|
26
|
+
@target.method( :initialize ).arity.should === -2
|
28
27
|
end
|
29
28
|
|
30
29
|
it "takes a symbol" do
|
@@ -37,6 +36,13 @@ describe CP::Command do
|
|
37
36
|
CP::Command.new( :test ).name.should === :test
|
38
37
|
end
|
39
38
|
|
39
|
+
it "saves the block as #block" do
|
40
|
+
block_ran = false
|
41
|
+
@target.execute { block_ran = true }
|
42
|
+
@target.block.call( nil )
|
43
|
+
block_ran.should be_true
|
44
|
+
end
|
45
|
+
|
40
46
|
it "yields itself" do
|
41
47
|
yielded = nil
|
42
48
|
c = CP::Command.new( :test ) do |cmd|
|
data/spec/cp_spec.rb
CHANGED
@@ -4,7 +4,7 @@ describe CP do
|
|
4
4
|
describe "methods" do
|
5
5
|
def assert_method_added( method )
|
6
6
|
Object.new.methods.include?( method ).should be_false
|
7
|
-
|
7
|
+
TestApp.new.methods.include?( method ).should be_true
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should define a app method" do
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.join( File.dirname( __FILE__ ), "..", "support", "spec_helper" )
|
2
|
+
|
3
|
+
describe CP::Has::Commands do
|
4
|
+
before( :each ) do
|
5
|
+
class Target; include CP::Has::Commands; end
|
6
|
+
@target = Target.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it_should_behave_like "it accepts commands"
|
10
|
+
end
|
data/spec/option_spec.rb
CHANGED
@@ -9,10 +9,8 @@ describe CP::Option do
|
|
9
9
|
describe "attributes" do
|
10
10
|
[
|
11
11
|
[:allowed, ["foo", "bar"]],
|
12
|
-
[:block, lambda{}],
|
13
12
|
[:description, "description"],
|
14
13
|
[:long, "--short"],
|
15
|
-
[:required, true],
|
16
14
|
[:short, "-s"],
|
17
15
|
[:type, String]
|
18
16
|
].each { |(attr, val)|
|
@@ -39,6 +37,29 @@ describe CP::Option do
|
|
39
37
|
end
|
40
38
|
end
|
41
39
|
|
40
|
+
describe "#block" do
|
41
|
+
it "should save the value" do
|
42
|
+
block = lambda {}
|
43
|
+
@target.block.call( "foo" )
|
44
|
+
@target.value.should === "foo"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should call the use's block" do
|
48
|
+
called = false
|
49
|
+
@target.block = lambda { |val| called = true }
|
50
|
+
@target.block.call( "value" )
|
51
|
+
called.should be_true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#default" do
|
56
|
+
it "should be returned as the value when no value is set" do
|
57
|
+
@target.short = "-s VAL"
|
58
|
+
@target.default = "foo"
|
59
|
+
@target.value.should === "foo"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
42
63
|
describe "#name" do
|
43
64
|
it "returns a symbol" do
|
44
65
|
@target.name.is_a?( Symbol )
|
@@ -107,7 +128,7 @@ describe CP::Option do
|
|
107
128
|
end
|
108
129
|
it "sets the block from arguments" do
|
109
130
|
ran = false
|
110
|
-
CP::Option.new( "-s", lambda{ ran = true } ).block.call
|
131
|
+
CP::Option.new( "-s", lambda{ ran = true } ).block.call( nil )
|
111
132
|
ran.should be_true
|
112
133
|
end
|
113
134
|
|
@@ -136,23 +157,30 @@ describe CP::Option do
|
|
136
157
|
end
|
137
158
|
end
|
138
159
|
|
139
|
-
describe "#long
|
160
|
+
describe "#long" do
|
140
161
|
it "parses the option, separating the option argument" do
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
o.arg.should == " VALUE"
|
145
|
-
o.long.should == "--switch"
|
162
|
+
@target.long = "--switch VALUE"
|
163
|
+
@target.arg.should == " VALUE"
|
164
|
+
@target.long.should == "--switch"
|
146
165
|
end
|
147
166
|
end
|
148
167
|
|
149
|
-
describe "#
|
168
|
+
describe "#required" do
|
169
|
+
it "defaults to false" do
|
170
|
+
@target.required?.should be_false
|
171
|
+
end
|
172
|
+
|
173
|
+
it "is converted to a boolean" do
|
174
|
+
@target.required = "not a boolean"
|
175
|
+
@target.required?.should be_true
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "#short" do
|
150
180
|
it "parses the option, separating the option argument" do
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
o.arg.should == " VALUE"
|
155
|
-
o.short.should == "-s"
|
181
|
+
@target.short = "-s VALUE"
|
182
|
+
@target.arg.should == " VALUE"
|
183
|
+
@target.short.should == "-s"
|
156
184
|
end
|
157
185
|
end
|
158
186
|
|
@@ -1,47 +1,15 @@
|
|
1
|
-
require File.join( File.dirname( __FILE__ ), "support", "spec_helper" )
|
1
|
+
require File.join( File.dirname( __FILE__ ), "..", "support", "spec_helper" )
|
2
2
|
|
3
3
|
describe CP::Runners::CmdParse do
|
4
4
|
before( :each ) do
|
5
|
-
@target =
|
5
|
+
@target = CP::Runners::CmdParse.new( create_test_app )
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
it "should always return the same object" do
|
10
|
-
@target.should == CP::App.instance
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "#parser" do
|
15
|
-
it "should default to CmdParser" do
|
16
|
-
@target.parser.should == CP::Parsers::CmdParse
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "#run" do
|
21
|
-
it "should exist" do
|
22
|
-
@target.methods.include?( :run ).should be_true
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should not take any parameters" do
|
26
|
-
@target.method( :run ).arity.should === 0
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe "properties" do
|
31
|
-
[:name, :version].each do |prop_name|
|
32
|
-
it "should accept a #{prop_name} property" do
|
33
|
-
prop_val = "0.1.1"
|
34
|
-
|
35
|
-
lambda {
|
36
|
-
@target.app prop_name, prop_val
|
37
|
-
}.should change( @target, prop_name ).from( nil ).to( prop_val )
|
38
|
-
end
|
39
|
-
end
|
8
|
+
it_should_behave_like "it is a runner"
|
40
9
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
}.should raise_error( ArgumentError, /no such property/ )
|
10
|
+
describe "#runner" do
|
11
|
+
it "return a CmdParse::CommandParser" do
|
12
|
+
@target.runner.should be_a( CmdParse::CommandParser )
|
45
13
|
end
|
46
14
|
end
|
47
15
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class TestAppRunner
|
2
|
+
attr_reader :errors, :exit_status, :output
|
3
|
+
|
4
|
+
def run( *args )
|
5
|
+
@errors, @output = trap_output do
|
6
|
+
app = create_test_app
|
7
|
+
yield app if block_given?
|
8
|
+
|
9
|
+
begin
|
10
|
+
app.run *args
|
11
|
+
rescue SystemExit => e
|
12
|
+
@exit_status = e.status
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
shared_examples_for "it accepts commands" do
|
2
|
+
describe "#command" do
|
3
|
+
it "should return a Command" do
|
4
|
+
@target.command( :test ).should be_an_instance_of( CP::Command )
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should return the existing Command" do
|
8
|
+
@target.command( :test ).should === @target.command( :test )
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "automatic subcommand creation" do
|
12
|
+
it "should define the parent command" do
|
13
|
+
@target.command( "test foo" )
|
14
|
+
@target.command( :test ).commands.size.should === 1
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should define subcommands when the name includes spaces" do
|
18
|
+
@target.command( :test )
|
19
|
+
lambda {
|
20
|
+
@target.command( "test foo" )
|
21
|
+
}.should_not change(){ @target.commands.size }.by( 1 )
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return the subcommand" do
|
25
|
+
@target.command( "test foo" ).name.should === :foo
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#commands" do
|
31
|
+
it "should return an array" do
|
32
|
+
@target.commands.should be_an_instance_of( Array )
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should increase with each defined command" do
|
36
|
+
lambda {
|
37
|
+
@target.command( :test )
|
38
|
+
}.should change(){ @target.commands.size }.by( 1 )
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should include each defined command" do
|
42
|
+
@target.commands.include?( @target.command( :test ) ).should be_true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should only allow one default command" do
|
46
|
+
lambda {
|
47
|
+
@target.command( :test ) { |c| c.default = true }
|
48
|
+
@target.command( :test2 ) { |c| c.default = true }
|
49
|
+
}.should raise_error( CP::CommandError, /only one/ )
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
shared_examples_for "it accepts options" do
|
2
|
+
describe "#option" do
|
3
|
+
it "should return an Option" do
|
4
|
+
@target.option( "-s" ).should be_an_instance_of( CP::Option )
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#options" do
|
9
|
+
it "should return an array" do
|
10
|
+
@target.options.should be_an_instance_of( Array )
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should increase with each defined option" do
|
14
|
+
lambda {
|
15
|
+
@target.option( "-s" )
|
16
|
+
}.should change(){ @target.options.length}.by( 1 )
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should include each defined option" do
|
20
|
+
@target.options.include?( @target.option( "-s" ) ).should be_true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
shared_examples_for "it is a runner" do
|
2
|
+
describe "#new" do
|
3
|
+
it "should take one parameter" do
|
4
|
+
@target.method( :initialize ).arity.should === 1
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "arguments" do
|
9
|
+
it "should be passed to the command block" do
|
10
|
+
passed_args = nil
|
11
|
+
|
12
|
+
run( "test", "foo", "bar" ) do |app|
|
13
|
+
app.command( :test ) { |c|
|
14
|
+
c.execute { |args, opts| passed_args = args }
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
passed_args.should == ["foo", "bar"]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "commands" do
|
23
|
+
describe "invalid commands" do
|
24
|
+
it "should explain that it's not valid" do
|
25
|
+
run( "invalid" ).errors.should match( /'invalid' is not a (\w+ )+command/i )
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should exit with a nonzero status" do
|
29
|
+
run( "invalid" ).exit_status.should_not === 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "the help command" do
|
34
|
+
it "should exist" do
|
35
|
+
run( "help" ).exit_status.should === 0
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not overwrite a custom help command" do
|
39
|
+
custom_help_ran = false
|
40
|
+
|
41
|
+
run( "help" ) do |app|
|
42
|
+
app.command( :help ) do |c|
|
43
|
+
c.execute { custom_help_ran = true }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
custom_help_ran .should be_true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "options" do
|
53
|
+
describe "boolean options" do
|
54
|
+
describe "defaults" do
|
55
|
+
it "should allow a `true` default" do
|
56
|
+
passed_value = nil
|
57
|
+
|
58
|
+
run( "test" ) do |app|
|
59
|
+
app.command( :test ) { |c|
|
60
|
+
c.option( "--[no-]option" ) { |o| o.default = true }
|
61
|
+
c.execute { |args, opts| passed_value = opts.option }
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
passed_value.should be_true
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should allow overriding of the `true` default" do
|
69
|
+
passed_value = nil
|
70
|
+
|
71
|
+
run( "test", "--no-option" ) do |app|
|
72
|
+
app.command( :test ) { |c|
|
73
|
+
c.option( "--[no-]option" ) { |o| o.default = true }
|
74
|
+
c.execute { |args, opts| passed_value = opts.option }
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
passed_value.should be_false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "default values" do
|
84
|
+
it "should pass them to the command block" do
|
85
|
+
passed_value = nil
|
86
|
+
|
87
|
+
run( "test" ) do |app|
|
88
|
+
app.command( :test ) { |c|
|
89
|
+
c.option( "--option VAL" ) { |o| o.default = "foo" }
|
90
|
+
c.execute { |args, opts| passed_value = opts.option }
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
passed_value.should === "foo"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "invalid options" do
|
99
|
+
it "should explain that it's not valid" do
|
100
|
+
run( "--invalid" ).errors.should match( /'--invalid' is not a valid option/i )
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should exit with a nonzero status" do
|
104
|
+
run( "--invalid" ).exit_status.should_not === 0
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "required options" do
|
109
|
+
describe "missing" do
|
110
|
+
before( :each ) do
|
111
|
+
@result = run( "test" ) do |app|
|
112
|
+
app.command( :test ) { |c|
|
113
|
+
c.option( "--option" ) { |o| o.required = true }
|
114
|
+
c.execute { |args, opts| }
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should explain that the option is required" do
|
120
|
+
@result.errors.should match( /'--option' is required/i )
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should exit with a nonzero status" do
|
124
|
+
@result.exit_status.should_not === 0
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "the options struct" do
|
130
|
+
it "should be passed to the command block" do
|
131
|
+
opts_struct = nil
|
132
|
+
|
133
|
+
run( "test", "foo", "bar" ) do |app|
|
134
|
+
app.command( :test ) { |c|
|
135
|
+
c.execute { |args, opts| opts_struct = opts }
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
opts_struct.should be_a( Struct::Options )
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should provide access to passed option values" do
|
143
|
+
passed_value = nil
|
144
|
+
|
145
|
+
run( "test", "--option", "foo" ) do |app|
|
146
|
+
app.command( :test ) { |c|
|
147
|
+
c.option( "--option FOO" )
|
148
|
+
c.execute { |args, opts| passed_value = opts.option }
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
passed_value.should === "foo"
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should include parent options" do
|
156
|
+
passed_value = nil
|
157
|
+
|
158
|
+
run( "cmd", "sub1", "--option", "foo", "sub2" ) do |app|
|
159
|
+
app.command( :cmd ) { |cmd|
|
160
|
+
cmd.command( :sub1 ) { |sub1|
|
161
|
+
sub1.option( "--option FOO" )
|
162
|
+
sub1.command( :sub2 ) { |sub2|
|
163
|
+
sub2.execute { |args, opts| passed_value = opts.option }
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
passed_value.should === "foo"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|