kerplutz 0.1.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.
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +46 -0
- data/LICENSE +20 -0
- data/README.md +25 -0
- data/Rakefile +10 -0
- data/cucumber.yml +1 -0
- data/features/kerplutz.feature +110 -0
- data/features/step_definitions/kerplutz_steps.rb +11 -0
- data/features/support/env.rb +4 -0
- data/kerplutz.gemspec +20 -0
- data/lib/kerplutz.rb +12 -0
- data/lib/kerplutz/builder.rb +42 -0
- data/lib/kerplutz/command.rb +56 -0
- data/lib/kerplutz/command_map.rb +31 -0
- data/lib/kerplutz/executable.rb +65 -0
- data/lib/kerplutz/options.rb +111 -0
- data/spec/kerplutz/command_spec.rb +26 -0
- data/spec/kerplutz/executable_spec.rb +20 -0
- data/spec/kerplutz/options_spec.rb +118 -0
- data/spec/spec_helper.rb +5 -0
- metadata +131 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
tmp/*
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create use 1.9.2@kerplutz
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
kerplutz (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
aruba (0.3.6)
|
10
|
+
childprocess (>= 0.1.7)
|
11
|
+
cucumber (>= 0.10.0)
|
12
|
+
rspec (>= 2.5.0)
|
13
|
+
builder (3.0.0)
|
14
|
+
childprocess (0.1.8)
|
15
|
+
ffi (~> 1.0.6)
|
16
|
+
cucumber (0.10.2)
|
17
|
+
builder (>= 2.1.2)
|
18
|
+
diff-lcs (>= 1.1.2)
|
19
|
+
gherkin (>= 2.3.5)
|
20
|
+
json (>= 1.4.6)
|
21
|
+
term-ansicolor (>= 1.0.5)
|
22
|
+
diff-lcs (1.1.2)
|
23
|
+
ffi (1.0.7)
|
24
|
+
rake (>= 0.8.7)
|
25
|
+
gherkin (2.3.7)
|
26
|
+
json (>= 1.4.6)
|
27
|
+
json (1.5.1)
|
28
|
+
rake (0.8.7)
|
29
|
+
rspec (2.5.0)
|
30
|
+
rspec-core (~> 2.5.0)
|
31
|
+
rspec-expectations (~> 2.5.0)
|
32
|
+
rspec-mocks (~> 2.5.0)
|
33
|
+
rspec-core (2.5.2)
|
34
|
+
rspec-expectations (2.5.0)
|
35
|
+
diff-lcs (~> 1.1.2)
|
36
|
+
rspec-mocks (2.5.0)
|
37
|
+
term-ansicolor (1.0.5)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
aruba
|
44
|
+
cucumber
|
45
|
+
kerplutz!
|
46
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Mike Sassak
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Kerplutz
|
2
|
+
|
3
|
+
Command-line option parsing that won't leave you feeling kerplutz.
|
4
|
+
|
5
|
+
## OMG WHY DO WE NEED ANOTHER ONE OF THESE THINGS?
|
6
|
+
|
7
|
+
Geez I love you too, sunshine. I hesitated for a long while before
|
8
|
+
committing myself to writing Kerplutz. Eventually what pushed me into
|
9
|
+
action was the observation (hopefully correct) that OptionParser is
|
10
|
+
generally a pretty slick library, even if its interface is a bit wonky.
|
11
|
+
It seemed like a shame to let it go to waste, when getting from it what
|
12
|
+
I needed requires only a small amount of code.
|
13
|
+
|
14
|
+
## Todo
|
15
|
+
|
16
|
+
* Read defaults from a config file
|
17
|
+
* Argument type-casts
|
18
|
+
* List arguments
|
19
|
+
* Cleanup OptionParser's puking when an option isn't recognized
|
20
|
+
* Be more shy with the parsed arguments collection via callbacks
|
21
|
+
* Multiline descriptions?
|
22
|
+
|
23
|
+
## Copyright
|
24
|
+
|
25
|
+
Copyright (c) 2011 Mike Sassak. See LICENSE for details.
|
data/Rakefile
ADDED
data/cucumber.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
default: --tags ~@todo
|
@@ -0,0 +1,110 @@
|
|
1
|
+
Feature: Kerplutz
|
2
|
+
|
3
|
+
Command-line option parser for executables with sub-commands
|
4
|
+
(like git or svn) that will not make developers feel kerplutz.
|
5
|
+
|
6
|
+
Background: Option parsing configuration
|
7
|
+
Given an executable named "my-bin" with:
|
8
|
+
"""
|
9
|
+
require 'kerplutz'
|
10
|
+
|
11
|
+
kerplutz = Kerplutz.build "my-bin" do |base|
|
12
|
+
base.banner = "Usage: #{base.name} [OPTIONS] COMMAND [ARGS]"
|
13
|
+
|
14
|
+
base.switch :blinkenlights, "Enable or disable the blinkenlights", abbrev: :b
|
15
|
+
base.flag :frobnicate, "Frobnicate the furtwangler", optional: :target
|
16
|
+
|
17
|
+
base.action :my_action, "Execute my action" do
|
18
|
+
puts "This is my action!"
|
19
|
+
end
|
20
|
+
|
21
|
+
base.action :version, "Show the version", abbrev: :V do
|
22
|
+
puts "#{base.name} version 1.2.3"
|
23
|
+
end
|
24
|
+
|
25
|
+
base.command :start, "Start the reactor!" do |command|
|
26
|
+
command.banner = "Usage: #{base.name} #{command.name} [ARGS]"
|
27
|
+
|
28
|
+
command.switch :lightbulb, "Turn the lightbulb on or off"
|
29
|
+
command.flag :dry_run, "Look, but don't touch", abbrev: :d
|
30
|
+
end
|
31
|
+
|
32
|
+
base.command :open, "Open your mind, Quaid" do |command|
|
33
|
+
command.flag :kuato, "High-level summon", abbrev: :k, required: :host
|
34
|
+
command.switch :backtrace, "Print the full backtrace", abbrev: :b
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
kerplutz.parse(ARGV.dup)
|
39
|
+
"""
|
40
|
+
|
41
|
+
Scenario: help
|
42
|
+
When I run `./my-bin help`
|
43
|
+
Then the output should contain exactly:
|
44
|
+
"""
|
45
|
+
Usage: my-bin [OPTIONS] COMMAND [ARGS]
|
46
|
+
|
47
|
+
-b, --[no-]blinkenlights Enable or disable the blinkenlights
|
48
|
+
--frobnicate [TARGET] Frobnicate the furtwangler
|
49
|
+
--my-action Execute my action
|
50
|
+
-V, --version Show the version
|
51
|
+
|
52
|
+
Commands:
|
53
|
+
start Start the reactor!
|
54
|
+
open Open your mind, Quaid
|
55
|
+
|
56
|
+
Type 'my-bin help COMMAND' for help with a specific command.
|
57
|
+
|
58
|
+
"""
|
59
|
+
|
60
|
+
Scenario: no arguments
|
61
|
+
When I run `./my-bin`
|
62
|
+
Then the output should contain:
|
63
|
+
"""
|
64
|
+
Type 'my-bin help COMMAND' for help with a specific command.
|
65
|
+
|
66
|
+
"""
|
67
|
+
|
68
|
+
Scenario: Known flag to executable
|
69
|
+
When I run `./my-bin --version`
|
70
|
+
Then the output should contain exactly:
|
71
|
+
"""
|
72
|
+
my-bin version 1.2.3
|
73
|
+
|
74
|
+
"""
|
75
|
+
|
76
|
+
Scenario: Only first action is executed
|
77
|
+
When I run `./my-bin --my-action --version`
|
78
|
+
Then the output should contain exactly:
|
79
|
+
"""
|
80
|
+
This is my action!
|
81
|
+
|
82
|
+
"""
|
83
|
+
|
84
|
+
Scenario: Get help about a command
|
85
|
+
When I run `./my-bin help start`
|
86
|
+
Then the output should contain exactly:
|
87
|
+
"""
|
88
|
+
Usage: my-bin start [ARGS]
|
89
|
+
|
90
|
+
--[no-]lightbulb Turn the lightbulb on or off
|
91
|
+
-d, --dry-run Look, but don't touch
|
92
|
+
|
93
|
+
"""
|
94
|
+
|
95
|
+
Scenario: Get help about a command with a default banner
|
96
|
+
When I run `./my-bin help open`
|
97
|
+
Then the output should contain exactly:
|
98
|
+
"""
|
99
|
+
Usage: my-bin open [OPTIONS]
|
100
|
+
|
101
|
+
-k, --kuato HOST High-level summon
|
102
|
+
-b, --[no-]backtrace Print the full backtrace
|
103
|
+
|
104
|
+
"""
|
105
|
+
|
106
|
+
@todo
|
107
|
+
Scenario: Invoke a flag with required argument without an argument
|
108
|
+
|
109
|
+
@todo
|
110
|
+
Scenario: Invoke an unknown option
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Given /^an executable named "(.+)" with:$/ do |name, body|
|
2
|
+
contents = <<EOF
|
3
|
+
#!/usr/bin/env ruby
|
4
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../lib'))
|
5
|
+
|
6
|
+
#{body}
|
7
|
+
EOF
|
8
|
+
|
9
|
+
write_file(name, contents)
|
10
|
+
File.open("tmp/aruba/#{name}") { |file| file.chmod(0755) }
|
11
|
+
end
|
data/kerplutz.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'kerplutz'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
s.authors = ["Mike Sassak"]
|
5
|
+
s.description = "Command-line option parser with subcommands that won't leave you feeling Kerplutz"
|
6
|
+
s.summary = "kerplutz #{s.version}"
|
7
|
+
s.email = "msassak@gmail.com"
|
8
|
+
s.homepage = "https://github.com/msassak/kerplutz"
|
9
|
+
|
10
|
+
s.add_development_dependency 'cucumber'
|
11
|
+
s.add_development_dependency 'aruba'
|
12
|
+
s.add_development_dependency 'rspec'
|
13
|
+
|
14
|
+
s.rubygems_version = "1.3.7"
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
17
|
+
s.extra_rdoc_files = ["LICENSE", "README.md"]
|
18
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
19
|
+
s.require_path = "lib"
|
20
|
+
end
|
data/lib/kerplutz.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'kerplutz/executable'
|
2
|
+
require 'kerplutz/options'
|
3
|
+
|
4
|
+
module Kerplutz
|
5
|
+
class Builder
|
6
|
+
attr_reader :base
|
7
|
+
|
8
|
+
def initialize(base)
|
9
|
+
@base = base
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
base.name
|
14
|
+
end
|
15
|
+
|
16
|
+
def banner=(banner)
|
17
|
+
base.banner = banner
|
18
|
+
end
|
19
|
+
|
20
|
+
def flag(name, desc, opts={})
|
21
|
+
base.add_option(Flag.build(name, desc, opts))
|
22
|
+
end
|
23
|
+
|
24
|
+
def switch(name, desc, opts={})
|
25
|
+
base.add_option(Switch.build(name, desc, opts))
|
26
|
+
end
|
27
|
+
|
28
|
+
def action(name, desc, opts={}, &action)
|
29
|
+
base.add_option(Action.build(name, desc, opts, &action))
|
30
|
+
end
|
31
|
+
|
32
|
+
def command(name, desc)
|
33
|
+
command = Command.new(name, desc, base.arguments)
|
34
|
+
yield builder = Builder.new(command)
|
35
|
+
base.add_command(builder.result)
|
36
|
+
end
|
37
|
+
|
38
|
+
def result
|
39
|
+
base
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Kerplutz
|
5
|
+
class Command
|
6
|
+
attr_reader :name, :desc, :arguments, :parser
|
7
|
+
|
8
|
+
extend Forwardable; def_delegators :@parser, :banner, :help, :parse
|
9
|
+
|
10
|
+
def initialize(name, desc, arguments={})
|
11
|
+
@name = name
|
12
|
+
@desc = desc
|
13
|
+
@arguments = arguments
|
14
|
+
@parser = OptionParser.new(default_banner)
|
15
|
+
end
|
16
|
+
|
17
|
+
def display_name
|
18
|
+
@display_name ||= name.to_s.tr("_", "-")
|
19
|
+
end
|
20
|
+
|
21
|
+
def banner=(banner)
|
22
|
+
parser.banner = (banner.chomp << "\n\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_option(option, prefix_key=true)
|
26
|
+
if prefix_key
|
27
|
+
key = :"#{name}_#{option.name}"
|
28
|
+
else
|
29
|
+
key = option.name.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
option.configure(parser) do |value|
|
33
|
+
arguments[key] = value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# TODO: Is this a better fit for Executable?
|
40
|
+
def default_banner
|
41
|
+
"Usage: #{command_name} [OPTIONS]\n\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
def command_name
|
45
|
+
if program_name == display_name
|
46
|
+
program_name
|
47
|
+
else
|
48
|
+
"#{program_name} #{display_name}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def program_name
|
53
|
+
@program_name ||= File.basename($PROGRAM_NAME)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kerplutz
|
2
|
+
class CommandMap
|
3
|
+
attr_reader :commands
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@commands = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(command)
|
10
|
+
commands[command.display_name] = command
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(command)
|
14
|
+
add(command) and return self
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](display_name)
|
18
|
+
commands[display_name]
|
19
|
+
end
|
20
|
+
|
21
|
+
def ===(display_name)
|
22
|
+
commands.has_key?(display_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def summary(indent=2)
|
26
|
+
commands.inject("") do |acc, (display_name, command)|
|
27
|
+
acc << " " * indent << "#{display_name} #{command.desc}\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
require 'kerplutz/command'
|
4
|
+
require 'kerplutz/command_map'
|
5
|
+
|
6
|
+
module Kerplutz
|
7
|
+
class Executable
|
8
|
+
attr_reader :top, :commands, :arguments
|
9
|
+
|
10
|
+
extend Forwardable; def_delegators :@top, :name, :banner, :banner=
|
11
|
+
|
12
|
+
def initialize(name, arguments={})
|
13
|
+
@arguments = arguments
|
14
|
+
@top = Command.new(name, '', @arguments)
|
15
|
+
@commands = CommandMap.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_command(command)
|
19
|
+
commands << command
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_option(option)
|
23
|
+
top.add_option(option, false)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(args)
|
27
|
+
first, *rest = args
|
28
|
+
remainder = []
|
29
|
+
|
30
|
+
case first
|
31
|
+
|
32
|
+
when help
|
33
|
+
puts (rest.empty? ? banner : commands[rest.first].help)
|
34
|
+
|
35
|
+
when option
|
36
|
+
remainder = top.parse(args)
|
37
|
+
|
38
|
+
when commands
|
39
|
+
remainder = commands[first].parse(rest)
|
40
|
+
|
41
|
+
else
|
42
|
+
puts banner
|
43
|
+
end
|
44
|
+
|
45
|
+
[arguments, remainder]
|
46
|
+
end
|
47
|
+
|
48
|
+
def banner
|
49
|
+
help = ""
|
50
|
+
help << top.help << "\n"
|
51
|
+
help << " Commands:\n" << commands.summary << "\n"
|
52
|
+
help << "Type '#{name} help COMMAND' for help with a specific command.\n"
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def help
|
58
|
+
/^(--help|help)$/
|
59
|
+
end
|
60
|
+
|
61
|
+
def option
|
62
|
+
/^(--|-)[\w-]+$/
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Kerplutz
|
2
|
+
class Option
|
3
|
+
attr_reader :name, :desc
|
4
|
+
attr_accessor :abbrev
|
5
|
+
|
6
|
+
def self.build(name, desc, opts)
|
7
|
+
option = self.new(name, desc)
|
8
|
+
option.abbrev = opts[:abbrev]
|
9
|
+
option
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(name, desc)
|
13
|
+
@name = name
|
14
|
+
@desc = desc
|
15
|
+
end
|
16
|
+
|
17
|
+
def display_name
|
18
|
+
name.to_s.tr("_", "-")
|
19
|
+
end
|
20
|
+
|
21
|
+
def option_sig
|
22
|
+
"--#{display_name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def abbrev_sig
|
26
|
+
return "-#{abbrev[0]}" if abbrev
|
27
|
+
end
|
28
|
+
|
29
|
+
def parser_args
|
30
|
+
[abbrev_sig, option_sig, desc].compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def configure(parser, &blk)
|
34
|
+
raise "You'll need to implement this one yourself, bub."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Flag < Option
|
39
|
+
attr_accessor :arg_name, :arg_required
|
40
|
+
|
41
|
+
def self.build(name, desc, opts)
|
42
|
+
flag = super(name, desc, opts)
|
43
|
+
flag.arg_name = opts[:required] || opts[:optional]
|
44
|
+
flag.arg_required = opts.has_key?(:required)
|
45
|
+
flag
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(name, desc, arg_name=nil)
|
49
|
+
super(name, desc)
|
50
|
+
@arg_name = arg_name
|
51
|
+
end
|
52
|
+
|
53
|
+
def configure(parser, &blk)
|
54
|
+
parser.on(*parser_args) do |arg|
|
55
|
+
if NilClass === arg
|
56
|
+
blk.call(true)
|
57
|
+
else
|
58
|
+
blk.call(arg)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def option_sig
|
64
|
+
"#{super}#{formatted_arg_name}"
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def formatted_arg_name
|
70
|
+
if arg_name and arg_required
|
71
|
+
" #{arg_name.to_s.upcase}"
|
72
|
+
elsif arg_name
|
73
|
+
" [#{arg_name.to_s.upcase}]"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Switch < Option
|
79
|
+
def option_sig
|
80
|
+
"--[no-]#{display_name}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def configure(parser, &blk)
|
84
|
+
parser.on(*parser_args) do |arg|
|
85
|
+
blk.call(arg)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Action < Option
|
91
|
+
attr_accessor :action, :continue_after_exec
|
92
|
+
|
93
|
+
def self.build(name, desc, opts, &action)
|
94
|
+
new_action = super(name, desc, opts)
|
95
|
+
new_action.action = action
|
96
|
+
new_action
|
97
|
+
end
|
98
|
+
|
99
|
+
def initialize(name, desc, &action)
|
100
|
+
super(name, desc)
|
101
|
+
@action = action
|
102
|
+
end
|
103
|
+
|
104
|
+
def configure(parser, &blk)
|
105
|
+
parser.on(*parser_args) do
|
106
|
+
action.call
|
107
|
+
exit unless continue_after_exec
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Kerplutz
|
4
|
+
describe Command do
|
5
|
+
let(:option) { Flag.new(:name, "Description") }
|
6
|
+
let(:args) { Hash.new }
|
7
|
+
subject { Command.new("commandy", "", args) }
|
8
|
+
|
9
|
+
context "#add_option" do
|
10
|
+
it "passes the parser into the option for configuration" do
|
11
|
+
option.should_receive(:configure).with(subject.parser)
|
12
|
+
subject.add_option(option)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "#parse" do
|
17
|
+
it "adds the parsed argument into the arguments hash" do
|
18
|
+
subject.add_option(option)
|
19
|
+
subject.parse("--name")
|
20
|
+
args.should have_key(:commandy_name)
|
21
|
+
args[:commandy_name].should eq(true)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Kerplutz
|
4
|
+
describe Executable do
|
5
|
+
subject { Executable.new("test") }
|
6
|
+
|
7
|
+
describe "#parse" do
|
8
|
+
it "extracts the options from the arguments" do
|
9
|
+
subject.add_option(Switch.new(:foo, ''))
|
10
|
+
subject.parse(["--foo"]).should == [{ :foo => true }, []]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#banner" do
|
15
|
+
it "has a sensible default" do
|
16
|
+
subject.banner.should =~ /^Usage: rspec test \[OPTIONS\]$/
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Kerplutz
|
4
|
+
describe Option do
|
5
|
+
let(:parser) { OptionParser.new }
|
6
|
+
subject { Option.new(:foo, "Do foo") }
|
7
|
+
|
8
|
+
it "generates the parser arguments" do
|
9
|
+
subject.parser_args.should == ["--foo", "Do foo"]
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with an abbreviation" do
|
13
|
+
it "generates the parser arguments" do
|
14
|
+
subject.abbrev = :f
|
15
|
+
subject.parser_args.should == ["-f", "--foo", "Do foo"]
|
16
|
+
subject.abbrev = :option_parser_does_weird_things_if_more_than_one_character
|
17
|
+
subject.parser_args.should == ["-o", "--foo", "Do foo"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Flag do
|
23
|
+
let(:parser) { OptionParser.new }
|
24
|
+
let(:args) { Hash.new }
|
25
|
+
|
26
|
+
context "with no arguments" do
|
27
|
+
subject { Flag.new(:kuato, 'Summon Kuato') }
|
28
|
+
|
29
|
+
its(:option_sig) { should == "--kuato" }
|
30
|
+
|
31
|
+
it "configures the parser" do
|
32
|
+
subject.configure(parser) do |value|
|
33
|
+
value.should === true
|
34
|
+
end
|
35
|
+
parser.parse("--kuato")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with an optional argument" do
|
40
|
+
subject { Flag.new(:kuato, 'Summon Kuato', :host) }
|
41
|
+
|
42
|
+
its(:option_sig) { should == "--kuato [HOST]" }
|
43
|
+
|
44
|
+
it "configures the parser" do
|
45
|
+
subject.configure(parser) do |value|
|
46
|
+
value.should == "George"
|
47
|
+
end
|
48
|
+
parser.parse("--kuato", "George")
|
49
|
+
|
50
|
+
subject.configure(parser) do |value|
|
51
|
+
value.should === true
|
52
|
+
end
|
53
|
+
parser.parse("--kuato")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with a required argument" do
|
58
|
+
subject do
|
59
|
+
flag = Flag.new(:kuato, 'Summon Kuato', :host)
|
60
|
+
flag.arg_required = true
|
61
|
+
flag
|
62
|
+
end
|
63
|
+
|
64
|
+
its(:option_sig) { should == "--kuato HOST" }
|
65
|
+
|
66
|
+
it "configures the parser" do
|
67
|
+
subject.configure(parser) { |value| } # no-op
|
68
|
+
expect { parser.parse("--kuato") }.to raise_error(OptionParser::MissingArgument)
|
69
|
+
|
70
|
+
subject.configure(parser) do |value|
|
71
|
+
value.should == "George"
|
72
|
+
end
|
73
|
+
parser.parse("--kuato", "George")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe Switch do
|
79
|
+
let(:parser) { OptionParser.new }
|
80
|
+
let(:args) { Hash.new }
|
81
|
+
|
82
|
+
subject { Switch.new(:verbose, "Be chatty") }
|
83
|
+
|
84
|
+
its(:option_sig) { should == "--[no-]verbose" }
|
85
|
+
|
86
|
+
it "configures the parser" do
|
87
|
+
subject.configure(parser) do |value|
|
88
|
+
value.should === true
|
89
|
+
end
|
90
|
+
parser.parse("--verbose")
|
91
|
+
|
92
|
+
subject.configure(parser) do |value|
|
93
|
+
value.should be_false
|
94
|
+
end
|
95
|
+
parser.parse("--no-verbose")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe Action do
|
100
|
+
let(:parser) { OptionParser.new }
|
101
|
+
let(:args) { Hash.new }
|
102
|
+
|
103
|
+
subject do
|
104
|
+
action = Action.new(:start_reactor, "Start the reactor!") do
|
105
|
+
$action = "Hello there"
|
106
|
+
end
|
107
|
+
action.continue_after_exec = true
|
108
|
+
action
|
109
|
+
end
|
110
|
+
|
111
|
+
it "configures the parser" do
|
112
|
+
subject.configure(parser)
|
113
|
+
$action.should eq(nil)
|
114
|
+
parser.parse("--start-reactor")
|
115
|
+
$action.should eq("Hello there")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kerplutz
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Mike Sassak
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-05-19 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: cucumber
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :development
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: aruba
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :development
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
type: :development
|
58
|
+
version_requirements: *id003
|
59
|
+
description: Command-line option parser with subcommands that won't leave you feeling Kerplutz
|
60
|
+
email: msassak@gmail.com
|
61
|
+
executables: []
|
62
|
+
|
63
|
+
extensions: []
|
64
|
+
|
65
|
+
extra_rdoc_files:
|
66
|
+
- LICENSE
|
67
|
+
- README.md
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- .rspec
|
71
|
+
- .rvmrc
|
72
|
+
- Gemfile
|
73
|
+
- Gemfile.lock
|
74
|
+
- LICENSE
|
75
|
+
- README.md
|
76
|
+
- Rakefile
|
77
|
+
- cucumber.yml
|
78
|
+
- features/kerplutz.feature
|
79
|
+
- features/step_definitions/kerplutz_steps.rb
|
80
|
+
- features/support/env.rb
|
81
|
+
- kerplutz.gemspec
|
82
|
+
- lib/kerplutz.rb
|
83
|
+
- lib/kerplutz/builder.rb
|
84
|
+
- lib/kerplutz/command.rb
|
85
|
+
- lib/kerplutz/command_map.rb
|
86
|
+
- lib/kerplutz/executable.rb
|
87
|
+
- lib/kerplutz/options.rb
|
88
|
+
- spec/kerplutz/command_spec.rb
|
89
|
+
- spec/kerplutz/executable_spec.rb
|
90
|
+
- spec/kerplutz/options_spec.rb
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
has_rdoc: true
|
93
|
+
homepage: https://github.com/msassak/kerplutz
|
94
|
+
licenses: []
|
95
|
+
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options:
|
98
|
+
- --charset=UTF-8
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
requirements: []
|
118
|
+
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 1.3.7
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: kerplutz 0.1.0
|
124
|
+
test_files:
|
125
|
+
- features/kerplutz.feature
|
126
|
+
- features/step_definitions/kerplutz_steps.rb
|
127
|
+
- features/support/env.rb
|
128
|
+
- spec/kerplutz/command_spec.rb
|
129
|
+
- spec/kerplutz/executable_spec.rb
|
130
|
+
- spec/kerplutz/options_spec.rb
|
131
|
+
- spec/spec_helper.rb
|