mercenary 0.2.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3ab95f854272a3615464fc0189bb7dd05de87115
4
- data.tar.gz: 5cb99b4246ee7194d1c69a142ef2b8ff8f1e3b3a
3
+ metadata.gz: d9ebb7e735aa1147cbcc69420fa3a934830c0415
4
+ data.tar.gz: 120e555e1d05e2af4e674b42cd9143195310b92e
5
5
  SHA512:
6
- metadata.gz: d557c2b7ec5b68148a50aded7101043f5de8f8e2024faa76fd745df535fb8c06ade969c9ebe3caa0f9345d777eedef954645e59777e4ac7767b638d7e924ebec
7
- data.tar.gz: 75495874c6ee7cd0c287005f4ef4ce2e4089ff07557014812f516a80805c04d7d84a6b7a021b97f8080721004bc0d7220c3e2376542e90728cb22bdac818524c
6
+ metadata.gz: becf09d037cb3f6475239595c42deba5c89791ccc13f5d2c622d1a88769d91e89c7da2685f1c238f2e41d0308b81cd81679f7ac7352fffa93d36cf7d989a7975
7
+ data.tar.gz: 2ca3a69a6039ab31343002957dec0c8753181c17817d3d6b59afaa7dc6186e3d78f501979ffae98e3ecb4ba730bdbd46e4d8d5974f653f25fedf603fc9c75cde
data/.travis.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.8.7
4
3
  - 1.9.3
5
4
  - 2.0.0
5
+ - 2.1.0
6
6
  script: "./script/cibuild"
7
7
  notifications:
8
8
  email:
data/History.markdown CHANGED
@@ -8,6 +8,25 @@
8
8
 
9
9
  ### Development Fixes
10
10
 
11
+ ## 0.3.0 / 2014-02-20
12
+
13
+ ### Major Enhancements
14
+
15
+ * Officially drop 1.8.7 support (#14)
16
+ * Allow Commands to set their own versions (#17)
17
+ * Show subcommands, options and usage in help and attach to all commands (#18)
18
+ * Add `-t, --trace` to allow full exception backtrace to print, otherwise print
19
+ just the error message (#19)
20
+
21
+ ### Minor Enhancements
22
+
23
+ * Logging state is maintained throughout process (#12)
24
+ * Tidy up Command#logger output (#21)
25
+
26
+ ### Development Fixes
27
+
28
+ * Added specs for `Program` (#13)
29
+
11
30
  ## 0.2.1 / 2013-12-25
12
31
 
13
32
  ### Bug Fixes
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Parker Moore
1
+ Copyright (c) 2013-2014 Parker Moore
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -18,6 +18,8 @@ Or install it yourself as:
18
18
 
19
19
  $ gem install mercenary
20
20
 
21
+ **Note: Mercenary may not work with Ruby < 1.9.3.**
22
+
21
23
  ## Usage
22
24
 
23
25
  ```ruby
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib })
4
+
5
+ require "mercenary"
6
+
7
+ # This example sets the logging mode of mercenary to
8
+ # debug. Logging messages from "p.logger.debug" will
9
+ # be output to STDOUT.
10
+
11
+ Mercenary.program(:help_dialogue) do |p|
12
+
13
+ p.version "2.0.1"
14
+ p.description 'An example of the help dialogue in Mercenary'
15
+ p.syntax 'help_dialogue <subcommand>'
16
+
17
+ p.command(:some_subcommand) do |c|
18
+ c.version '1.4.2'
19
+ c.syntax 'some_subcommand <subcommand> [options]'
20
+ c.description 'Some subcommand to do something'
21
+ c.option 'an_option', '-o', '--option', 'Some option'
22
+
23
+ c.command(:yet_another_sub) do |f|
24
+ f.syntax 'yet_another_sub [options]'
25
+ f.description 'Do amazing things'
26
+ f.option 'blah', '-b', '--blah', 'Trigger blah flag'
27
+ f.option 'heh', '-H ARG', '--heh ARG', 'Give a heh'
28
+
29
+ f.action do |args, options|
30
+ print "Args: "
31
+ p args
32
+ print "Opts: "
33
+ p options
34
+ end
35
+ end
36
+ end
37
+
38
+ p.command(:another_subcommand) do |c|
39
+ c.syntax 'another_subcommand <subcommand> [options]'
40
+ c.description 'Another subcommand to do something different.'
41
+ c.option 'an_option', '-O', '--option', 'Some option'
42
+ c.option 'another_options', '--pluginzzz', 'Set where the plugins should be found from'
43
+ end
44
+
45
+ end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib })
4
+
5
+ require "mercenary"
6
+
7
+ # This example sets the logging mode of mercenary to
8
+ # debug. Logging messages from "p.logger.debug" will
9
+ # be output to STDOUT.
10
+
11
+ Mercenary.program(:logger_output) do |p|
12
+
13
+ p.version "5.2.6"
14
+ p.description 'An example of turning on logging for Mercenary.'
15
+ p.syntax 'logger_output'
16
+
17
+
18
+ p.logger.info "The default log level is INFO. So this will output."
19
+ p.logger.debug "Since DEBUG is below INFO, this will not output."
20
+
21
+ p.logger(Logger::DEBUG)
22
+ p.logger.debug "Logger level now set to DEBUG. So everything will output."
23
+
24
+ p.logger.debug "Example of DEBUG level message."
25
+ p.logger.info "Example of INFO level message."
26
+ p.logger.warn "Example of WARN level message."
27
+ p.logger.error "Example of ERROR level message."
28
+ p.logger.fatal "Example of FATAL level message."
29
+ p.logger.unknown "Example of UNKNOWN level message."
30
+
31
+ p.action do |args, options|
32
+
33
+ p.logger(Logger::INFO)
34
+ p.logger.debug "Logger level back to INFO. This line will not output."
35
+ p.logger.info "This INFO message will output."
36
+
37
+ end
38
+
39
+ end
data/examples/trace.rb ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib })
4
+
5
+ require "mercenary"
6
+
7
+ # This example sets the logging mode of mercenary to
8
+ # debug. Logging messages from "p.logger.debug" will
9
+ # be output to STDOUT.
10
+
11
+ Mercenary.program(:trace) do |p|
12
+
13
+ p.version "2.0.1"
14
+ p.description 'An example of traces in Mercenary'
15
+ p.syntax 'trace <subcommand>'
16
+
17
+ p.action do |_, _|
18
+ raise ArgumentError.new("YOU DID SOMETHING TERRIBLE YOU BUFFOON")
19
+ end
20
+
21
+ end
data/lib/mercenary.rb CHANGED
@@ -6,8 +6,10 @@ require "optparse"
6
6
  require "logger"
7
7
 
8
8
  module Mercenary
9
- autoload :Command, "mercenary/command"
10
- autoload :Program, "mercenary/program"
9
+ autoload :Command, "mercenary/command"
10
+ autoload :Option, "mercenary/option"
11
+ autoload :Presenter, "mercenary/presenter"
12
+ autoload :Program, "mercenary/program"
11
13
 
12
14
  # Public: Instantiate a new program and execute.
13
15
  #
@@ -8,6 +8,7 @@ module Mercenary
8
8
  attr_accessor :actions
9
9
  attr_reader :map
10
10
  attr_accessor :parent
11
+ attr_reader :trace
11
12
 
12
13
  # Public: Creates a new Command
13
14
  #
@@ -17,12 +18,23 @@ module Mercenary
17
18
  #
18
19
  # Returns nothing
19
20
  def initialize(name, parent = nil)
20
- @name = name
21
- @options = []
22
- @commands = {}
23
- @actions = []
24
- @map = {}
25
- @parent = parent
21
+ @name = name
22
+ @options = []
23
+ @commands = {}
24
+ @actions = []
25
+ @map = {}
26
+ @parent = parent
27
+ @trace = false
28
+ end
29
+
30
+ # Public: Sets or gets the command version
31
+ #
32
+ # version - the command version (optional)
33
+ #
34
+ # Returns the version and sets it if an argument is non-nil
35
+ def version(version = nil)
36
+ @version = version if version
37
+ @version
26
38
  end
27
39
 
28
40
  # Public: Sets or gets the syntax string
@@ -32,7 +44,12 @@ module Mercenary
32
44
  # Returns the syntax string and sets it if an argument is present
33
45
  def syntax(syntax = nil)
34
46
  @syntax = syntax if syntax
35
- @syntax
47
+ syntax_list = []
48
+ if parent
49
+ syntax_list << parent.syntax.to_s.gsub(/<[\w\s-]+>/, '').gsub(/\[[\w\s-]+\]/, '').strip
50
+ end
51
+ syntax_list << (@syntax || name.to_s)
52
+ syntax_list.join(" ")
36
53
  end
37
54
 
38
55
  # Public: Sets or gets the command description
@@ -71,8 +88,9 @@ module Mercenary
71
88
  #
72
89
  # Returns nothing
73
90
  def option(sym, *options)
74
- @options << options
75
- @map[options[0]] = sym
91
+ new_option = Option.new(sym, options)
92
+ @options << new_option
93
+ @map[new_option.hash] = sym
76
94
  end
77
95
 
78
96
  # Public: Adds a subcommand
@@ -112,15 +130,16 @@ module Mercenary
112
130
  # level - the logger level (a Logger constant, see docs for more info)
113
131
  #
114
132
  # Returns the instance of Logger
115
- def logger(level = Logger::INFO)
133
+ def logger(level = nil)
116
134
  unless @logger
117
135
  @logger = Logger.new(STDOUT)
136
+ @logger.level = level || Logger::INFO
118
137
  @logger.formatter = proc do |severity, datetime, progname, msg|
119
- "#{ident} (#{severity}): #{msg}\n"
138
+ "#{identity} | " << "#{severity.downcase.capitalize}:".ljust(7) << " #{msg}\n"
120
139
  end
121
140
  end
122
141
 
123
- @logger.level = level
142
+ @logger.level = level unless level.nil?
124
143
  @logger
125
144
  end
126
145
 
@@ -134,6 +153,7 @@ module Mercenary
134
153
  def go(argv, opts, config)
135
154
  opts.banner = "Usage: #{syntax}"
136
155
  process_options(opts, config)
156
+ add_default_options(opts)
137
157
 
138
158
  if argv[0] && cmd = commands[argv[0].to_sym]
139
159
  logger.debug "Found subcommand '#{cmd.name}'"
@@ -153,13 +173,36 @@ module Mercenary
153
173
  #
154
174
  # Returns nothing
155
175
  def process_options(opts, config)
156
- options.each do |o|
157
- opts.on(*o) do |x|
158
- config[map[o[0]]] = x
176
+ options.each do |option|
177
+ opts.on(*option.for_option_parser) do |x|
178
+ config[map[option.hash]] = x
159
179
  end
160
180
  end
161
181
  end
162
182
 
183
+ # Public: Add version and help options to the command
184
+ #
185
+ # opts - instance of OptionParser
186
+ #
187
+ # Returns nothing
188
+ def add_default_options(opts)
189
+ option 'show_help', '-h', '--help', 'Show this message'
190
+ option 'show_version', '-v', '--version', 'Print the name and version'
191
+ opts.on("-v", "--version", "Print the version") do
192
+ puts "#{name} #{version}"
193
+ abort
194
+ end
195
+
196
+ opts.on('-t', '--trace', 'Show full backtrace if an error occurs') do
197
+ @trace = true
198
+ end
199
+
200
+ opts.on_tail("-h", "--help", "Show this message") do
201
+ puts self
202
+ exit
203
+ end
204
+ end
205
+
163
206
  # Public: Execute all actions given the inputted args and options
164
207
  #
165
208
  # argv - (optional) command-line args (sans opts)
@@ -188,19 +231,39 @@ module Mercenary
188
231
  #
189
232
  # Returns a string which identifies this command
190
233
  def ident
191
- "<Command name=#{name}>"
234
+ "<Command name=#{identity}>"
235
+ end
236
+
237
+ # Public: Get the full identity (name & version) of this command
238
+ #
239
+ # Returns a string containing the name and version if it exists
240
+ def identity
241
+ "#{full_name} #{version if version}".strip
242
+ end
243
+
244
+ # Public: Get the name of the current command plus that of
245
+ # its parent commands
246
+ #
247
+ # Returns the full name of the command
248
+ def full_name
249
+ the_name = []
250
+ the_name << parent.full_name if parent && parent.full_name
251
+ the_name << name
252
+ the_name.join(" ")
253
+ end
254
+
255
+ # Public: Build a string containing a summary of the command
256
+ #
257
+ # Returns a one-line summary of the command.
258
+ def summarize
259
+ " #{name.to_s.ljust(20)} #{description}"
192
260
  end
193
261
 
194
262
  # Public: Build a string containing the command name, options and any subcommands
195
263
  #
196
264
  # Returns the string identifying this command, its options and its subcommands
197
265
  def to_s
198
- msg = ''
199
- msg += "Command: #{name}\n"
200
- options.each { |o| msg += " " + o.inspect + "\n"}
201
- msg += "\n"
202
- commands.each { |k, v| msg += commands[k].inspect }
203
- msg
266
+ Presenter.new(self).print_command
204
267
  end
205
268
  end
206
269
  end
@@ -0,0 +1,80 @@
1
+ module Mercenary
2
+ class Option
3
+ attr_reader :config_key, :description, :switches
4
+
5
+ # Public: Create a new Option
6
+ #
7
+ # config_key - the key in the config hash to which the value of this option will map
8
+ # info - an array containing first the switches, then a description of the option
9
+ #
10
+ # Returns nothing
11
+ def initialize(config_key, info)
12
+ @config_key = config_key
13
+ @description = info.last unless info.last.start_with?("-")
14
+ set_switches(info.take(info.size - [@description].reject(&:nil?).size))
15
+ end
16
+
17
+ # Public: Fetch the array containing the info OptionParser is interested in
18
+ #
19
+ # Returns the array which OptionParser#on wants
20
+ def for_option_parser
21
+ [switches.reject(&:empty?), description].reject{ |o| o.nil? || o.empty? }.flatten
22
+ end
23
+
24
+ # Public: Build a string representation of this option including the
25
+ # switches and description
26
+ #
27
+ # Returns a string representation of this option
28
+ def to_s
29
+ "#{formatted_switches} #{description}"
30
+ end
31
+
32
+ # Public: Build a beautifully-formatted string representation of the switches
33
+ #
34
+ # Returns a formatted string representation of the switches
35
+ def formatted_switches
36
+ [
37
+ switches.first.rjust(10),
38
+ switches.last.ljust(13)
39
+ ].join(", ").gsub(/ , /, ' ').gsub(/, /, ' ')
40
+ end
41
+
42
+ # Public: Hash based on the hash value of instance variables
43
+ #
44
+ # Returns a Fixnum which is unique to this Option based on the instance variables
45
+ def hash
46
+ instance_variables.map do |var|
47
+ instance_variable_get(var).hash
48
+ end.reduce(:&)
49
+ end
50
+
51
+ # Public: Check equivalence of two Options based on equivalence of their
52
+ # instance variables
53
+ #
54
+ # Returns true if all the instance variables are equal, false otherwise
55
+ def eql?(other)
56
+ return false unless self.class.eql?(other.class)
57
+ instance_variables.map do |var|
58
+ instance_variable_get(var).eql?(other.instance_variable_get(var))
59
+ end.all?
60
+ end
61
+
62
+ private
63
+
64
+ # Private: Set the full switches array, ensuring the first element is the
65
+ # short switch and the second element is the long switch
66
+ #
67
+ # Returns the corrected switches array
68
+ def set_switches(switches)
69
+ if switches.size < 2
70
+ if switches.first.start_with?("--")
71
+ switches.unshift ""
72
+ else
73
+ switches << ""
74
+ end
75
+ end
76
+ @switches = switches
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,80 @@
1
+ module Mercenary
2
+ class Presenter
3
+ attr_accessor :command
4
+
5
+ # Public: Make a new Presenter
6
+ #
7
+ # command - a Mercenary::Command to present
8
+ #
9
+ # Returns nothing
10
+ def initialize(command)
11
+ @command = command
12
+ end
13
+
14
+ # Public: Builds a string representation of the command usage
15
+ #
16
+ # Returns the string representation of the command usage
17
+ def usage_presentation
18
+ " #{command.syntax}"
19
+ end
20
+
21
+ # Public: Builds a string representation of the options
22
+ #
23
+ # Returns the string representation of the options
24
+ def options_presentation
25
+ return nil unless command.options.size > 0
26
+ command.options.map(&:to_s).join("\n")
27
+ end
28
+
29
+ # Public: Builds a string representation of the subcommands
30
+ #
31
+ # Returns the string representation of the subcommands
32
+ def subcommands_presentation
33
+ return nil unless command.commands.size > 0
34
+ command.commands.values.map(&:summarize).join("\n")
35
+ end
36
+
37
+ # Public: Builds the command header, including the command identity and description
38
+ #
39
+ # Returns the command header as a String
40
+ def command_header
41
+ header = "#{command.identity}"
42
+ header << " -- #{command.description}" if command.description
43
+ header
44
+ end
45
+
46
+ # Public: Builds a string representation of the whole command
47
+ #
48
+ # Returns the string representation of the whole command
49
+ def command_presentation
50
+ msg = []
51
+ msg << command_header
52
+ msg << "Usage:"
53
+ msg << usage_presentation
54
+
55
+ if opts = options_presentation
56
+ msg << "Options:\n#{opts}"
57
+ end
58
+ if subcommands = subcommands_presentation
59
+ msg << "Subcommands:\n#{subcommands_presentation}"
60
+ end
61
+ msg.join("\n\n")
62
+ end
63
+
64
+ # Public: Turn a print_* into a *_presentation or freak out
65
+ #
66
+ # meth - the method being called
67
+ # args - an array of arguments passed to the missing method
68
+ # block - the block passed to the missing method
69
+ #
70
+ # Returns the value of whatever function is called
71
+ def method_missing(meth, *args, &block)
72
+ if meth.to_s =~ /^print_(.+)$/
73
+ send("#{$1.downcase}_presentation")
74
+ else
75
+ super # You *must* call super if you don't handle the method,
76
+ # otherwise you'll mess up Ruby's method lookup.
77
+ end
78
+ end
79
+ end
80
+ end
@@ -13,19 +13,9 @@ module Mercenary
13
13
  super(name)
14
14
  end
15
15
 
16
- # Public: Sets or gets the program version
17
- #
18
- # version - the program version (optional)
19
- #
20
- # Returns the version and sets it if an argument is present
21
- def version(version = nil)
22
- @version = version if version
23
- @version
24
- end
25
-
26
16
  # Public: Run the program
27
17
  #
28
- # argv - an array of string args (usually ARGV)
18
+ # argv - an array of string args (usually ARGV)
29
19
  #
30
20
  # Returns nothing
31
21
  def go(argv)
@@ -35,18 +25,22 @@ module Mercenary
35
25
 
36
26
  @optparse = OptionParser.new do |opts|
37
27
  cmd = super(argv, opts, @config)
38
-
39
- opts.on('-v', '--version', 'Print the version') do
40
- puts "#{name} #{version}"
41
- abort
42
- end
43
28
  end
44
29
 
45
30
  @optparse.parse!(argv)
46
31
 
47
32
  logger.debug("Parsed config: #{@config.inspect}")
48
33
 
49
- cmd.execute(argv, @config)
34
+ begin
35
+ cmd.execute(argv, @config)
36
+ rescue => e
37
+ if cmd.trace
38
+ raise e
39
+ else
40
+ logger.error e.message
41
+ abort
42
+ end
43
+ end
50
44
  end
51
45
  end
52
46
  end
@@ -1,3 +1,3 @@
1
1
  module Mercenary
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
data/script/cibuild CHANGED
@@ -1,3 +1,6 @@
1
1
  #! /bin/sh
2
2
 
3
+ set -ex
4
+
3
5
  bundle exec rspec
6
+ ./script/examples
data/script/console ADDED
@@ -0,0 +1,3 @@
1
+ #! /bin/bash
2
+
3
+ irb -r./lib/mercenary.rb
data/script/examples ADDED
@@ -0,0 +1,17 @@
1
+ #! /bin/bash
2
+
3
+ set -e
4
+
5
+ function run () {
6
+ echo "+ ruby ./examples/$@"
7
+ ruby -e "puts '=' * 79"
8
+ ruby ./examples/$@
9
+ ruby -e "puts '=' * 79"
10
+ }
11
+
12
+ run logging.rb
13
+ run help_dialogue.rb -h
14
+ run help_dialogue.rb some_subcommand -h
15
+ run help_dialogue.rb another_subcommand -h
16
+ run help_dialogue.rb some_subcommand yet_another_sub -h
17
+ run help_dialogue.rb some_subcommand yet_another_sub -b
data/spec/command_spec.rb CHANGED
@@ -35,6 +35,12 @@ describe(Mercenary::Command) do
35
35
  expect(add_sub.call(command).parent).to eq(command)
36
36
  end
37
37
 
38
+ it "can set its version" do
39
+ version = "1.4.2"
40
+ command.version version
41
+ expect(command.version).to eq(version)
42
+ end
43
+
38
44
  it "can set its syntax" do
39
45
  syntax_string = "my_name [options]"
40
46
  cmd = described_class.new(:my_name)
@@ -50,10 +56,20 @@ describe(Mercenary::Command) do
50
56
 
51
57
  it "can set its options" do
52
58
  name = "show_drafts"
53
- opt = ['--drafts', 'Render posts in the _drafts folder']
54
- command.option name, *opt
55
- expect(command.options).to eq([opt])
56
- expect(command.map).to include({opt.first => name})
59
+ opts = ['--drafts', 'Render posts in the _drafts folder']
60
+ option = Mercenary::Option.new(name, opts)
61
+ command.option name, *opts
62
+ expect(command.options).to eql([option])
63
+ expect(command.map).to include({option.hash => name})
64
+ end
65
+
66
+ it "knows its full name" do
67
+ expect(command_with_parent.full_name).to eql("my_parent i_have_parent")
68
+ end
69
+
70
+ it "knows its identity" do
71
+ command_with_parent.version '1.8.7'
72
+ expect(command_with_parent.identity).to eql("my_parent i_have_parent 1.8.7")
57
73
  end
58
74
 
59
75
  it "raises an ArgumentError if I specify a default_command that isn't there" do
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe(Mercenary::Option) do
4
+ let(:config_key) { "largo" }
5
+ let(:description) { "This is a description" }
6
+ let(:switches) { ['-l', '--largo'] }
7
+ let(:option) { described_class.new(config_key, [switches, description].flatten.reject(&:nil?)) }
8
+
9
+ it "knows its config key" do
10
+ expect(option.config_key).to eql(config_key)
11
+ end
12
+
13
+ it "knows its description" do
14
+ expect(option.description).to eql(description)
15
+ end
16
+
17
+ it "knows its switches" do
18
+ expect(option.switches).to eql(switches)
19
+ end
20
+
21
+ it "knows how to present itself" do
22
+ expect(option.to_s).to eql(" -l, --largo #{description}")
23
+ end
24
+
25
+ it "has an OptionParser representation" do
26
+ expect(option.for_option_parser).to eql([switches, description].flatten)
27
+ end
28
+
29
+ it "compares itself with other options well" do
30
+ new_option = described_class.new(config_key, ['-l', '--largo', description])
31
+ expect(option.eql?(new_option)).to be_true
32
+ expect(option.hash.eql?(new_option.hash)).to be_true
33
+ end
34
+
35
+ it "has a custom #hash" do
36
+ expect(option.hash.to_s).to match(/\d+/)
37
+ end
38
+
39
+ context "with just the long switch" do
40
+ let(:switches) { ['--largo'] }
41
+
42
+ it "adds an empty string in place of the short switch" do
43
+ expect(option.switches).to eql(['', '--largo'])
44
+ end
45
+
46
+ it "sets its description properly" do
47
+ expect(option.description).to eql(description)
48
+ end
49
+
50
+ it "knows how to present the switch" do
51
+ expect(option.formatted_switches).to eql(" --largo ")
52
+ end
53
+ end
54
+
55
+ context "with just the short switch" do
56
+ let(:switches) { ['-l'] }
57
+
58
+ it "adds an empty string in place of the long switch" do
59
+ expect(option.switches).to eql(['-l', ''])
60
+ end
61
+
62
+ it "sets its description properly" do
63
+ expect(option.description).to eql(description)
64
+ end
65
+
66
+ it "knows how to present the switch" do
67
+ expect(option.formatted_switches).to eql(" -l ")
68
+ end
69
+ end
70
+
71
+ context "without a description" do
72
+ let(:description) { nil }
73
+
74
+ it "knows there is no description" do
75
+ expect(option.description).to be_nil
76
+ end
77
+
78
+ it "knows both inputs are switches" do
79
+ expect(option.switches).to eql(switches)
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe(Mercenary::Presenter) do
4
+ let(:supercommand) { Mercenary::Command.new(:script_name) }
5
+ let(:command) { Mercenary::Command.new(:subcommand, supercommand) }
6
+ let(:presenter) { described_class.new(command) }
7
+
8
+ before(:each) do
9
+ command.version '1.4.2'
10
+ command.description 'Do all the things.'
11
+ command.option 'one', '-1', '--one', 'The first option'
12
+ command.option 'two', '-2', '--two', 'The second option'
13
+ supercommand.commands[command.name] = command
14
+ end
15
+
16
+ it "knows how to present the command" do
17
+ expect(presenter.command_presentation).to eql("script_name subcommand 1.4.2 -- Do all the things.\n\nUsage:\n\n script_name subcommand\n\nOptions:\n -1, --one The first option\n -2, --two The second option")
18
+ end
19
+
20
+ it "knows how to present the subcommands" do
21
+ expect(described_class.new(supercommand).subcommands_presentation).to eql(" subcommand Do all the things.")
22
+ end
23
+
24
+ it "knows how to present the usage" do
25
+ expect(presenter.usage_presentation).to eql(" script_name subcommand")
26
+ end
27
+
28
+ it "knows how to present the options" do
29
+ expect(presenter.options_presentation).to eql(" -1, --one The first option\n -2, --two The second option")
30
+ end
31
+
32
+ it "allows you to say print_* instead of *_presentation" do
33
+ expect(presenter.print_usage).to eql(presenter.usage_presentation)
34
+ expect(presenter.print_subcommands).to eql(presenter.subcommands_presentation)
35
+ expect(presenter.print_options).to eql(presenter.options_presentation)
36
+ expect(presenter.print_command).to eql(presenter.command_presentation)
37
+ end
38
+ end
data/spec/program_spec.rb CHANGED
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ describe(Mercenary::Program) do
4
+
5
+ context "a basic program" do
6
+ let(:program) { Mercenary::Program.new(:my_name) }
7
+
8
+ it "can be created with just a name" do
9
+ expect(program.name).to eql(:my_name)
10
+ end
11
+
12
+ it "can set its version" do
13
+ version = Mercenary::VERSION
14
+ program.version version
15
+ expect(program.version).to eq(version)
16
+ end
17
+ end
18
+
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mercenary
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Preston-Werner
@@ -9,48 +9,48 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-26 00:00:00.000000000 Z
12
+ date: 2014-02-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ~>
19
19
  - !ruby/object:Gem::Version
20
20
  version: '1.3'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ~>
26
26
  - !ruby/object:Gem::Version
27
27
  version: '1.3'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
32
+ - - '>='
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ">="
39
+ - - '>='
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rspec
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ~>
47
47
  - !ruby/object:Gem::Version
48
48
  version: '2.14'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - "~>"
53
+ - - ~>
54
54
  - !ruby/object:Gem::Version
55
55
  version: '2.14'
56
56
  description: Lightweight and flexible library for writing command-line apps in Ruby.
@@ -61,22 +61,31 @@ executables: []
61
61
  extensions: []
62
62
  extra_rdoc_files: []
63
63
  files:
64
- - ".gitignore"
65
- - ".rspec"
66
- - ".travis.yml"
64
+ - .gitignore
65
+ - .rspec
66
+ - .travis.yml
67
67
  - Gemfile
68
68
  - History.markdown
69
69
  - LICENSE.txt
70
70
  - README.md
71
71
  - Rakefile
72
+ - examples/help_dialogue.rb
73
+ - examples/logging.rb
74
+ - examples/trace.rb
72
75
  - lib/mercenary.rb
73
76
  - lib/mercenary/command.rb
77
+ - lib/mercenary/option.rb
78
+ - lib/mercenary/presenter.rb
74
79
  - lib/mercenary/program.rb
75
80
  - lib/mercenary/version.rb
76
81
  - mercenary.gemspec
77
82
  - script/bootstrap
78
83
  - script/cibuild
84
+ - script/console
85
+ - script/examples
79
86
  - spec/command_spec.rb
87
+ - spec/option_spec.rb
88
+ - spec/presenter_spec.rb
80
89
  - spec/program_spec.rb
81
90
  - spec/spec_helper.rb
82
91
  homepage: https://github.com/jekyll/mercenary
@@ -89,21 +98,23 @@ require_paths:
89
98
  - lib
90
99
  required_ruby_version: !ruby/object:Gem::Requirement
91
100
  requirements:
92
- - - ">="
101
+ - - '>='
93
102
  - !ruby/object:Gem::Version
94
103
  version: '0'
95
104
  required_rubygems_version: !ruby/object:Gem::Requirement
96
105
  requirements:
97
- - - ">="
106
+ - - '>='
98
107
  - !ruby/object:Gem::Version
99
108
  version: '0'
100
109
  requirements: []
101
110
  rubyforge_project:
102
- rubygems_version: 2.2.0
111
+ rubygems_version: 2.0.14
103
112
  signing_key:
104
113
  specification_version: 4
105
114
  summary: Lightweight and flexible library for writing command-line apps in Ruby.
106
115
  test_files:
107
116
  - spec/command_spec.rb
117
+ - spec/option_spec.rb
118
+ - spec/presenter_spec.rb
108
119
  - spec/program_spec.rb
109
120
  - spec/spec_helper.rb