thunder 0.6.1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/thunder.png)](http://badge.fury.io/rb/thunder)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/stevenkaras/thunder.png)](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!
|