cp 0.0.1 → 0.0.2
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/cp.gemspec +4 -3
- data/examples/net.rb +15 -14
- data/lib/cp.rb +9 -1
- data/lib/cp/app.rb +15 -0
- data/lib/cp/command.rb +40 -24
- data/lib/cp/has/commands.rb +4 -4
- data/lib/cp/has/options.rb +11 -2
- data/lib/cp/highline.rb +41 -0
- data/lib/cp/option.rb +31 -9
- data/lib/cp/runners/cmd_parse.rb +7 -7
- data/lib/cp/version.rb +1 -1
- data/lib/ext/core.rb +25 -0
- data/spec/app_spec.rb +66 -0
- data/spec/command_spec.rb +15 -2
- data/spec/option_spec.rb +4 -11
- data/spec/support/lib/test_app_runner.rb +2 -1
- data/spec/support/shared_examples/action_examples.rb +19 -0
- data/spec/support/shared_examples/commands_examples.rb +5 -4
- data/spec/support/shared_examples/options_examples.rb +5 -4
- data/spec/support/shared_examples/runner_examples.rb +9 -9
- data/spec/support/spec_helper.rb +3 -3
- metadata +30 -4
data/cp.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
$:.push File.expand_path("../lib", __FILE__)
|
3
2
|
require "cp/version"
|
4
3
|
|
@@ -10,12 +9,14 @@ Gem::Specification.new do |s|
|
|
10
9
|
s.email = ["fletch@pobox.com"]
|
11
10
|
s.homepage = "https://github.com/baseballdb/cp"
|
12
11
|
s.summary = %q{An alternative API for CmdParse}
|
13
|
-
s.description =
|
12
|
+
s.description = s.summary
|
14
13
|
|
15
14
|
s.files = `git ls-files`.split("\n")
|
16
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
17
|
s.require_paths = ["lib"]
|
19
18
|
|
20
|
-
s.add_runtime_dependency
|
19
|
+
s.add_runtime_dependency "cmdparse", "~> 2.0.2"
|
20
|
+
s.add_runtime_dependency "highline", "~> 1.6.2"
|
21
|
+
s.add_runtime_dependency "json_pure", "~> 1.5.1"
|
21
22
|
end
|
data/examples/net.rb
CHANGED
@@ -32,8 +32,8 @@ command :ipaddr do |c|
|
|
32
32
|
c.command( :add ) do |s|
|
33
33
|
s.summary = "Add an IP address"
|
34
34
|
|
35
|
-
s.
|
36
|
-
|
35
|
+
s.action do |opts, args|
|
36
|
+
say "Adding IP addresses: #{args.join(', ')}" if $verbose
|
37
37
|
$ipaddrs += args
|
38
38
|
end
|
39
39
|
end
|
@@ -44,11 +44,11 @@ command :ipaddr do |c|
|
|
44
44
|
|
45
45
|
s.option( "-a", "--all", "Delete all IP addresses" ){ $deleteAll = true }
|
46
46
|
|
47
|
-
s.
|
47
|
+
s.action do |opts, args|
|
48
48
|
if $deleteAll
|
49
49
|
$ipaddrs = []
|
50
50
|
else
|
51
|
-
|
51
|
+
say "Deleting IP addresses: #{args.join(', ')}" if $verbose
|
52
52
|
args.each { |ip| $ipaddrs.delete( ip ) }
|
53
53
|
end
|
54
54
|
end
|
@@ -59,9 +59,9 @@ command :ipaddr do |c|
|
|
59
59
|
s.default = true
|
60
60
|
s.summary = "List all IP addresses"
|
61
61
|
|
62
|
-
s.
|
63
|
-
|
64
|
-
|
62
|
+
s.action do |*args|
|
63
|
+
say "Listing IP addresses:" if $verbose
|
64
|
+
say $ipaddrs.to_yaml
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -70,15 +70,16 @@ command :ipaddr do |c|
|
|
70
70
|
s.summary = "Show network statistics"
|
71
71
|
s.description = "This command shows very useful network statistics - eye catching!!!"
|
72
72
|
|
73
|
-
s.
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
s.action do |opts, args|
|
74
|
+
if $verbose
|
75
|
+
say "Showing network statistics"
|
76
|
+
say
|
77
|
+
end
|
78
|
+
say "Yeah, I will do something now..."
|
79
|
+
say
|
78
80
|
1.upto(10) do |row|
|
79
|
-
|
81
|
+
say " "*(20-row) + "#"*(row*2 - 1)
|
80
82
|
end
|
81
|
-
puts
|
82
83
|
end
|
83
84
|
end
|
84
85
|
end
|
data/lib/cp.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
1
|
require "rubygems"
|
2
|
+
|
2
3
|
require "cmdparse"
|
4
|
+
require "highline"
|
5
|
+
require "json"
|
3
6
|
require "optparse"
|
7
|
+
require "terminal-table"
|
8
|
+
require "yaml"
|
9
|
+
|
10
|
+
require "ext/core"
|
4
11
|
|
5
12
|
require "cp/has/commands"
|
6
13
|
require "cp/has/options"
|
14
|
+
require "cp/highline"
|
7
15
|
|
8
16
|
require "cp/app"
|
9
17
|
require "cp/command"
|
@@ -28,7 +36,7 @@ module CP
|
|
28
36
|
at_exit { CP::App.run } if is_main
|
29
37
|
end
|
30
38
|
|
31
|
-
|
39
|
+
CP::App.exported_methods.each do |method|
|
32
40
|
define_method( method ) { |*args, &block|
|
33
41
|
CP::App.instance.send( method, *args, &block )
|
34
42
|
}
|
data/lib/cp/app.rb
CHANGED
@@ -12,6 +12,8 @@ module CP
|
|
12
12
|
def initialize
|
13
13
|
self.name = File.basename( $0 )
|
14
14
|
self.runner = CP::Runners::CmdParse
|
15
|
+
|
16
|
+
define_builtin_options
|
15
17
|
end
|
16
18
|
|
17
19
|
def app( attr, value )
|
@@ -22,6 +24,15 @@ module CP
|
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
27
|
+
def define_builtin_options
|
28
|
+
option( "-f", "--format FORMAT", "Output format" ) do |o|
|
29
|
+
o.allowed = [:json, :table, :yaml]
|
30
|
+
o.action = lambda { |value|
|
31
|
+
CP::HighLine.instance.format = value
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
25
36
|
def fatal( msg )
|
26
37
|
self.error( msg )
|
27
38
|
exit 1
|
@@ -31,6 +42,10 @@ module CP
|
|
31
42
|
$stderr.puts "#{self.name}: #{msg}. See `#{self.name} --help`."
|
32
43
|
end
|
33
44
|
|
45
|
+
def self.exported_methods
|
46
|
+
[:app, :command, :option]
|
47
|
+
end
|
48
|
+
|
34
49
|
def run( *args )
|
35
50
|
CP::App.instance.runner.new( CP::App.instance ).run( *args )
|
36
51
|
end
|
data/lib/cp/command.rb
CHANGED
@@ -3,7 +3,7 @@ module CP
|
|
3
3
|
include CP::Has::Commands
|
4
4
|
include CP::Has::Options
|
5
5
|
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :name, :parent
|
7
7
|
attr_accessor :default, :description, :summary
|
8
8
|
|
9
9
|
def initialize( name, parent=nil )
|
@@ -17,38 +17,54 @@ module CP
|
|
17
17
|
yield self if block_given?
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
def action( &block )
|
21
|
+
if !block_given?
|
22
|
+
@action
|
23
|
+
else
|
24
|
+
@action = lambda { |args|
|
25
|
+
begin
|
26
|
+
opts = gather_options
|
27
|
+
rescue CP::MissingOptionError => e
|
28
|
+
CP::App.instance.fatal( "'#{e}' is required" )
|
29
|
+
end
|
27
30
|
|
28
|
-
|
29
|
-
|
31
|
+
block.call( args, opts )
|
32
|
+
CP::HighLine.instance.say_buffer
|
33
|
+
}
|
34
|
+
end
|
30
35
|
end
|
31
36
|
|
32
|
-
|
37
|
+
def action=( block )
|
38
|
+
action( &block )
|
39
|
+
end
|
33
40
|
|
34
|
-
|
35
|
-
options = []
|
41
|
+
private
|
36
42
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
# get ancestor commands [child, parent, grandparent]
|
44
|
+
def ancestors
|
45
|
+
commands = [self]
|
46
|
+
while commands.last.respond_to?( :parent ) && commands.last.parent
|
47
|
+
commands << commands.last.parent
|
48
|
+
end
|
49
|
+
commands
|
50
|
+
end
|
42
51
|
|
43
|
-
|
44
|
-
|
45
|
-
o.
|
46
|
-
|
52
|
+
def gather_options
|
53
|
+
options = ancestors.reverse.inject( {} ) do |o, command|
|
54
|
+
o.merge( command.options )
|
55
|
+
end
|
47
56
|
|
48
|
-
|
57
|
+
validate_options( options )
|
49
58
|
|
50
|
-
|
59
|
+
struct = CP::OptionsStruct.new( *options.keys )
|
60
|
+
options.each { |k, v| struct[k] = v.value }
|
51
61
|
struct
|
52
62
|
end
|
63
|
+
|
64
|
+
def validate_options( opts )
|
65
|
+
opts.each do |k, v|
|
66
|
+
raise CP::MissingOptionError.new( v.switches.last ) if v.required? && v.value.nil?
|
67
|
+
end
|
68
|
+
end
|
53
69
|
end
|
54
70
|
end
|
data/lib/cp/has/commands.rb
CHANGED
@@ -2,17 +2,17 @@ module CP
|
|
2
2
|
module Has
|
3
3
|
module Commands
|
4
4
|
def commands
|
5
|
-
@commands ||=
|
5
|
+
@commands ||= {}
|
6
6
|
@commands
|
7
7
|
end
|
8
8
|
|
9
9
|
def command( name )
|
10
10
|
cmd = name.to_s.split( " " ).inject( self ) do |parent, name|
|
11
|
-
subcommand = parent.commands
|
11
|
+
subcommand = parent.commands[name.to_sym]
|
12
12
|
|
13
13
|
if subcommand.nil?
|
14
14
|
subcommand = CP::Command.new( name, parent )
|
15
|
-
parent.commands
|
15
|
+
parent.commands[subcommand.name] = subcommand
|
16
16
|
end
|
17
17
|
|
18
18
|
subcommand
|
@@ -21,7 +21,7 @@ module CP
|
|
21
21
|
yield cmd if block_given?
|
22
22
|
|
23
23
|
if cmd.default
|
24
|
-
default_cmd = commands.find{ |c| c.default }
|
24
|
+
default_cmd = commands.values.find{ |c| c.default && c != cmd }
|
25
25
|
if default_cmd
|
26
26
|
raise CP::CommandError.new( "only one default command is allowed: #{default_cmd.name}, #{cmd.name}" )
|
27
27
|
end
|
data/lib/cp/has/options.rb
CHANGED
@@ -2,14 +2,23 @@ module CP
|
|
2
2
|
module Has
|
3
3
|
module Options
|
4
4
|
def options
|
5
|
-
@options ||=
|
5
|
+
@options ||= {}
|
6
6
|
@options
|
7
7
|
end
|
8
8
|
|
9
9
|
def option( *args )
|
10
10
|
opt = CP::Option.new( *args )
|
11
11
|
yield opt if block_given?
|
12
|
-
|
12
|
+
|
13
|
+
if( respond_to?( :ancestors, true ) )
|
14
|
+
parent_opt = ancestors[1..-1].reverse.inject( {} ) { |opts, c|
|
15
|
+
opts.merge( c.options )
|
16
|
+
}[opt.name]
|
17
|
+
|
18
|
+
opt = parent_opt.merge( opt ) if parent_opt
|
19
|
+
end
|
20
|
+
|
21
|
+
options[opt.name] = opt
|
13
22
|
opt
|
14
23
|
end
|
15
24
|
end
|
data/lib/cp/highline.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "singleton"
|
3
|
+
|
4
|
+
module CP
|
5
|
+
class HighLine < HighLine
|
6
|
+
include ::Singleton
|
7
|
+
|
8
|
+
attr_reader :format
|
9
|
+
|
10
|
+
def format=( format )
|
11
|
+
@format = format
|
12
|
+
@buffer = @format.nil? ? nil : []
|
13
|
+
end
|
14
|
+
|
15
|
+
def say( statement="" )
|
16
|
+
@output = $stdout # because we override $stdout for testing
|
17
|
+
|
18
|
+
if !@buffer.nil?
|
19
|
+
@buffer << statement
|
20
|
+
else
|
21
|
+
formatter = "to_#{format}".to_sym
|
22
|
+
statement = statement.respond_to?( formatter ) ? statement.send( formatter ) : statement.to_s
|
23
|
+
super( statement )
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def say_buffer
|
28
|
+
if !@buffer.nil? && @buffer.size > 0
|
29
|
+
statement = @buffer
|
30
|
+
@buffer = nil
|
31
|
+
say( statement.size === 1 ? statement.first : statement )
|
32
|
+
@buffer = []
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Kernel
|
39
|
+
extend Forwardable
|
40
|
+
def_delegators :"CP::HighLine.instance", :agree, :ask, :choose, :say
|
41
|
+
end
|
data/lib/cp/option.rb
CHANGED
@@ -3,7 +3,7 @@ require "optparse"
|
|
3
3
|
module CP
|
4
4
|
class Option
|
5
5
|
attr_accessor :allowed, :default, :description, :type
|
6
|
-
attr_reader :arg, :
|
6
|
+
attr_reader :arg, :short, :long
|
7
7
|
|
8
8
|
# see: OptionsParser#make_switch
|
9
9
|
def initialize( *args )
|
@@ -20,11 +20,21 @@ module CP
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
def action( &block )
|
24
|
+
save_value = lambda { |value| @value = value }
|
25
|
+
|
26
|
+
if !block_given?
|
27
|
+
@action || save_value
|
28
|
+
else
|
29
|
+
@action = lambda { |value|
|
30
|
+
save_value.call( value )
|
31
|
+
block.call( *( block.arity === 0 ? [] : [value] ) ) if block
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def action=( block )
|
37
|
+
action( &block )
|
28
38
|
end
|
29
39
|
|
30
40
|
def long=( val )
|
@@ -40,6 +50,17 @@ module CP
|
|
40
50
|
name.gsub( "-", "_" ).to_sym
|
41
51
|
end
|
42
52
|
|
53
|
+
def merge( opt )
|
54
|
+
new_opt = self.dup
|
55
|
+
new_opt.action = @action
|
56
|
+
[:allowed, :default, :description, :type, :short, :long].each { |attr|
|
57
|
+
val = opt.send( :"#{attr}" )
|
58
|
+
new_opt.send( :"#{attr}=", val.dup ) unless val.nil?
|
59
|
+
}
|
60
|
+
|
61
|
+
new_opt
|
62
|
+
end
|
63
|
+
|
43
64
|
def required=( val )
|
44
65
|
@required = !!val
|
45
66
|
end
|
@@ -63,7 +84,7 @@ module CP
|
|
63
84
|
end
|
64
85
|
|
65
86
|
def to_option_parser_args
|
66
|
-
args = self.switches + [self.type, self.allowed, self.description, self.
|
87
|
+
args = self.switches + [self.type, self.allowed, self.description, self.action]
|
67
88
|
args.find_all { |a| !a.nil? }
|
68
89
|
end
|
69
90
|
|
@@ -81,7 +102,7 @@ module CP
|
|
81
102
|
self.allowed = args.find { |a| a.is_a?( Hash ) || a.is_a?( Array ) }
|
82
103
|
self.type = args.find { |a| a.is_a?( Class ) }
|
83
104
|
self.description = switch.desc.first rescue nil
|
84
|
-
self.
|
105
|
+
self.action = switch.block
|
85
106
|
self.long = switch
|
86
107
|
self.short = switch
|
87
108
|
end
|
@@ -100,7 +121,8 @@ module CP
|
|
100
121
|
end
|
101
122
|
|
102
123
|
@arg = switch.arg
|
103
|
-
|
124
|
+
switch = switch.send( which )
|
125
|
+
instance_variable_set( :"@#{which}", switch.first ) unless switch.nil?
|
104
126
|
end
|
105
127
|
end
|
106
128
|
end
|
data/lib/cp/runners/cmd_parse.rb
CHANGED
@@ -17,12 +17,12 @@ module CP
|
|
17
17
|
|
18
18
|
rescue ::CmdParse::InvalidCommandError => e
|
19
19
|
command_name << e.message.gsub( /^.*: /, '' )
|
20
|
-
CP::App.instance.fatal( "'#{command_name}' is not a #{CP::App.instance.name} command
|
20
|
+
CP::App.instance.fatal( "'#{command_name}' is not a #{CP::App.instance.name} command" )
|
21
21
|
|
22
22
|
rescue ::CmdParse::InvalidOptionError,
|
23
23
|
::OptionParser::InvalidOption => e
|
24
24
|
switch = e.message.gsub( /^.*: /, '' )
|
25
|
-
CP::App.instance.fatal( "'#{switch}' is not a valid option
|
25
|
+
CP::App.instance.fatal( "'#{switch}' is not a valid option" )
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -34,8 +34,8 @@ module CP
|
|
34
34
|
add_options( runner, @app.options )
|
35
35
|
add_commands( runner, @app.commands )
|
36
36
|
|
37
|
-
unless @app.commands
|
38
|
-
has_default_command = @app.commands.find { |c| c.default }
|
37
|
+
unless @app.commands[:help]
|
38
|
+
has_default_command = @app.commands.values.find { |c| c.default }
|
39
39
|
runner.add_command( ::CmdParse::HelpCommand.new, !has_default_command )
|
40
40
|
end
|
41
41
|
|
@@ -48,20 +48,20 @@ module CP
|
|
48
48
|
unless options.empty?
|
49
49
|
target.options = ::CmdParse::OptionParserWrapper.new do |o|
|
50
50
|
o.separator "Global Options:"
|
51
|
-
options.each { |opt| o.on( *opt.to_option_parser_args ) }
|
51
|
+
options.values.each { |opt| o.on( *opt.to_option_parser_args ) }
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
56
|
def add_commands( target, commands )
|
57
57
|
unless commands.empty?
|
58
|
-
commands.each do |c|
|
58
|
+
commands.values.each do |c|
|
59
59
|
cmd = ::CmdParse::Command.new( c.name.to_s, !c.commands.empty? )
|
60
60
|
cmd.description = c.description
|
61
61
|
cmd.short_desc = c.summary
|
62
62
|
|
63
63
|
cmd.set_execution_block do |args|
|
64
|
-
c.
|
64
|
+
c.action.call( args )
|
65
65
|
end
|
66
66
|
|
67
67
|
add_options( cmd, c.options )
|
data/lib/cp/version.rb
CHANGED
data/lib/ext/core.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Array
|
2
|
+
def to_table
|
3
|
+
if self.first.is_a?( Hash )
|
4
|
+
headings = self.first.keys
|
5
|
+
Terminal::Table.new(
|
6
|
+
:headings => headings,
|
7
|
+
:rows => self.map { |r| headings.map { |h| r[h] } }
|
8
|
+
).to_s
|
9
|
+
else
|
10
|
+
Terminal::Table.new( :rows => self.map { |r| r.is_a?( Array ) ? r : [r] } ).to_s
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Hash
|
16
|
+
def to_table
|
17
|
+
Terminal::Table.new( :headings => self.keys, :rows => [self.values] ).to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Object
|
22
|
+
def to_table
|
23
|
+
Terminal::Table.new( :rows => [[self]] ).to_s
|
24
|
+
end
|
25
|
+
end
|
data/spec/app_spec.rb
CHANGED
@@ -3,6 +3,7 @@ require File.join( File.dirname( __FILE__ ), "support", "spec_helper" )
|
|
3
3
|
describe CP::App do
|
4
4
|
before( :each ) do
|
5
5
|
@target = CP::App.instance
|
6
|
+
@result = { :foo => "bar" }
|
6
7
|
end
|
7
8
|
|
8
9
|
it_should_behave_like "it accepts commands"
|
@@ -38,6 +39,71 @@ describe CP::App do
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
42
|
+
describe "built-in options" do
|
43
|
+
describe "--format" do
|
44
|
+
it "should exist" do
|
45
|
+
@target.options[:format].should_not be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should default to unformatted" do
|
49
|
+
run( "test" ).output.should === "#{@result}\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should accept 'json'" do
|
53
|
+
run( "--format", "json", "test" ).output.should === "#{@result.to_json}\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should accept 'table'" do
|
57
|
+
run( "--format", "table", "test" ).output.should === @result.to_table
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should accept 'yaml'" do
|
61
|
+
run( "--format", "yaml", "test" ).output.should === @result.to_yaml
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should buffer output for non-default formats" do
|
65
|
+
@result = [1,2,3]
|
66
|
+
run( "--format", "yaml", "test" ) do |app|
|
67
|
+
app.command( :test ) { @result.each { |line| say line } }
|
68
|
+
end.output.should === @result.to_yaml
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "per-command options" do
|
74
|
+
before( :each ) do
|
75
|
+
@target.option( "--opt" ) do |o|
|
76
|
+
o.description = "does something optional"
|
77
|
+
o.default = "foo"
|
78
|
+
end
|
79
|
+
@target.command( :test ) do |c|
|
80
|
+
c.option( "--opt" ) { |o| o.default = "subfoo" }
|
81
|
+
c.command( :subtest ) do |s|
|
82
|
+
s.option( "--opt" )
|
83
|
+
end
|
84
|
+
end
|
85
|
+
@parent_opt = @target.options[:opt]
|
86
|
+
@child_opt = @target.commands[:test].options[:opt]
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should be a copy of the parent Option" do
|
90
|
+
@child_opt.should_not === @parent_opt
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should extend the parent option of the same name" do
|
94
|
+
@child_opt.description.should === @parent_opt.description
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should cascade down to any level of commands" do
|
98
|
+
@child_opt = @target.commands[:test].commands[:subtest].options[:opt]
|
99
|
+
@child_opt.description.should === @parent_opt.description
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should not alter the parent option" do
|
103
|
+
@parent_opt.default.should_not === @child_opt.default
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
41
107
|
describe "properties" do
|
42
108
|
[:name, :version].each do |prop|
|
43
109
|
it "should accept a #{prop} property" do
|
data/spec/command_spec.rb
CHANGED
@@ -7,6 +7,19 @@ describe CP::Command do
|
|
7
7
|
|
8
8
|
it_should_behave_like "it accepts commands"
|
9
9
|
it_should_behave_like "it accepts options"
|
10
|
+
it_should_behave_like "it has an action"
|
11
|
+
|
12
|
+
it "has HighLine integration" do
|
13
|
+
create_test_app do |app|
|
14
|
+
app.command( :test ) do |c|
|
15
|
+
c.action do
|
16
|
+
[:agree, :ask, :choose, :say].inject( true ) { |b, method|
|
17
|
+
b && respond_to?( method )
|
18
|
+
}.should be_true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end.run "test"
|
22
|
+
end
|
10
23
|
|
11
24
|
describe "attributes" do
|
12
25
|
[
|
@@ -38,8 +51,8 @@ describe CP::Command do
|
|
38
51
|
|
39
52
|
it "saves the block as #block" do
|
40
53
|
block_ran = false
|
41
|
-
@target.
|
42
|
-
@target.
|
54
|
+
@target.action { block_ran = true }
|
55
|
+
@target.action.call( nil )
|
43
56
|
block_ran.should be_true
|
44
57
|
end
|
45
58
|
|
data/spec/option_spec.rb
CHANGED
@@ -5,6 +5,7 @@ describe CP::Option do
|
|
5
5
|
@target = CP::Option.new( "-x" )
|
6
6
|
end
|
7
7
|
|
8
|
+
it_should_behave_like "it has an action"
|
8
9
|
|
9
10
|
describe "attributes" do
|
10
11
|
[
|
@@ -37,19 +38,11 @@ describe CP::Option do
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
40
|
-
describe "#
|
41
|
+
describe "#action" do
|
41
42
|
it "should save the value" do
|
42
|
-
|
43
|
-
@target.block.call( "foo" )
|
43
|
+
@target.action.call( "foo" )
|
44
44
|
@target.value.should === "foo"
|
45
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
46
|
end
|
54
47
|
|
55
48
|
describe "#default" do
|
@@ -128,7 +121,7 @@ describe CP::Option do
|
|
128
121
|
end
|
129
122
|
it "sets the block from arguments" do
|
130
123
|
ran = false
|
131
|
-
CP::Option.new( "-s", lambda{ ran = true } ).
|
124
|
+
CP::Option.new( "-s", lambda{ ran = true } ).action.call( nil )
|
132
125
|
ran.should be_true
|
133
126
|
end
|
134
127
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
shared_examples_for "it has an action" do
|
2
|
+
describe "#action" do
|
3
|
+
it "accepts a block as #action" do
|
4
|
+
called = false
|
5
|
+
@target.action { |*args| called = true }
|
6
|
+
args = [nil] * @target.action.arity
|
7
|
+
@target.action.call( *args )
|
8
|
+
called.should be_true
|
9
|
+
end
|
10
|
+
|
11
|
+
it "accepts a Proc as #action=" do
|
12
|
+
called = false
|
13
|
+
@target.action = lambda { |*args| called = true }
|
14
|
+
args = [nil] * @target.action.arity
|
15
|
+
@target.action.call( *args )
|
16
|
+
called.should be_true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -28,8 +28,8 @@ shared_examples_for "it accepts commands" do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
describe "#commands" do
|
31
|
-
it "should return
|
32
|
-
@target.commands.should be_an_instance_of(
|
31
|
+
it "should return a hash" do
|
32
|
+
@target.commands.should be_an_instance_of( Hash )
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should increase with each defined command" do
|
@@ -39,12 +39,13 @@ shared_examples_for "it accepts commands" do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
it "should include each defined command" do
|
42
|
-
|
42
|
+
cmd = @target.command( :test )
|
43
|
+
@target.commands.values.include?( cmd ).should be_true
|
43
44
|
end
|
44
45
|
|
45
46
|
it "should only allow one default command" do
|
47
|
+
@target.command( :test ) { |c| c.default = true }
|
46
48
|
lambda {
|
47
|
-
@target.command( :test ) { |c| c.default = true }
|
48
49
|
@target.command( :test2 ) { |c| c.default = true }
|
49
50
|
}.should raise_error( CP::CommandError, /only one/ )
|
50
51
|
end
|
@@ -6,18 +6,19 @@ shared_examples_for "it accepts options" do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe "#options" do
|
9
|
-
it "should return
|
10
|
-
@target.options.should be_an_instance_of(
|
9
|
+
it "should return a hash" do
|
10
|
+
@target.options.should be_an_instance_of( Hash )
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should increase with each defined option" do
|
14
14
|
lambda {
|
15
15
|
@target.option( "-s" )
|
16
|
-
}.should change(){ @target.options.length}.by( 1 )
|
16
|
+
}.should change(){ @target.options.length }.by( 1 )
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should include each defined option" do
|
20
|
-
|
20
|
+
opt = @target.option( "-s" )
|
21
|
+
@target.options.values.include?( opt ).should be_true
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
@@ -11,7 +11,7 @@ shared_examples_for "it is a runner" do
|
|
11
11
|
|
12
12
|
run( "test", "foo", "bar" ) do |app|
|
13
13
|
app.command( :test ) { |c|
|
14
|
-
c.
|
14
|
+
c.action { |args, opts| passed_args = args }
|
15
15
|
}
|
16
16
|
end
|
17
17
|
|
@@ -40,7 +40,7 @@ shared_examples_for "it is a runner" do
|
|
40
40
|
|
41
41
|
run( "help" ) do |app|
|
42
42
|
app.command( :help ) do |c|
|
43
|
-
c.
|
43
|
+
c.action { custom_help_ran = true }
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -58,7 +58,7 @@ shared_examples_for "it is a runner" do
|
|
58
58
|
run( "test" ) do |app|
|
59
59
|
app.command( :test ) { |c|
|
60
60
|
c.option( "--[no-]option" ) { |o| o.default = true }
|
61
|
-
c.
|
61
|
+
c.action { |args, opts| passed_value = opts.option }
|
62
62
|
}
|
63
63
|
end
|
64
64
|
|
@@ -71,7 +71,7 @@ shared_examples_for "it is a runner" do
|
|
71
71
|
run( "test", "--no-option" ) do |app|
|
72
72
|
app.command( :test ) { |c|
|
73
73
|
c.option( "--[no-]option" ) { |o| o.default = true }
|
74
|
-
c.
|
74
|
+
c.action { |args, opts| passed_value = opts.option }
|
75
75
|
}
|
76
76
|
end
|
77
77
|
|
@@ -87,7 +87,7 @@ shared_examples_for "it is a runner" do
|
|
87
87
|
run( "test" ) do |app|
|
88
88
|
app.command( :test ) { |c|
|
89
89
|
c.option( "--option VAL" ) { |o| o.default = "foo" }
|
90
|
-
c.
|
90
|
+
c.action { |args, opts| passed_value = opts.option }
|
91
91
|
}
|
92
92
|
end
|
93
93
|
|
@@ -111,7 +111,7 @@ shared_examples_for "it is a runner" do
|
|
111
111
|
@result = run( "test" ) do |app|
|
112
112
|
app.command( :test ) { |c|
|
113
113
|
c.option( "--option" ) { |o| o.required = true }
|
114
|
-
c.
|
114
|
+
c.action { |args, opts| }
|
115
115
|
}
|
116
116
|
end
|
117
117
|
end
|
@@ -132,7 +132,7 @@ shared_examples_for "it is a runner" do
|
|
132
132
|
|
133
133
|
run( "test", "foo", "bar" ) do |app|
|
134
134
|
app.command( :test ) { |c|
|
135
|
-
c.
|
135
|
+
c.action { |args, opts| opts_struct = opts }
|
136
136
|
}
|
137
137
|
end
|
138
138
|
|
@@ -145,7 +145,7 @@ shared_examples_for "it is a runner" do
|
|
145
145
|
run( "test", "--option", "foo" ) do |app|
|
146
146
|
app.command( :test ) { |c|
|
147
147
|
c.option( "--option FOO" )
|
148
|
-
c.
|
148
|
+
c.action { |args, opts| passed_value = opts.option }
|
149
149
|
}
|
150
150
|
end
|
151
151
|
|
@@ -160,7 +160,7 @@ shared_examples_for "it is a runner" do
|
|
160
160
|
cmd.command( :sub1 ) { |sub1|
|
161
161
|
sub1.option( "--option FOO" )
|
162
162
|
sub1.command( :sub2 ) { |sub2|
|
163
|
-
sub2.
|
163
|
+
sub2.action { |args, opts| passed_value = opts.option }
|
164
164
|
}
|
165
165
|
}
|
166
166
|
}
|
data/spec/support/spec_helper.rb
CHANGED
@@ -30,8 +30,8 @@ def create_test_app
|
|
30
30
|
a.command( :test ) do |c|
|
31
31
|
c.summary = "test summary"
|
32
32
|
c.option "-v", "--verbose", "verbose description"
|
33
|
-
c.
|
34
|
-
"test #{args.join( ", " )}"
|
33
|
+
c.action do |args|
|
34
|
+
say( @result || "test #{args.join( ", " )}" )
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -42,7 +42,7 @@ end
|
|
42
42
|
|
43
43
|
def run *args, &block
|
44
44
|
runner = TestAppRunner.new
|
45
|
-
runner.run( *args, &block )
|
45
|
+
runner.run( *args, @result, &block )
|
46
46
|
runner
|
47
47
|
end
|
48
48
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: cp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Rick Fletcher
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-07-
|
13
|
+
date: 2011-07-17 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: cmdparse
|
@@ -18,12 +18,34 @@ dependencies:
|
|
18
18
|
requirement: &id001 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
|
-
- -
|
21
|
+
- - ~>
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: 2.0.2
|
24
24
|
type: :runtime
|
25
25
|
version_requirements: *id001
|
26
|
-
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: highline
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.6.2
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: json_pure
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.1
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id003
|
48
|
+
description: An alternative API for CmdParse
|
27
49
|
email:
|
28
50
|
- fletch@pobox.com
|
29
51
|
executables: []
|
@@ -45,10 +67,12 @@ files:
|
|
45
67
|
- lib/cp/errors.rb
|
46
68
|
- lib/cp/has/commands.rb
|
47
69
|
- lib/cp/has/options.rb
|
70
|
+
- lib/cp/highline.rb
|
48
71
|
- lib/cp/option.rb
|
49
72
|
- lib/cp/options_struct.rb
|
50
73
|
- lib/cp/runners/cmd_parse.rb
|
51
74
|
- lib/cp/version.rb
|
75
|
+
- lib/ext/core.rb
|
52
76
|
- spec/app_spec.rb
|
53
77
|
- spec/command_spec.rb
|
54
78
|
- spec/cp_spec.rb
|
@@ -58,6 +82,7 @@ files:
|
|
58
82
|
- spec/options_struct_spec.rb
|
59
83
|
- spec/runners/cmd_parse_spec.rb
|
60
84
|
- spec/support/lib/test_app_runner.rb
|
85
|
+
- spec/support/shared_examples/action_examples.rb
|
61
86
|
- spec/support/shared_examples/commands_examples.rb
|
62
87
|
- spec/support/shared_examples/options_examples.rb
|
63
88
|
- spec/support/shared_examples/runner_examples.rb
|
@@ -100,6 +125,7 @@ test_files:
|
|
100
125
|
- spec/options_struct_spec.rb
|
101
126
|
- spec/runners/cmd_parse_spec.rb
|
102
127
|
- spec/support/lib/test_app_runner.rb
|
128
|
+
- spec/support/shared_examples/action_examples.rb
|
103
129
|
- spec/support/shared_examples/commands_examples.rb
|
104
130
|
- spec/support/shared_examples/options_examples.rb
|
105
131
|
- spec/support/shared_examples/runner_examples.rb
|