thunder 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,12 @@
1
+ v0.4.2
2
+ - fixed boolean flags in default options processor
3
+ - default help formatter now strips whitespace properly
4
+ - all options now have optional arguments
5
+ + default values are now set properly
6
+ + added trollop adapter for option processing
7
+ + improved documentation and help formatting for options
8
+ - fixed handling of ARGV and subcommands
9
+
1
10
  v0.4.1
2
11
  - fixed fatal options processing bug
3
12
 
data/README.md CHANGED
@@ -2,10 +2,19 @@ Thunder
2
2
  =======
3
3
  Ruby gem for quick and easy command line interfaces
4
4
 
5
+ Usage
6
+ -----
7
+
8
+ gem install thunder
9
+
10
+ see 'sample' for a quick overview of all features
11
+
5
12
  Philosophy
6
13
  ----------
7
14
  The command line is the most basic interface we have with a computer. It makes sense that we should invest as much time and effort as possible to build tools to work with the command line, and tie into code we write as quickly as possible. Sadly, this has not taken place as much as one would expect. This library steps up to bridge the admittedly small gap between your standard shell and ruby code.
8
15
 
16
+ While this is possible, and even easy using existing libraries, they either violate the principle of locality, or provide too many services.
17
+
9
18
  The overarching philosophy here is that a library should do one or two things, and do them extremely well.
10
19
 
11
20
  Goals
@@ -16,7 +25,7 @@ Phase 1: call a method from the command line
16
25
  Phase 2: provide options and arguments
17
26
  Phase 3: provide help/banner formatter
18
27
  Phase 4: provide yardoc integration
19
- Phase 5: provide a bash-completion script.
28
+ Phase 5: provide a bash-completion script
20
29
  Phase 6: ???
21
30
  Phase 7: Profit!
22
31
 
data/lib/thunder.rb CHANGED
@@ -12,7 +12,7 @@ module Thunder
12
12
  #
13
13
  # @param args [<String>] the command line arguments [ARGV]
14
14
  # @param options [{Symbol => *}] the default options to use [{}]
15
- def start(args=ARGV, options={})
15
+ def start(args=ARGV.dup, options={})
16
16
  command_spec = determine_command(args)
17
17
 
18
18
  unless command_spec
@@ -56,7 +56,7 @@ module Thunder
56
56
  #
57
57
  # @param args [<String>] the argument list to process
58
58
  # @param command_spec [Hash] the command specification to use
59
- # @return [{Symbol => *}] the options
59
+ # @return [{Symbol => *},nil] the options
60
60
  def process_options(args, command_spec)
61
61
  return nil unless command_spec[:options]
62
62
 
@@ -119,6 +119,7 @@ module Thunder
119
119
  name: :help,
120
120
  usage: "help [COMMAND]",
121
121
  description: "list available commands or describe a specific command",
122
+ long_description: nil,
122
123
  options: nil,
123
124
  default_help: true
124
125
  },
@@ -183,6 +184,7 @@ module Thunder
183
184
  # @option options :short [String] the short version of the option [the first letter of the option name]
184
185
  # @option options :type [Class] the datatype of this option [Boolean]
185
186
  # @option options :desc [String] the long description of this option [""]
187
+ # @option options :default [*] the default value
186
188
  #
187
189
  # @example
188
190
  # option :output_file, type: String
@@ -195,18 +197,18 @@ module Thunder
195
197
  options[:name] = name
196
198
  options[:short] ||= name[0]
197
199
  options[:type] ||= Boolean
198
- options[:description] ||= ""
200
+ options[:desc] ||= ""
199
201
  thunder[:options] ||= {}
200
202
  thunder[:options][name] = options
201
203
  end
202
204
 
203
205
  # Define a subcommand
204
206
  #
205
- # @param command [String] the command that transfers processing to the provided handler
207
+ # @param command [Symbol,String] the command that transfers processing to the provided handler
206
208
  # @param handler [Thunder] the handler that processes the request
207
209
  def subcommand(command, handler)
208
- method_added(command)
209
- thunder[:commands][command][:subcommand] = handler
210
+ method_added(command.to_sym)
211
+ thunder[:commands][command.to_sym][:subcommand] = handler
210
212
  end
211
213
 
212
214
  end
@@ -7,14 +7,17 @@ module Thunder
7
7
  def help_command(command_spec)
8
8
  preamble = determine_preamble
9
9
  #TODO: add options to output
10
+ footer = ""
11
+ footer << command_spec[:description] + "\n" if command_spec[:description]
12
+ footer << command_spec[:long_description] + "\n" if command_spec[:long_description]
13
+ footer << "\n" + format_options(command_spec[:options]) if command_spec[:options]
10
14
  output = <<-EOS
11
15
  Usage:
12
16
  #{preamble} #{command_spec[:usage]}
13
17
 
14
- #{command_spec[:description]}
15
- #{command_spec[:long_description]}
18
+ #{footer.strip}
16
19
  EOS
17
- output.chomp
20
+ output.rstrip
18
21
  end
19
22
 
20
23
  # @see Thunder#help_list(commands)
@@ -28,6 +31,29 @@ Usage:
28
31
  end
29
32
 
30
33
  private
34
+
35
+ # format a set of option specs
36
+ #
37
+ # @param options [<Hash>] the option specs to format
38
+ # @return [String]
39
+ def format_options(options)
40
+ data = []
41
+ options.each do |name, option_spec|
42
+ data << format_option(option_spec)
43
+ end
44
+ "Options:\n" + render_table(data, ": ")
45
+ end
46
+
47
+ # format an option
48
+ #
49
+ # @param option_spec [Hash] the option spec to format
50
+ # @return [(String, String)] the formatted option and its description
51
+ def format_option(option_spec)
52
+ usage = " -#{option_spec[:short]}, --#{option_spec[:name]}"
53
+ usage << " [#{option_spec[:name].to_s.upcase}]" unless option_spec[:type] == Boolean
54
+ return usage, option_spec[:desc]
55
+ end
56
+
31
57
  # determine the preamble
32
58
  #
33
59
  # @return [String] the preamble
@@ -54,13 +80,13 @@ Usage:
54
80
  # @param data [(String,String)]
55
81
  # @param separator [String]
56
82
  # @return [String] a two-column table
57
- def render_table(data, separator = "#")
83
+ def render_table(data, separator = " # ")
58
84
  column_width = data.group_by do |data|
59
85
  data.first.size
60
86
  end.max.first
61
87
  "".tap do |output|
62
88
  data.each do |line|
63
- output << "%-#{column_width}s #{separator} %s\n" % line
89
+ output << "%-#{column_width}s#{separator}%s\n" % line
64
90
  end
65
91
  end
66
92
  end
@@ -1,4 +1,4 @@
1
- require "optparse"
1
+ require 'optparse'
2
2
 
3
3
  module Thunder
4
4
  # Provides an adapter to the optparse library included in the Ruby std-lib
@@ -13,12 +13,12 @@ module Thunder
13
13
  opt = []
14
14
  opt << "-#{option_spec[:short]}"
15
15
  opt << if option_spec[:type] == Boolean
16
- "--[no]#{name}"
16
+ "--[no-]#{name}"
17
17
  else
18
- "--#{name} OPT"
18
+ "--#{name} [#{name.to_s.upcase}]"
19
19
  end
20
20
  opt << option_spec[:type] unless option_spec[:type] == Boolean
21
- opt << option_spec[:description]
21
+ opt << option_spec[:desc]
22
22
  parser.on(*opt) do |value|
23
23
  options[name] = value
24
24
  end
@@ -26,7 +26,18 @@ module Thunder
26
26
  end
27
27
  command_spec[:options_processor].parse!(args)
28
28
 
29
+ # set default values
30
+ command_spec[:options].each do |name, option_spec|
31
+ next if options.has_key? name
32
+ next unless option_spec[:default]
33
+ options[name] = option_spec[:default]
34
+ end
35
+
29
36
  return options
37
+ rescue OptionParser::InvalidOption => e
38
+ puts e
39
+ puts "Try --help for help."
40
+ exit 1
30
41
  end
31
42
  end
32
43
  end
@@ -0,0 +1,27 @@
1
+ require 'trollop'
2
+
3
+ module Thunder
4
+ # provides an adapter to the popular trollop option parsing library (requires trollop.rb be on the load path)
5
+ class TrollopAdapter
6
+ # @see Thunder#process_options
7
+ def self.process_options(args, command_spec)
8
+ return nil unless command_spec[:options]
9
+ #TODO: fix the unspecified option bug
10
+ command_spec[:option_processor] ||= Trollop::Parser.new do
11
+ command_spec[:options].each do |name, option_spec|
12
+ opt_options = {}
13
+ description = option_spec[:desc] || ""
14
+ type = option_spec[:type]
15
+ type = :flag if type == Thunder::Boolean
16
+ opt_options[:type] = type
17
+ default_value = option_spec[:default]
18
+ opt_options[:default] = default_value if default_value
19
+ opt_options[:short] = "-" + option_spec[:short]
20
+
21
+ opt name, description, opt_options
22
+ end
23
+ end
24
+ command_spec[:option_processor].parse(args)
25
+ end
26
+ end
27
+ end
@@ -1,4 +1,4 @@
1
1
  module Thunder
2
2
  # Version string for gemspec
3
- VERSION = "0.4.1"
3
+ VERSION = "0.4.2"
4
4
  end
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.4.1
4
+ version: 0.4.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: 2012-08-04 00:00:00.000000000 Z
12
+ date: 2012-08-05 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Thor does everything and the kitchen sink. Thunder only does command
15
15
  line interfaces.
@@ -20,6 +20,7 @@ extra_rdoc_files: []
20
20
  files:
21
21
  - lib/thunder/help/default.rb
22
22
  - lib/thunder/options/optparse.rb
23
+ - lib/thunder/options/trollop.rb
23
24
  - lib/thunder/version.rb
24
25
  - lib/thunder.rb
25
26
  - spec/spec_thunder.rb