thunder 0.6.1 → 0.6.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/README.md +7 -0
- data/bin/thunder-completion +1 -1
- data/bin/thunder-spec +1 -1
- data/lib/thunder.rb +20 -25
- data/lib/thunder/help/default.rb +72 -74
- data/lib/thunder/options/optparse.rb +32 -34
- data/lib/thunder/options/trollop.rb +18 -20
- data/lib/thunder/version.rb +1 -1
- metadata +5 -4
data/README.md
CHANGED
@@ -2,11 +2,18 @@
|
|
2
2
|
=======
|
3
3
|
Ruby gem for quick and easy command line interfaces
|
4
4
|
|
5
|
+
[](http://badge.fury.io/rb/thunder)
|
6
|
+
[](https://codeclimate.com/github/stevenkaras/thunder)
|
7
|
+
|
5
8
|
Usage
|
6
9
|
-----
|
7
10
|
|
8
11
|
gem install thunder
|
9
12
|
|
13
|
+
or if you're running ruby 1.9.3:
|
14
|
+
|
15
|
+
gem install thunder-1.9.3
|
16
|
+
|
10
17
|
or if you're running [ruby 1.8.7](http://www.ruby-lang.org/en/news/2011/10/06/plans-for-1-8-7):
|
11
18
|
|
12
19
|
gem install thunder-1.8.7
|
data/bin/thunder-completion
CHANGED
data/bin/thunder-spec
CHANGED
data/lib/thunder.rb
CHANGED
@@ -10,14 +10,11 @@ module Thunder
|
|
10
10
|
# Start the object as a command line program,
|
11
11
|
# processing the given arguments and using the provided options.
|
12
12
|
#
|
13
|
-
# @param args [<String>] the command line arguments
|
14
|
-
# @param options [{Symbol => *}] the default options to use
|
15
|
-
def start(args=ARGV.dup, options={})
|
13
|
+
# @param args [<String>] (ARGV) the command line arguments
|
14
|
+
# @param options [{Symbol => *}] ({}) the default options to use
|
15
|
+
def start(args = ARGV.dup, options = {})
|
16
16
|
command_spec = determine_command(args)
|
17
|
-
|
18
|
-
unless command_spec
|
19
|
-
return
|
20
|
-
end
|
17
|
+
return unless command_spec
|
21
18
|
|
22
19
|
if command_spec[:name] == :help && command_spec[:default_help]
|
23
20
|
return get_help(args, options)
|
@@ -25,12 +22,10 @@ module Thunder
|
|
25
22
|
|
26
23
|
parsed_options = process_options(args, command_spec)
|
27
24
|
options.merge!(parsed_options) if parsed_options
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if parsed_options
|
32
|
-
args << options
|
33
|
-
end
|
25
|
+
|
26
|
+
return command_spec[:subcommand].start(args, options) if command_spec[:subcommand]
|
27
|
+
|
28
|
+
args << options if parsed_options
|
34
29
|
|
35
30
|
if command_spec[:params]
|
36
31
|
min = command_spec[:params].count { |param| param.first == :req}
|
@@ -82,7 +77,7 @@ module Thunder
|
|
82
77
|
return nil unless command_spec[:options]
|
83
78
|
|
84
79
|
unless self.class.thunder[:options_processor]
|
85
|
-
require
|
80
|
+
require File.expand_path("../thunder/options/optparse", __FILE__)
|
86
81
|
self.class.thunder[:options_processor] = Thunder::OptParseAdapter
|
87
82
|
end
|
88
83
|
self.class.thunder[:options_processor].process_options(args, command_spec)
|
@@ -93,7 +88,7 @@ module Thunder
|
|
93
88
|
# @param args [<String>] the arguments list
|
94
89
|
# @param options [Hash] any included options
|
95
90
|
def get_help(args, options)
|
96
|
-
if args.
|
91
|
+
if args.empty?
|
97
92
|
puts help_list(self.class.thunder[:commands])
|
98
93
|
else
|
99
94
|
puts help_command(determine_command(args))
|
@@ -105,11 +100,7 @@ module Thunder
|
|
105
100
|
# @param commands [<Hash>] the commands to list
|
106
101
|
# @return [String] the rendered help
|
107
102
|
def help_list(commands)
|
108
|
-
|
109
|
-
require 'thunder/help/default'
|
110
|
-
self.class.thunder[:help_formatter] = Thunder::DefaultHelp
|
111
|
-
end
|
112
|
-
self.class.thunder[:help_formatter].help_list(commands)
|
103
|
+
self.class.get_help_formatter.help_list(commands)
|
113
104
|
end
|
114
105
|
|
115
106
|
# Render detailed help on a specific command
|
@@ -117,11 +108,7 @@ module Thunder
|
|
117
108
|
# @param command_spec [Hash] the command to render detailed help for
|
118
109
|
# @return [String] the rendered help
|
119
110
|
def help_command(command_spec)
|
120
|
-
|
121
|
-
require 'thunder/help/default'
|
122
|
-
self.class.thunder[:help_formatter] = Thunder::DefaultHelp
|
123
|
-
end
|
124
|
-
self.class.thunder[:help_formatter].help_command(command_spec)
|
111
|
+
self.class.get_help_formatter.help_command(command_spec)
|
125
112
|
end
|
126
113
|
|
127
114
|
public
|
@@ -152,6 +139,14 @@ module Thunder
|
|
152
139
|
}
|
153
140
|
end
|
154
141
|
|
142
|
+
def get_help_formatter
|
143
|
+
unless thunder[:help_formatter]
|
144
|
+
require File.expand_path("../thunder/help/default", __FILE__)
|
145
|
+
thunder[:help_formatter] = Thunder::DefaultHelp
|
146
|
+
end
|
147
|
+
thunder[:help_formatter]
|
148
|
+
end
|
149
|
+
|
155
150
|
# @api private
|
156
151
|
# Registers a method as a thunder task
|
157
152
|
def method_added(method)
|
data/lib/thunder/help/default.rb
CHANGED
@@ -1,92 +1,90 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class
|
4
|
-
class << self
|
1
|
+
# Provides an easy to parse help formatter
|
2
|
+
class Thunder::DefaultHelp
|
3
|
+
class << self
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
# @see Thunder#help_command(command_spec)
|
6
|
+
def help_command(command_spec)
|
7
|
+
preamble = determine_preamble
|
8
|
+
footer = ""
|
9
|
+
footer << command_spec[:description] + "\n" if command_spec[:description]
|
10
|
+
footer << command_spec[:long_description] + "\n" if command_spec[:long_description]
|
11
|
+
footer << "\n" + format_options(command_spec[:options]) if command_spec[:options]
|
12
|
+
output = <<-EOS
|
14
13
|
Usage:
|
15
14
|
#{preamble} #{command_spec[:usage]}
|
16
15
|
|
17
16
|
#{footer.strip}
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
EOS
|
18
|
+
output.rstrip
|
19
|
+
end
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
render_table(help)
|
21
|
+
# @see Thunder#help_list(commands)
|
22
|
+
def help_list(commands)
|
23
|
+
preamble = determine_preamble
|
24
|
+
help = []
|
25
|
+
commands.each do |name, command_spec|
|
26
|
+
help << short_help(preamble, command_spec)
|
30
27
|
end
|
28
|
+
render_table(help)
|
29
|
+
end
|
31
30
|
|
32
|
-
|
31
|
+
private
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
"Options:\n" + render_table(data, ": ")
|
33
|
+
# format a set of option specs
|
34
|
+
#
|
35
|
+
# @param options [<Hash>] the option specs to format
|
36
|
+
# @return [String]
|
37
|
+
def format_options(options)
|
38
|
+
data = []
|
39
|
+
options.each do |name, option_spec|
|
40
|
+
data << format_option(option_spec)
|
44
41
|
end
|
42
|
+
"Options:\n" + render_table(data, ": ")
|
43
|
+
end
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
45
|
+
# format an option
|
46
|
+
#
|
47
|
+
# @param option_spec [Hash] the option spec to format
|
48
|
+
# @return [(String, String)] the formatted option and its description
|
49
|
+
def format_option(option_spec)
|
50
|
+
usage = " -#{option_spec[:short]}, --#{option_spec[:name]}"
|
51
|
+
usage << " [#{option_spec[:name].to_s.upcase}]" unless option_spec[:type] == Boolean
|
52
|
+
return usage, option_spec[:desc]
|
53
|
+
end
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
preamble
|
55
|
+
# determine the preamble
|
56
|
+
#
|
57
|
+
# @return [String] the preamble
|
58
|
+
def determine_preamble
|
59
|
+
preamble = "#{File.basename($0)}"
|
60
|
+
ARGV.each do |arg|
|
61
|
+
break if arg == "help"
|
62
|
+
preamble << " #{arg}"
|
66
63
|
end
|
64
|
+
preamble
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
67
|
+
# render the short help string for a command
|
68
|
+
#
|
69
|
+
# @param preamble [String] the preamble
|
70
|
+
# @param command_spec [Hash]
|
71
|
+
# @return [String] the short help string for the given command
|
72
|
+
def short_help(preamble, command_spec)
|
73
|
+
return " #{preamble} #{command_spec[:usage]}", command_spec[:description]
|
74
|
+
end
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
76
|
+
# render a two-column table
|
77
|
+
#
|
78
|
+
# @param data [(String,String)]
|
79
|
+
# @param separator [String]
|
80
|
+
# @return [String] a two-column table
|
81
|
+
def render_table(data, separator = " # ")
|
82
|
+
column_width = data.group_by do |row|
|
83
|
+
row.first.size
|
84
|
+
end.max.first
|
85
|
+
"".tap do |output|
|
86
|
+
data.each do |row|
|
87
|
+
output << "%-#{column_width}s#{separator}%s\n" % row
|
90
88
|
end
|
91
89
|
end
|
92
90
|
end
|
@@ -1,43 +1,41 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
return {} unless command_spec[:options]
|
3
|
+
# Provides an adapter to the optparse library included in the Ruby std-lib
|
4
|
+
module Thunder::OptParseAdapter
|
5
|
+
# @see Thunder#process_options
|
6
|
+
def self.process_options(args, command_spec)
|
7
|
+
return {} unless command_spec[:options]
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
command_spec[:options].each do |name, option_spec|
|
13
|
-
opt = []
|
14
|
-
opt << "-#{option_spec[:short]}"
|
15
|
-
opt << if option_spec[:type] == Boolean
|
16
|
-
"--[no-]#{name}"
|
17
|
-
else
|
18
|
-
"--#{name} [#{name.to_s.upcase}]"
|
19
|
-
end
|
20
|
-
opt << option_spec[:type] unless option_spec[:type] == Boolean
|
21
|
-
opt << option_spec[:desc]
|
22
|
-
parser.on(*opt) do |value|
|
23
|
-
options[name] = value
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
command_spec[:options_processor].parse!(args)
|
28
|
-
|
29
|
-
# set default values
|
9
|
+
options = {}
|
10
|
+
command_spec[:options_processor] ||= OptionParser.new do |parser|
|
30
11
|
command_spec[:options].each do |name, option_spec|
|
31
|
-
|
32
|
-
|
33
|
-
|
12
|
+
opt = []
|
13
|
+
opt << "-#{option_spec[:short]}"
|
14
|
+
opt << if option_spec[:type] == Boolean
|
15
|
+
"--[no-]#{name}"
|
16
|
+
else
|
17
|
+
"--#{name} [#{name.to_s.upcase}]"
|
18
|
+
end
|
19
|
+
opt << option_spec[:type] unless option_spec[:type] == Boolean
|
20
|
+
opt << option_spec[:desc]
|
21
|
+
parser.on(*opt) do |value|
|
22
|
+
options[name] = value
|
23
|
+
end
|
34
24
|
end
|
25
|
+
end
|
26
|
+
command_spec[:options_processor].parse!(args)
|
35
27
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
28
|
+
# set default values
|
29
|
+
command_spec[:options].each do |name, option_spec|
|
30
|
+
next if options.has_key? name
|
31
|
+
next unless option_spec[:default]
|
32
|
+
options[name] = option_spec[:default]
|
41
33
|
end
|
34
|
+
|
35
|
+
return options
|
36
|
+
rescue OptionParser::InvalidOption => e
|
37
|
+
puts e
|
38
|
+
puts "Try --help for help."
|
39
|
+
exit 1
|
42
40
|
end
|
43
41
|
end
|
@@ -1,27 +1,25 @@
|
|
1
1
|
require 'trollop'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
command_spec[:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
opt_options[:short] = "-" + option_spec[:short]
|
3
|
+
# provides an adapter to the popular trollop option parsing library (requires trollop.rb be on the load path)
|
4
|
+
class Thunder::TrollopAdapter
|
5
|
+
# @see Thunder#process_options
|
6
|
+
def self.process_options(args, command_spec)
|
7
|
+
return nil unless command_spec[:options]
|
8
|
+
#TODO: fix the unspecified option bug
|
9
|
+
command_spec[:option_processor] ||= Trollop::Parser.new do
|
10
|
+
command_spec[:options].each do |name, option_spec|
|
11
|
+
opt_options = {}
|
12
|
+
description = option_spec[:desc] || ""
|
13
|
+
type = option_spec[:type]
|
14
|
+
type = :flag if type == Thunder::Boolean
|
15
|
+
opt_options[:type] = type
|
16
|
+
default_value = option_spec[:default]
|
17
|
+
opt_options[:default] = default_value if default_value
|
18
|
+
opt_options[:short] = "-" + option_spec[:short]
|
20
19
|
|
21
|
-
|
22
|
-
end
|
20
|
+
opt name, description, opt_options
|
23
21
|
end
|
24
|
-
command_spec[:option_processor].parse(args)
|
25
22
|
end
|
23
|
+
command_spec[:option_processor].parse(args)
|
26
24
|
end
|
27
25
|
end
|
data/lib/thunder/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thunder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-09-09 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Thunder does command line interfaces. Nothing more, nothing less.
|
15
15
|
email: steven.karas@gmail.com
|
@@ -31,7 +31,8 @@ files:
|
|
31
31
|
- bin/thunder-completion
|
32
32
|
- bin/thunder-spec
|
33
33
|
homepage: http://stevenkaras.github.com/thunder
|
34
|
-
licenses:
|
34
|
+
licenses:
|
35
|
+
- MIT
|
35
36
|
post_install_message:
|
36
37
|
rdoc_options: []
|
37
38
|
require_paths:
|
@@ -50,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
51
|
version: '0'
|
51
52
|
requirements: []
|
52
53
|
rubyforge_project:
|
53
|
-
rubygems_version: 1.8.
|
54
|
+
rubygems_version: 1.8.25
|
54
55
|
signing_key:
|
55
56
|
specification_version: 3
|
56
57
|
summary: Thunder makes command lines apps easy!
|