luban-cli 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -3
- data/lib/luban/cli/application.rb +2 -2
- data/lib/luban/cli/base/core.rb +17 -13
- data/lib/luban/cli/base/dsl.rb +34 -19
- data/lib/luban/cli/command.rb +7 -3
- data/lib/luban/cli/commands.rb +43 -27
- data/lib/luban/cli/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad584f0174c5361200ed88f252387ac294ff8768
|
4
|
+
data.tar.gz: 9af48be33bc18fa6d049780354d0a6dc3abb34fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 932c919d74edc1e23cc4a45fe10240913603864aa25cf71a24b76e0a542da0a54296d20348fb5f7dc5c645b1b143e3557d897a6fbaf36df2ae88b5a0ba1bd400
|
7
|
+
data.tar.gz: 889e415204354c2c6db2440e1297fb52a85e4f59a0d662707c3bc404066eeb835c592b156fc3594bb35562c9db64f463504b2ab3bb1ebd97934de4a0e0b465b1
|
data/CHANGELOG.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
Bootstrapped Luban::CLI
|
6
6
|
|
7
|
-
|
7
|
+
New features:
|
8
8
|
* Support general command-line parsing
|
9
9
|
* Support options
|
10
10
|
* Support switches (boolean options)
|
@@ -15,9 +15,27 @@ Features:
|
|
15
15
|
## Version 0.2.0 (Apr 02, 2015)
|
16
16
|
|
17
17
|
Minor enhancements:
|
18
|
-
*
|
19
|
-
*
|
18
|
+
* Refactor error class
|
19
|
+
* Refactor argument validation
|
20
20
|
* Validate required options/arguments in Luban::CLI::Base
|
21
21
|
* Create singleton action handler method on application instance
|
22
22
|
* Move parse error handling to action handler
|
23
23
|
* Exclude examples and spec from the gem itself
|
24
|
+
|
25
|
+
## Version 0.3.0 (Apr 11, 2015)
|
26
|
+
|
27
|
+
New features:
|
28
|
+
* Support prefix for action name
|
29
|
+
* By default, subcommand method is prefixed with "__command_"
|
30
|
+
* By default, application action method has no prefix
|
31
|
+
* Support nested subcommands
|
32
|
+
* Add help option by default in Luban::CLI::Base in order to turn on auto help by default
|
33
|
+
|
34
|
+
Minor enhancements:
|
35
|
+
* Refactor action creation to be more readable
|
36
|
+
* Add an example for subcommands and nested subcommands
|
37
|
+
|
38
|
+
Bug fixes:
|
39
|
+
* Apply the correct method creator when defining action method
|
40
|
+
* Dispatch command under the right class context
|
41
|
+
* Show correct command chain between program name and synopsis when composing parser banner
|
@@ -5,8 +5,8 @@ module Luban
|
|
5
5
|
class Application < Base
|
6
6
|
attr_reader :rc
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
super(self,
|
8
|
+
def initialize(action_name = :run, **opts, &config_blk)
|
9
|
+
super(self, action_name, **opts, &config_blk)
|
10
10
|
@rc = init_rc
|
11
11
|
validate
|
12
12
|
end
|
data/lib/luban/cli/base/core.rb
CHANGED
@@ -19,6 +19,9 @@ module Luban
|
|
19
19
|
DefaultSummaryIndent = 4
|
20
20
|
DefaultTitleIndent = 2
|
21
21
|
|
22
|
+
attr_reader :app
|
23
|
+
attr_reader :prefix
|
24
|
+
attr_reader :action_method
|
22
25
|
attr_reader :program_name
|
23
26
|
attr_reader :options
|
24
27
|
attr_reader :arguments
|
@@ -32,9 +35,11 @@ module Luban
|
|
32
35
|
attr_accessor :summary_width
|
33
36
|
attr_accessor :summary_indent
|
34
37
|
|
35
|
-
def initialize(app,
|
38
|
+
def initialize(app, action_name, prefix: default_prefix, auto_help: true, &config_blk)
|
36
39
|
@app = app
|
37
|
-
@
|
40
|
+
@action_name = action_name
|
41
|
+
@prefix = prefix
|
42
|
+
@action_method = "#{@prefix}#{@action_name}"
|
38
43
|
@action_defined = false
|
39
44
|
|
40
45
|
@program_name = default_program_name
|
@@ -51,9 +56,12 @@ module Luban
|
|
51
56
|
@summary_indent = DefaultSummaryIndent
|
52
57
|
|
53
58
|
configure(&config_blk)
|
54
|
-
|
59
|
+
setup_default_action unless @action_defined
|
60
|
+
self.auto_help if auto_help
|
55
61
|
end
|
56
62
|
|
63
|
+
def default_prefix; ''; end
|
64
|
+
|
57
65
|
def parser
|
58
66
|
@parser ||= create_parser
|
59
67
|
end
|
@@ -75,20 +83,16 @@ module Luban
|
|
75
83
|
instance_eval(&config_blk) unless config_blk.nil?
|
76
84
|
end
|
77
85
|
|
78
|
-
def
|
79
|
-
method = @
|
80
|
-
|
81
|
-
|
82
|
-
else
|
83
|
-
action do |**opts|
|
84
|
-
raise NotImplementedError, "#{self.class.name}##{method} is an abstract method."
|
85
|
-
end
|
86
|
+
def setup_default_action
|
87
|
+
method = @action_method
|
88
|
+
action do |**opts|
|
89
|
+
raise NotImplementedError, "#{self.class.name}##{method} is an abstract method."
|
86
90
|
end
|
87
91
|
end
|
88
92
|
|
89
|
-
def dispatch_command(cmd:, argv:, **params)
|
93
|
+
def dispatch_command(context, cmd:, argv:, **params)
|
90
94
|
validate_command(cmd)
|
91
|
-
send(cmd, argv)
|
95
|
+
context.send(commands[cmd].action_method, argv)
|
92
96
|
end
|
93
97
|
|
94
98
|
def validate_command(cmd)
|
data/lib/luban/cli/base/dsl.rb
CHANGED
@@ -8,15 +8,14 @@ module Luban
|
|
8
8
|
|
9
9
|
def configure(&blk); @config_blk = blk; end
|
10
10
|
|
11
|
-
def help_command(
|
11
|
+
def help_command(**opts, &blk)
|
12
12
|
if block_given?
|
13
|
-
command(
|
13
|
+
command(**opts, &blk)
|
14
14
|
else
|
15
|
-
command(:help) do
|
15
|
+
command(:help, **opts) do
|
16
16
|
desc "List all commands or help for one command"
|
17
17
|
argument :command, "Command to help for",
|
18
18
|
type: :symbol, required: false
|
19
|
-
self.auto_help if auto_help
|
20
19
|
action :show_help_for_command
|
21
20
|
end
|
22
21
|
end
|
@@ -99,29 +98,45 @@ module Luban
|
|
99
98
|
blk
|
100
99
|
end
|
101
100
|
if handler.nil?
|
102
|
-
raise ArgumentError, "Code block to execute command #{@
|
101
|
+
raise ArgumentError, "Code block to execute command #{@action_name} is MISSING."
|
103
102
|
end
|
104
103
|
_base = self
|
105
104
|
parse_method = preserve_argv ? :parse : :parse!
|
106
|
-
|
107
|
-
_base.send(parse_method, argv)
|
108
|
-
|
109
|
-
if _base.result[:opts][:help]
|
110
|
-
_base.show_help
|
111
|
-
elsif _base.result[:opts][:version]
|
112
|
-
_base.show_version
|
113
|
-
else
|
114
|
-
_base.validate_required_options
|
115
|
-
_base.validate_required_arguments
|
116
|
-
instance_exec(**_base.result, &handler)
|
117
|
-
end
|
118
|
-
rescue OptionParser::ParseError, Error => e
|
119
|
-
_base.on_parse_error(e)
|
105
|
+
define_action_method do |argv = _base.default_argv|
|
106
|
+
_base.send(:process, self, parse_method, argv) do |result|
|
107
|
+
instance_exec(**result, &handler)
|
120
108
|
end
|
121
109
|
end
|
122
110
|
@action_defined = true
|
123
111
|
end
|
124
112
|
|
113
|
+
def define_action_method(&action_blk)
|
114
|
+
@app.send(method_creator, action_method, &action_blk)
|
115
|
+
end
|
116
|
+
|
117
|
+
def method_creator
|
118
|
+
@method_creator ||= @app.is_a?(Class) ? :define_method : :define_singleton_method
|
119
|
+
end
|
120
|
+
|
121
|
+
def process(context, parse_method, argv)
|
122
|
+
send(parse_method, argv)
|
123
|
+
if result[:opts][:help]
|
124
|
+
show_help
|
125
|
+
elsif result[:opts][:version]
|
126
|
+
show_version
|
127
|
+
else
|
128
|
+
if has_commands?
|
129
|
+
dispatch_command(context, **result)
|
130
|
+
else
|
131
|
+
validate_required_options
|
132
|
+
validate_required_arguments
|
133
|
+
yield result
|
134
|
+
end
|
135
|
+
end
|
136
|
+
rescue OptionParser::ParseError, Error => e
|
137
|
+
on_parse_error(e)
|
138
|
+
end
|
139
|
+
|
125
140
|
def on_parse_error(error)
|
126
141
|
show_error_and_exit(error)
|
127
142
|
end
|
data/lib/luban/cli/command.rb
CHANGED
@@ -2,16 +2,20 @@ module Luban
|
|
2
2
|
module CLI
|
3
3
|
class Command < Base
|
4
4
|
attr_reader :name
|
5
|
+
attr_reader :command_chain
|
5
6
|
|
6
|
-
def initialize(app, name, &config_blk)
|
7
|
-
super
|
7
|
+
def initialize(app, name, command_chain: [name], **opts, &config_blk)
|
8
8
|
@name = name
|
9
|
+
@command_chain = command_chain
|
10
|
+
super(app, name, **opts, &config_blk)
|
9
11
|
end
|
10
12
|
|
13
|
+
def default_prefix; '__command_'; end
|
14
|
+
|
11
15
|
protected
|
12
16
|
|
13
17
|
def compose_banner
|
14
|
-
"Usage: #{program_name} #{
|
18
|
+
"Usage: #{program_name} #{command_chain.map(&:to_s).join(' ')} #{compose_synopsis}"
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
data/lib/luban/cli/commands.rb
CHANGED
@@ -6,21 +6,7 @@ module Luban
|
|
6
6
|
base.send(:include, InstanceMethods)
|
7
7
|
end
|
8
8
|
|
9
|
-
module
|
10
|
-
def inherited(subclass)
|
11
|
-
# Ensure commands from base class
|
12
|
-
# got inherited to its subclasses
|
13
|
-
subclass.instance_variable_set(
|
14
|
-
'@commands',
|
15
|
-
Marshal.load(Marshal.dump(instance_variable_get('@commands')))
|
16
|
-
)
|
17
|
-
super
|
18
|
-
end
|
19
|
-
|
20
|
-
def commands
|
21
|
-
@commands ||= {}
|
22
|
-
end
|
23
|
-
|
9
|
+
module CommonMethods
|
24
10
|
def list_commands
|
25
11
|
commands.keys
|
26
12
|
end
|
@@ -32,32 +18,62 @@ module Luban
|
|
32
18
|
def has_commands?
|
33
19
|
!commands.empty?
|
34
20
|
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
include CommonMethods
|
25
|
+
|
26
|
+
def commands
|
27
|
+
@commands ||= {}
|
28
|
+
end
|
35
29
|
|
36
|
-
def
|
37
|
-
|
30
|
+
def command_class(cmd)
|
31
|
+
"#{classify(cmd)}Command"
|
32
|
+
end
|
33
|
+
|
34
|
+
def command(app = self, cmd, **opts, &blk)
|
35
|
+
cmd_class = command_class(cmd)
|
36
|
+
klass = if self.const_defined?(command_class(cmd))
|
37
|
+
self.const_get(command_class(cmd))
|
38
|
+
else
|
39
|
+
self.const_set(command_class(cmd), Class.new(Command))
|
40
|
+
end
|
41
|
+
commands[cmd] = klass.new(app, cmd, **opts, &blk)
|
38
42
|
end
|
39
43
|
|
40
44
|
def undef_command(cmd)
|
41
|
-
commands.delete(cmd)
|
42
|
-
|
45
|
+
undef_method(commands.delete(cmd).action_method)
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def classify(cmd)
|
51
|
+
cmd = cmd.to_s.dup
|
52
|
+
cmd.gsub!(/\/(.?)/){ "::#{$1.upcase}" }
|
53
|
+
cmd.gsub!(/(?:_+|-+)([a-z])/){ $1.upcase }
|
54
|
+
cmd.gsub!(/(\A|\s)([a-z])/){ $1 + $2.upcase }
|
55
|
+
cmd
|
43
56
|
end
|
44
57
|
end
|
45
58
|
|
46
59
|
module InstanceMethods
|
60
|
+
include CommonMethods
|
61
|
+
|
47
62
|
def commands
|
48
63
|
self.class.commands
|
49
64
|
end
|
50
65
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
66
|
+
def command(cmd, **opts, &blk)
|
67
|
+
if self.is_a?(Command)
|
68
|
+
opts[:command_chain] = self.command_chain.clone.push(cmd)
|
69
|
+
self.class.command(self.app, cmd, **opts, &blk)
|
70
|
+
else
|
71
|
+
self.class.command(cmd, **opts, &blk)
|
72
|
+
end
|
57
73
|
end
|
58
74
|
|
59
|
-
def
|
60
|
-
self.class.
|
75
|
+
def undef_command(cmd)
|
76
|
+
self.class.undef_command(cmd)
|
61
77
|
end
|
62
78
|
end
|
63
79
|
end
|
data/lib/luban/cli/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: luban-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rubyist Chi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|