delano-drydock 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +16 -0
- data/README.rdoc +46 -33
- data/Rakefile +72 -0
- data/bin/example +32 -50
- data/drydock.gemspec +53 -0
- data/lib/drydock.rb +375 -125
- data/test/command_test.rb +40 -0
- metadata +33 -7
- data/lib/drydock/exceptions.rb +0 -24
data/CHANGES.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
DRYDOCK, CHANGES
|
2
|
+
|
3
|
+
#### 0.3 (2009-02-05) ###############################
|
4
|
+
|
5
|
+
* Added support for custom Drydock::Commands objects
|
6
|
+
* Global and command-specific options are now available as
|
7
|
+
attributes of the Drydock::Commands class instance.
|
8
|
+
* Automatic execution
|
9
|
+
* Now in a single file (lib/drydock.rb)
|
10
|
+
* Started adding tests
|
11
|
+
* Improved documentation
|
12
|
+
|
13
|
+
#### 0.2 (2008-12-27) ###############################
|
14
|
+
|
15
|
+
* Initial release
|
16
|
+
* Forked from bmizerany/frylock
|
data/README.rdoc
CHANGED
@@ -1,56 +1,69 @@
|
|
1
|
-
= Drydock -
|
1
|
+
= Drydock - v0.3
|
2
2
|
|
3
|
-
Inspired by
|
4
|
-
|
5
|
-
Inspired by "bmizerany-frylock":http://github.com/bmizerany/frylock/tree
|
3
|
+
Inspired by github-gem and bmizerany-frylock.
|
6
4
|
|
7
5
|
== Overview
|
8
6
|
|
9
|
-
Drydock is a DSL for command line apps.
|
7
|
+
Drydock is a seaworthy DSL for command line apps. It is contained in a single .rb which can be copied directly into your project.
|
10
8
|
|
11
9
|
== Install
|
12
10
|
|
13
|
-
|
11
|
+
One of:
|
12
|
+
|
13
|
+
* gem install drydock
|
14
|
+
* copy lib/drydock.rb into your lib directory.
|
14
15
|
|
16
|
+
Or for GitHub fans:
|
17
|
+
|
18
|
+
* git clone git://github.com/delano/drydock.git
|
19
|
+
* gem install delano-drydock
|
15
20
|
|
16
21
|
== Examples
|
17
22
|
|
18
23
|
See bin/example for more.
|
19
24
|
|
20
|
-
|
21
|
-
require '
|
22
|
-
require 'drydock'
|
25
|
+
require 'rubygems'
|
26
|
+
require 'drydock'
|
23
27
|
|
24
|
-
default :welcome
|
28
|
+
default :welcome
|
25
29
|
|
26
|
-
before do
|
27
|
-
# You can execute a block before the requests command is executed. Instance
|
28
|
-
# variables defined here will be available to all commands.
|
29
|
-
end
|
30
|
+
before do
|
31
|
+
# You can execute a block before the requests command is executed. Instance
|
32
|
+
# variables defined here will be available to all commands.
|
33
|
+
end
|
30
34
|
|
31
|
-
command :welcome do
|
32
|
-
# Example: ruby bin/example
|
35
|
+
command :welcome do
|
36
|
+
# Example: ruby bin/example
|
33
37
|
|
34
|
-
|
35
|
-
|
38
|
+
puts "Meatwad: Science is a mystery to man, isn't it Frylock?"
|
39
|
+
print "Frylock: At least we have some commands: "
|
36
40
|
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
option :f, :found, "A boolean value. Did you find the car?"
|
42
|
-
command :findcar do |options|
|
43
|
-
# +options+ is a hash containing the options defined above
|
44
|
-
# Example: ruby bin/example -f findcar
|
41
|
+
# The commands method returns a hash of Frylock::Command objects
|
42
|
+
puts commands.keys.inject([]) { |list, command| list << command.to_s }.sort.join(', ')
|
43
|
+
end
|
44
|
+
|
45
|
+
option :f, :found, "A boolean value. Did you find the car?"
|
46
|
+
command :findcar do |options|
|
47
|
+
# +options+ is a hash containing the options defined above
|
48
|
+
# Example: ruby bin/example -f findcar
|
45
49
|
|
46
|
-
|
50
|
+
puts "Frylock: So, did they ever find your car?"
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
53
|
-
|
52
|
+
# The keys to the hash are the long string from the option definition.
|
53
|
+
# If only the short string is provided, those will be used instead (i.e. :f).
|
54
|
+
puts (!options[:found]) ? "Carl: No" :
|
55
|
+
"Carl: Oh, they found part of it, hangin' from a trestle near the turnpike."
|
56
|
+
end
|
57
|
+
|
58
|
+
== More Information
|
59
|
+
|
60
|
+
http://www.youtube.com/watch?v=m_wFEB4Oxlo
|
61
|
+
|
62
|
+
== Credits
|
63
|
+
|
64
|
+
* Delano Mandelbaum (delano@solutious.com)
|
65
|
+
* Bernie Kopell (bernie@solutious.com)
|
66
|
+
|
54
67
|
|
55
68
|
== License
|
56
69
|
|
data/Rakefile
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'hanna/rdoctask'
|
5
|
+
require 'fileutils'
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
# SPECS ===============================================================
|
11
|
+
|
12
|
+
desc 'Run specs with unit test style output'
|
13
|
+
task :test do |t|
|
14
|
+
sh "ruby tests/*_test.rb"
|
15
|
+
end
|
16
|
+
|
17
|
+
# PACKAGE =============================================================
|
18
|
+
|
19
|
+
|
20
|
+
require File.dirname(__FILE__) + "/lib/drydock"
|
21
|
+
load "drydock.gemspec"
|
22
|
+
|
23
|
+
version = Drydock::VERSION.to_s
|
24
|
+
|
25
|
+
Drydock.run = false
|
26
|
+
|
27
|
+
Rake::GemPackageTask.new(@spec) do |p|
|
28
|
+
p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
29
|
+
end
|
30
|
+
|
31
|
+
task :release => [ :rdoc, :package ]
|
32
|
+
|
33
|
+
task :install => [ :rdoc, :package ] do
|
34
|
+
sh %{sudo gem install pkg/#{name}-#{version}.gem}
|
35
|
+
end
|
36
|
+
|
37
|
+
task :uninstall => [ :clean ] do
|
38
|
+
sh %{sudo gem uninstall #{name}}
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# Rubyforge Release / Publish Tasks ==================================
|
43
|
+
|
44
|
+
desc 'Publish website to rubyforge'
|
45
|
+
task 'publish:doc' => 'doc/index.html' do
|
46
|
+
sh 'scp -rp doc/* rubyforge.org:/var/www/gforge-projects/drydock/'
|
47
|
+
end
|
48
|
+
puts "rubyforge add_release drydock drydock #{@spec.version} pkg/drydock-#{@spec.version}.gem "
|
49
|
+
task 'publish:gem' => [:package] do |t|
|
50
|
+
sh <<-end
|
51
|
+
rubyforge add_release -o Any -a CHANGES.txt -f -n README.rdoc drydock drydock #{@spec.version} pkg/drydock-#{@spec.version}.gem &&
|
52
|
+
rubyforge add_file -o Any -a CHANGES.txt -f -n README.rdoc drydock drydock #{@spec.version} pkg/drydock-#{@spec.version}.tgz
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
Rake::RDocTask.new do |t|
|
58
|
+
t.rdoc_dir = 'doc'
|
59
|
+
t.title = "Drydock, A seaworthy DSL for command-line apps."
|
60
|
+
t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
61
|
+
t.options << '--charset' << 'utf-8'
|
62
|
+
t.rdoc_files.include('LICENSE.txt')
|
63
|
+
t.rdoc_files.include('README.rdoc')
|
64
|
+
t.rdoc_files.include('CHANGES.txt')
|
65
|
+
t.rdoc_files.include('bin/*')
|
66
|
+
t.rdoc_files.include('lib/*.rb')
|
67
|
+
end
|
68
|
+
|
69
|
+
CLEAN.include [ 'pkg', '*.gem', '.config', 'doc' ]
|
70
|
+
|
71
|
+
|
72
|
+
|
data/bin/example
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
$: << File.join(DRYDOCK_HOME, 'lib')
|
3
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..')), 'lib'
|
5
4
|
|
6
|
-
require 'rubygems'
|
7
5
|
require 'drydock'
|
8
6
|
|
9
7
|
default :welcome
|
10
8
|
|
11
|
-
|
12
9
|
before do
|
13
10
|
# You can execute a block before the requests command is executed. Instance
|
14
11
|
# variables defined here will be available to all commands.
|
15
12
|
end
|
16
13
|
|
14
|
+
after do
|
15
|
+
# And this will be called after the command.
|
16
|
+
end
|
17
17
|
|
18
18
|
command :welcome do
|
19
19
|
# Example: ruby bin/example
|
@@ -27,15 +27,15 @@ end
|
|
27
27
|
|
28
28
|
|
29
29
|
option :f, :found, "A boolean value. Did you find the car?"
|
30
|
-
command :findcar do |
|
31
|
-
# +
|
30
|
+
command :findcar do |obj|
|
31
|
+
# +obj+ is the Drylock::Command object instance. It contains accessors for all options.
|
32
32
|
# Example: ruby bin/example -f findcar
|
33
33
|
|
34
34
|
puts "Frylock: So, did they ever find your car?"
|
35
35
|
|
36
36
|
# The keys to the hash are the long string from the option definition.
|
37
37
|
# If only the short string is provided, those will be used instead (i.e. :f).
|
38
|
-
puts (!
|
38
|
+
puts (!obj.found) ? "Carl: No" :
|
39
39
|
"Carl: Oh, they found part of it, hangin' from a trestle near the turnpike."
|
40
40
|
end
|
41
41
|
|
@@ -51,17 +51,28 @@ global_option :v, :verbose, "Verbosity level (i.e. -vvv is greater than -v)" do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
|
54
|
-
usage "
|
55
|
-
command :date do |
|
56
|
-
# +argv+
|
57
|
-
# +global_options+ contains hash of the options defined with global_options
|
58
|
-
|
54
|
+
usage "#{$0} [-s] [-vv] date"
|
55
|
+
command :date do |obj, argv|
|
56
|
+
# +argv+ is an array containing the unnamed arguments
|
59
57
|
require 'time'
|
60
58
|
now = Time.now
|
61
|
-
puts "
|
62
|
-
puts
|
59
|
+
puts "(Not verbose enough. Try adding a -v.)" if (obj.verbose || 0) == 1
|
60
|
+
puts "More verbosely, the date is now: " if (obj.verbose || 0) >= 2
|
61
|
+
puts (obj.seconds) ? now.to_i : now.to_s
|
63
62
|
end
|
64
63
|
|
64
|
+
usage "#{$0} rogue"
|
65
|
+
ignore :options
|
66
|
+
command :rogue do |obj, argv|
|
67
|
+
# You can use ignore :options to tell Drydock to not process the
|
68
|
+
# command-specific options.
|
69
|
+
if argv.empty?
|
70
|
+
puts "Had you supplied some arguments, I would have ignored them."
|
71
|
+
else
|
72
|
+
puts "Hi! You supplied some arguments but I ignored them."
|
73
|
+
puts "They're all still here in this array: %s" % argv.join(', ')
|
74
|
+
end
|
75
|
+
end
|
65
76
|
|
66
77
|
option :c, :check, "Check response codes for each URI"
|
67
78
|
option :d, :delim, String, "Output delimiter"
|
@@ -73,31 +84,31 @@ option :t, :timeout, Float, "Timeout value for HTTP request" do |v|
|
|
73
84
|
end
|
74
85
|
|
75
86
|
usage 'echo "http://github.com/" | ruby bin/example process -c -d " " -t 15 http://solutious.com/'
|
76
|
-
command :
|
77
|
-
# +stdin+ is either an IO object or a custom object defined with a stdin block (see below)
|
87
|
+
command :processuri do |obj, argv, stdin|
|
78
88
|
# +cmd+ is the string used to evoke this command. Useful with alias_command (see below).
|
89
|
+
# +stdin+ is either an IO object or a custom object defined with a stdin block (see below)
|
79
90
|
|
80
91
|
require 'net/http'
|
81
92
|
require 'uri'
|
82
93
|
require 'timeout'
|
83
94
|
|
84
95
|
uris = [stdin, argv].flatten # Combine the argv and stdin arrays
|
85
|
-
delim =
|
86
|
-
timeout =
|
96
|
+
delim = obj.delim || ','
|
97
|
+
timeout = obj.timeout || 5
|
87
98
|
code = :notchecked # The default code when :check is false
|
88
99
|
|
89
100
|
if uris.empty?
|
90
101
|
puts "Frylock: You didn't provide any URIs. "
|
91
|
-
puts "Master Shake: Ya, see #{$0} #{
|
102
|
+
puts "Master Shake: Ya, see #{$0} #{obj.alias} -h"
|
92
103
|
exit 0
|
93
104
|
end
|
94
105
|
|
95
106
|
uris.each_with_index do |uri, index|
|
96
|
-
code = response_code(uri, timeout) if (
|
107
|
+
code = response_code(uri, timeout) if (obj.check)
|
97
108
|
puts [index+1, uri, code].join(delim)
|
98
109
|
end
|
99
110
|
end
|
100
|
-
alias_command :
|
111
|
+
alias_command :checkuri, :processuri
|
101
112
|
|
102
113
|
|
103
114
|
|
@@ -139,32 +150,3 @@ def response_code(uri_str, duration=5)
|
|
139
150
|
response
|
140
151
|
end
|
141
152
|
|
142
|
-
|
143
|
-
at_exit do
|
144
|
-
# This is an example of how to call Frylock in your script.
|
145
|
-
begin
|
146
|
-
Drydock.run!(ARGV, STDIN)
|
147
|
-
|
148
|
-
rescue Drydock::UnknownCommand => ex
|
149
|
-
STDERR.puts "Frylock: I don't know what the #{ex.name} command is. #{$/}"
|
150
|
-
STDERR.puts "Master Shake: I'll tell you what it is, friends... it's shut up and let me eat it."
|
151
|
-
|
152
|
-
rescue Drydock::NoCommandsDefined => ex
|
153
|
-
STDERR.puts "Frylock: Carl, I don't want it. And I'd appreciate it if you'd define at least one command. #{$/}"
|
154
|
-
STDERR.puts "Carl: Fryman, don't be that way! This sorta thing happens every day! People just don't... you know, talk about it this loud."
|
155
|
-
|
156
|
-
rescue Drydock::InvalidArgument => ex
|
157
|
-
STDERR.puts "Frylock: Shake, how many arguments have you not provided a value for this year? #{$/}"
|
158
|
-
STDERR.puts "Master Shake: A *lot* more than *you* have! (#{@args.join(', ')})"
|
159
|
-
|
160
|
-
rescue Drydock::MissingArgument => ex
|
161
|
-
STDERR.puts "Frylock: I don't know what #{ex.args.join(', ')} is. #{$/}"
|
162
|
-
STDERR.puts "Master Shake: I'll tell you what it is, friends... it's shut up and let me eat it."
|
163
|
-
|
164
|
-
rescue => ex
|
165
|
-
STDERR.puts "Master Shake: Okay, but when we go in, watch your step. "
|
166
|
-
STDERR.puts "Frylock: Why?"
|
167
|
-
STDERR.puts "Meatwad: [explosion] #{ex.message}"
|
168
|
-
STDERR.puts ex.backtrace
|
169
|
-
end
|
170
|
-
end
|
data/drydock.gemspec
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
@spec = Gem::Specification.new do |s|
|
2
|
+
s.name = %q{drydock}
|
3
|
+
s.version = "0.3.1"
|
4
|
+
s.specification_version = 1 if s.respond_to? :specification_version=
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
|
7
|
+
s.authors = ["Delano Mandelbaum"]
|
8
|
+
s.date = %q{2008-08-17}
|
9
|
+
s.description = %q{A seaworthy DSL for writing command line apps inspired by Blake Mizerany's Frylock}
|
10
|
+
s.email = %q{delano@solutious.com}
|
11
|
+
s.files = %w(
|
12
|
+
CHANGES.txt
|
13
|
+
LICENSE.txt
|
14
|
+
README.rdoc
|
15
|
+
Rakefile
|
16
|
+
bin/example
|
17
|
+
drydock.gemspec
|
18
|
+
lib/drydock.rb
|
19
|
+
test/command_test.rb
|
20
|
+
doc
|
21
|
+
doc/classes
|
22
|
+
doc/classes/Drydock
|
23
|
+
doc/classes/Drydock/Command.html
|
24
|
+
doc/classes/Drydock/InvalidArgument.html
|
25
|
+
doc/classes/Drydock/MissingArgument.html
|
26
|
+
doc/classes/Drydock/NoCommandsDefined.html
|
27
|
+
doc/classes/Drydock/UnknownCommand.html
|
28
|
+
doc/classes/Drydock.html
|
29
|
+
doc/created.rid
|
30
|
+
doc/files
|
31
|
+
doc/files/bin
|
32
|
+
doc/files/bin/example.html
|
33
|
+
doc/files/CHANGES_txt.html
|
34
|
+
doc/files/lib
|
35
|
+
doc/files/lib/drydock_rb.html
|
36
|
+
doc/files/LICENSE_txt.html
|
37
|
+
doc/files/README_rdoc.html
|
38
|
+
doc/fr_class_index.html
|
39
|
+
doc/fr_file_index.html
|
40
|
+
doc/fr_method_index.html
|
41
|
+
doc/index.html
|
42
|
+
doc/rdoc-style.css
|
43
|
+
)
|
44
|
+
s.has_rdoc = true
|
45
|
+
s.homepage = %q{http://github.com/delano/drydock}
|
46
|
+
s.extra_rdoc_files = %w[README.rdoc LICENSE.txt CHANGES.txt]
|
47
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Drydock: a seaworthy DSL for command-line apps", "--main", "README.rdoc"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.1.1}
|
50
|
+
s.summary = %q{A seaworthy DSL for writing command line apps}
|
51
|
+
|
52
|
+
s.rubyforge_project = "drydock"
|
53
|
+
end
|
data/lib/drydock.rb
CHANGED
@@ -1,133 +1,368 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'ostruct'
|
3
|
-
require 'pp'
|
4
|
-
|
5
|
-
require 'drydock/exceptions'
|
6
3
|
|
4
|
+
#
|
5
|
+
#
|
7
6
|
module Drydock
|
7
|
+
# The base class for all command objects. There is an instance of this class
|
8
|
+
# for every command defined. Global and command-specific options are added
|
9
|
+
# as attributes to this class dynamically.
|
10
|
+
#
|
11
|
+
# i.e. "example -v date -f yaml"
|
12
|
+
#
|
13
|
+
# global_option :v, :verbose, "I want mooooore!"
|
14
|
+
# option :f, :format, String, "Long date format"
|
15
|
+
# command :date do |obj|
|
16
|
+
# puts obj.verbose #=> true
|
17
|
+
# puts obj.format #=> "yaml"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# You can inherit from this class to create your own: EatFood < Drydock::Command.
|
21
|
+
# And then specific your class in the command definition:
|
22
|
+
#
|
23
|
+
# command :eat => EatFood do |obj|; ...; end
|
24
|
+
#
|
8
25
|
class Command
|
9
|
-
attr_reader :cmd, :
|
10
|
-
|
11
|
-
|
12
|
-
|
26
|
+
attr_reader :cmd, :alias
|
27
|
+
# +cmd+ is the short name of this command.
|
28
|
+
# +b+ is the block associated to this command.
|
29
|
+
def initialize(cmd, &b)
|
30
|
+
@cmd = (cmd.kind_of?(Symbol)) ? cmd : cmd.to_sym
|
13
31
|
@b = b
|
14
32
|
end
|
15
33
|
|
16
|
-
|
17
|
-
|
18
|
-
|
34
|
+
# Execute the block.
|
35
|
+
#
|
36
|
+
# +cmd_str+ is the short name used to evoke this command. It will equal @cmd
|
37
|
+
# unless an alias was used used to evoke this command.
|
38
|
+
# +argv+ an array of unnamed arguments. If ignore :options was declared this
|
39
|
+
# will contain the arguments exactly as they were defined on the command-line.
|
40
|
+
# +stdin+ contains the output of stdin do; ...; end otherwise it's a STDIN IO handle.
|
41
|
+
# +global_options+ a hash of the global options specified on the command-line
|
42
|
+
# +options+ a hash of the command-specific options specific on the command-line.
|
43
|
+
def call(cmd_str=nil, argv=[], stdin=[], global_options={}, options={})
|
44
|
+
@alias = cmd_str.nil? ? @cmd : cmd_str
|
45
|
+
global_options.merge(options).each_pair do |n,v|
|
46
|
+
self.send("#{n}=", v)
|
47
|
+
end
|
48
|
+
block_args = [self, argv, stdin] # TODO: review order
|
49
|
+
@b.call(*block_args[0..(@b.arity-1)]) # send only as many args as defined
|
19
50
|
end
|
51
|
+
|
52
|
+
# The name of the command
|
20
53
|
def to_s
|
21
54
|
@cmd.to_s
|
22
55
|
end
|
23
56
|
end
|
24
57
|
end
|
25
58
|
|
59
|
+
module Drydock
|
60
|
+
class UnknownCommand < RuntimeError
|
61
|
+
attr_reader :name
|
62
|
+
def initialize(name)
|
63
|
+
@name = name || :unknown
|
64
|
+
end
|
65
|
+
def message
|
66
|
+
"Unknown command: #{@name}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
class NoCommandsDefined < RuntimeError
|
70
|
+
def message
|
71
|
+
"No commands defined"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
class InvalidArgument < RuntimeError
|
75
|
+
attr_accessor :args
|
76
|
+
def initialize(args)
|
77
|
+
@args = args || []
|
78
|
+
end
|
79
|
+
def message
|
80
|
+
"Unknown option: #{@args.join(", ")}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
class MissingArgument < InvalidArgument
|
84
|
+
def message
|
85
|
+
"Option requires a value: #{@args.join(", ")}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Drydock is a DSL for command-line apps.
|
91
|
+
# See bin/example for usage examples.
|
26
92
|
module Drydock
|
27
93
|
extend self
|
28
94
|
|
29
|
-
|
95
|
+
VERSION = 0.3
|
96
|
+
|
97
|
+
private
|
98
|
+
# Stolen from Sinatra!
|
99
|
+
def delegate(*args)
|
100
|
+
args.each do |m|
|
101
|
+
eval(<<-end_eval, binding, "(__Drydock__)", __LINE__)
|
102
|
+
def #{m}(*args, &b)
|
103
|
+
Drydock.#{m}(*args, &b)
|
104
|
+
end
|
105
|
+
end_eval
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
delegate :before, :after, :alias_command, :commands
|
110
|
+
delegate :global_option, :global_usage, :usage, :command
|
111
|
+
delegate :debug, :option, :stdin, :default, :ignore, :command_alias
|
112
|
+
|
113
|
+
@@debug = false
|
114
|
+
@@has_run = false
|
115
|
+
@@run = true
|
116
|
+
|
117
|
+
public
|
118
|
+
# Enable or disable debug output.
|
119
|
+
#
|
120
|
+
# debug :on
|
121
|
+
# debug :off
|
122
|
+
#
|
123
|
+
# Calling without :on or :off will toggle the value.
|
124
|
+
#
|
125
|
+
def debug(toggle=false)
|
126
|
+
if toggle.is_a? Symbol
|
127
|
+
@@debug = true if toggle == :on
|
128
|
+
@@debug = false if toggle == :off
|
129
|
+
else
|
130
|
+
@@debug = (!@@debug)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
# Returns true if debug output is enabled.
|
134
|
+
def debug?
|
135
|
+
@@debug
|
136
|
+
end
|
30
137
|
|
138
|
+
# Define a default command.
|
139
|
+
#
|
140
|
+
# default :task
|
141
|
+
#
|
31
142
|
def default(cmd)
|
32
|
-
|
143
|
+
@@default_command = canonize(cmd)
|
33
144
|
end
|
34
145
|
|
146
|
+
# Define a block for processing STDIN before the command is called.
|
147
|
+
# The command block receives the return value of this block in a named argument:
|
148
|
+
#
|
149
|
+
# command :task do |obj, argv, stdin|; ...; end
|
150
|
+
#
|
151
|
+
# If a stdin block isn't defined, +stdin+ above will be the STDIN IO handle.
|
35
152
|
def stdin(&b)
|
36
|
-
|
153
|
+
@@stdin_block = b
|
37
154
|
end
|
155
|
+
|
156
|
+
# Define a block to be called before the command.
|
157
|
+
# This is useful for opening database connections, etc...
|
38
158
|
def before(&b)
|
39
|
-
|
159
|
+
@@before_block = b
|
40
160
|
end
|
41
161
|
|
42
|
-
#
|
43
|
-
#
|
162
|
+
# Define a block to be called after the command.
|
163
|
+
# This is useful for stopping, closing, etc... the stuff in the before block.
|
164
|
+
def after(&b)
|
165
|
+
@@after_block = b
|
166
|
+
end
|
167
|
+
|
168
|
+
# Define the default global usage banner. This is displayed
|
169
|
+
# with "script -h".
|
44
170
|
def global_usage(msg)
|
45
|
-
|
46
|
-
|
171
|
+
@@global_options ||= OpenStruct.new
|
172
|
+
global_opts_parser.banner = "USAGE: #{msg}"
|
173
|
+
end
|
47
174
|
|
48
|
-
|
175
|
+
# Define a command-specific usage banner. This is displayed
|
176
|
+
# with "script command -h"
|
177
|
+
def usage(msg)
|
178
|
+
get_current_option_parser.banner = "USAGE: #{msg}"
|
49
179
|
end
|
50
180
|
|
51
|
-
|
181
|
+
# Grab the options parser for the current command or create it if it doesn't exist.
|
182
|
+
def get_current_option_parser
|
183
|
+
@@command_opts_parser ||= []
|
184
|
+
@@command_index ||= 0
|
185
|
+
(@@command_opts_parser[@@command_index] ||= OptionParser.new)
|
186
|
+
end
|
52
187
|
|
53
|
-
#
|
188
|
+
# Tell the Drydock parser to ignore something.
|
189
|
+
# Drydock will currently only listen to you if you tell it to "ignore :options",
|
190
|
+
# otherwise it will ignore you!
|
191
|
+
#
|
192
|
+
# +what+ the thing to ignore. When it equals :options Drydock will not parse
|
193
|
+
# the command-specific arguments. It will pass the Command object the list of
|
194
|
+
# arguments. This is useful when you want to parse the arguments in some a way
|
195
|
+
# that's too crazy, dangerous for Drydock to handle automatically.
|
196
|
+
def ignore(what=:nothing)
|
197
|
+
@@command_opts_parser[@@command_index] = :ignore if what == :options || what == :all
|
198
|
+
end
|
199
|
+
|
200
|
+
# Define a global option. See +option+ for more info.
|
201
|
+
def global_option(*args, &b)
|
202
|
+
args.unshift(global_opts_parser)
|
203
|
+
global_option_names << option_parser(args, &b)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Define a command-specific option.
|
207
|
+
#
|
208
|
+
# +args+ is passed directly to OptionParser.on so it can contain anything
|
209
|
+
# that's valid to that method. Some examples:
|
210
|
+
# [:h, :help, "Displays this message"]
|
211
|
+
# [:m, :max, Integer, "Maximum threshold"]
|
212
|
+
# ['-l x,y,z', '--lang=x,y,z', Array, "Requested languages"]
|
213
|
+
# If a class is included, it will tell OptionParser to expect a value
|
214
|
+
# otherwise it assumes a boolean value.
|
54
215
|
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
|
60
|
-
|
61
|
-
|
216
|
+
# All calls to +option+ must come before the command they're associated
|
217
|
+
# to. Example:
|
218
|
+
#
|
219
|
+
# option :l, :longname, String, "Description" do; ...; end
|
220
|
+
# command :task do |obj|; ...; end
|
221
|
+
#
|
222
|
+
# When calling your script with a specific command-line option, the value
|
223
|
+
# is available via obj.longname inside the command block.
|
224
|
+
#
|
225
|
+
def option(*args, &b)
|
226
|
+
args.unshift(get_current_option_parser)
|
227
|
+
current_command_option_names << option_parser(args, &b)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Define a command.
|
231
|
+
#
|
232
|
+
# command :task do
|
233
|
+
# ...
|
234
|
+
# end
|
235
|
+
#
|
236
|
+
# A custom command class can be specified using Hash syntax. The class
|
237
|
+
# must inherit from Drydock::Command (class CustomeClass < Drydock::Command)
|
238
|
+
#
|
239
|
+
# command :task => CustomCommand do
|
240
|
+
# ...
|
241
|
+
# end
|
242
|
+
#
|
243
|
+
def command(*cmds, &b)
|
244
|
+
@@command_index ||= 0
|
245
|
+
@@command_opts_parser ||= []
|
246
|
+
@@command_option_names ||= []
|
247
|
+
cmds.each do |cmd|
|
248
|
+
if cmd.is_a? Hash
|
249
|
+
c = cmd.values.first.new(cmd.keys.first, &b)
|
250
|
+
else
|
251
|
+
c = Drydock::Command.new(cmd, &b)
|
252
|
+
end
|
253
|
+
commands[c.cmd] = c
|
254
|
+
command_index_map[c.cmd] = @@command_index
|
255
|
+
@@command_index += 1
|
256
|
+
end
|
62
257
|
|
63
|
-
|
258
|
+
end
|
259
|
+
|
260
|
+
# Used to create an alias to a defined command.
|
261
|
+
# Here's an example:
|
262
|
+
#
|
263
|
+
# command :task do; ...; end
|
264
|
+
# alias_command :pointer, :task
|
265
|
+
#
|
266
|
+
# Either name can be used on the command-line:
|
267
|
+
#
|
268
|
+
# $ script task [options]
|
269
|
+
# $ script pointer [options]
|
270
|
+
#
|
271
|
+
# Inside of the command definition, you have access to the
|
272
|
+
# command name that was used via obj.alias.
|
273
|
+
def alias_command(aliaz, cmd)
|
274
|
+
return unless commands.has_key? cmd
|
275
|
+
@@commands[aliaz] = commands[cmd]
|
276
|
+
end
|
277
|
+
alias :command_alias :alias_command
|
278
|
+
|
279
|
+
# An array of the currently defined Drydock::Command objects
|
280
|
+
def commands
|
281
|
+
@@commands ||= {}
|
282
|
+
end
|
283
|
+
|
284
|
+
# Returns true if automatic execution is enabled.
|
285
|
+
def run?
|
286
|
+
@@run
|
287
|
+
end
|
288
|
+
|
289
|
+
# Disable automatic execution (enabled by default)
|
290
|
+
#
|
291
|
+
# Drydock.run = false
|
292
|
+
def run=(v)
|
293
|
+
@@run = (v == true) ? true : false
|
294
|
+
end
|
295
|
+
|
296
|
+
# Return true if a command has been executed.
|
297
|
+
def has_run?
|
298
|
+
@@has_run
|
299
|
+
end
|
300
|
+
|
301
|
+
# Execute the given command.
|
302
|
+
# By default, Drydock automatically executes itself and provides handlers for known errors.
|
303
|
+
# You can override this functionality by calling +Drydock.run!+ yourself. Drydock
|
304
|
+
# will only call +run!+ once.
|
305
|
+
def run!(argv=[], stdin=STDIN)
|
306
|
+
return if has_run?
|
307
|
+
@@has_run = true
|
308
|
+
raise NoCommandsDefined.new unless commands
|
309
|
+
@@global_options, cmd_name, @@command_options, argv = process_arguments(argv)
|
64
310
|
|
65
|
-
|
66
|
-
global_options = global_options.keys.inject({}) do |hash, key|
|
67
|
-
hash[key.to_sym] = global_options[key]
|
68
|
-
hash
|
69
|
-
end
|
311
|
+
cmd_name ||= default_command
|
70
312
|
|
71
|
-
cmd_name = (argv.empty?) ? @default_command : argv.shift
|
72
313
|
raise UnknownCommand.new(cmd_name) unless command?(cmd_name)
|
73
314
|
|
74
|
-
|
75
|
-
|
315
|
+
stdin = (defined? @@stdin_block) ? @@stdin_block.call(stdin, []) : stdin
|
316
|
+
@@before_block.call if defined? @@before_block
|
76
317
|
|
77
|
-
|
78
|
-
command_options = command_options.keys.inject({}) do |hash, key|
|
79
|
-
hash[key.to_sym] = command_options[key]
|
80
|
-
hash
|
81
|
-
end
|
318
|
+
call_command(cmd_name, argv, stdin)
|
82
319
|
|
83
|
-
|
320
|
+
@@after_block.call if defined? @@after_block
|
321
|
+
|
322
|
+
rescue OptionParser::InvalidOption => ex
|
323
|
+
raise Drydock::InvalidArgument.new(ex.args)
|
324
|
+
rescue OptionParser::MissingArgument => ex
|
325
|
+
raise Drydock::MissingArgument.new(ex.args)
|
84
326
|
end
|
85
327
|
|
86
|
-
|
328
|
+
private
|
87
329
|
|
88
|
-
|
89
|
-
|
330
|
+
# Executes the block associated to +cmd+
|
331
|
+
def call_command(cmd, argv=[], stdin=nil)
|
332
|
+
return unless command?(cmd)
|
333
|
+
get_command(cmd).call(cmd, argv, stdin, @@global_options || {}, @@command_options || {})
|
90
334
|
end
|
91
335
|
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
@command_index ||= 0
|
98
|
-
(@command_opts_parser[@command_index] ||= OptionParser.new)
|
99
|
-
end
|
336
|
+
# Returns the Drydock::Command object with the name +cmd+
|
337
|
+
def get_command(cmd)
|
338
|
+
return unless command?(cmd)
|
339
|
+
@@commands[canonize(cmd)]
|
340
|
+
end
|
100
341
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
342
|
+
# Returns true if a command with the name +cmd+ has been defined.
|
343
|
+
def command?(cmd)
|
344
|
+
name = canonize(cmd)
|
345
|
+
(@@commands || {}).has_key? name
|
105
346
|
end
|
106
347
|
|
107
|
-
|
108
|
-
|
109
|
-
|
348
|
+
# Canonizes a string to the symbol format for command names
|
349
|
+
def canonize(cmd)
|
350
|
+
return unless cmd
|
351
|
+
return cmd if cmd.kind_of?(Symbol)
|
352
|
+
cmd.tr('-', '_').to_sym
|
110
353
|
end
|
111
354
|
|
112
|
-
# option_parser
|
113
|
-
#
|
114
355
|
# Processes calls to option and global_option. Symbols are converted into
|
115
|
-
# OptionParser style strings (:h and :help become '-h' and '--help').
|
116
|
-
# class is included, it will tell OptionParser to expect a value otherwise
|
117
|
-
# it assumes a boolean value.
|
118
|
-
#
|
119
|
-
# +args+ is passed directly to OptionParser.on so it can contain anything
|
120
|
-
# that's valid to that method. Some examples:
|
121
|
-
# [:h, :help, "Displays this message"]
|
122
|
-
# [:m, :max, Integer, "Maximum threshold"]
|
123
|
-
# ['-l x,y,z', '--lang=x,y,z', Array, "Requested languages"]
|
356
|
+
# OptionParser style strings (:h and :help become '-h' and '--help').
|
124
357
|
def option_parser(args=[], &b)
|
125
358
|
return if args.empty?
|
126
359
|
opts_parser = args.shift
|
127
360
|
|
361
|
+
arg_name = ''
|
128
362
|
symbol_switches = []
|
129
363
|
args.each_with_index do |arg, index|
|
130
364
|
if arg.is_a? Symbol
|
365
|
+
arg_name = arg.to_s if arg.to_s.size > arg_name.size
|
131
366
|
args[index] = (arg.to_s.length == 1) ? "-#{arg.to_s}" : "--#{arg.to_s}"
|
132
367
|
symbol_switches << args[index]
|
133
368
|
elsif arg.kind_of?(Class)
|
@@ -145,88 +380,103 @@ module Drydock
|
|
145
380
|
result = (b.nil?) ? v : b.call(*block_args[0..(b.arity-1)])
|
146
381
|
end
|
147
382
|
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def command(*cmds, &b)
|
151
|
-
@command_index ||= 0
|
152
|
-
@command_opts_parser ||= []
|
153
|
-
cmds.each do |cmd|
|
154
|
-
c = Command.new(cmd, @command_index, &b)
|
155
|
-
(@commands ||= {})[cmd] = c
|
156
|
-
end
|
157
383
|
|
158
|
-
|
384
|
+
arg_name
|
159
385
|
end
|
160
386
|
|
161
|
-
def alias_command(aliaz, cmd)
|
162
|
-
return unless @commands.has_key? cmd
|
163
|
-
@commands[aliaz] = @commands[cmd]
|
164
|
-
end
|
165
387
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
388
|
+
# Split the +argv+ array into global args and command args and
|
389
|
+
# find the command name.
|
390
|
+
# i.e. ./script -H push -f (-H is a global arg, push is the command, -f is a command arg)
|
391
|
+
# returns [global_options, cmd, command_options, argv]
|
392
|
+
def process_arguments(argv=[])
|
393
|
+
global_options = command_options = {}
|
394
|
+
cmd = nil
|
171
395
|
|
396
|
+
global_options = global_opts_parser.getopts(argv)
|
397
|
+
|
398
|
+
cmd_name = (argv.empty?) ? @@default_command : argv.shift
|
172
399
|
raise UnknownCommand.new(cmd_name) unless command?(cmd_name)
|
173
400
|
|
174
|
-
|
175
|
-
@before_block.call if defined? @before_block
|
401
|
+
cmd = get_command(cmd_name)
|
176
402
|
|
403
|
+
command_parser = @@command_opts_parser[get_command_index(cmd_name)]
|
404
|
+
command_options = {}
|
177
405
|
|
178
|
-
|
406
|
+
# We only need to parse the options out of the arguments when
|
407
|
+
# there are args available, there is a valid parser, and
|
408
|
+
# we weren't requested to ignore the options.
|
409
|
+
if !argv.empty? && command_parser && command_parser != :ignore
|
410
|
+
command_options = command_parser.getopts(argv)
|
411
|
+
end
|
179
412
|
|
413
|
+
# Add accessors to the Drydock::Command object
|
414
|
+
# for the global and command specific options
|
415
|
+
[global_option_names, (command_option_names[get_command_index(cmd_name)] || [])].flatten.each do |n|
|
416
|
+
unless cmd.respond_to?(n)
|
417
|
+
cmd.class.send(:define_method, n) do
|
418
|
+
instance_variable_get("@#{n}")
|
419
|
+
end
|
420
|
+
end
|
421
|
+
unless cmd.respond_to?("#{n}=")
|
422
|
+
cmd.class.send(:define_method, "#{n}=") do |val|
|
423
|
+
instance_variable_set("@#{n}", val)
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
180
427
|
|
181
|
-
|
182
|
-
raise Drydock::InvalidArgument.new(ex.args)
|
183
|
-
rescue OptionParser::MissingArgument => ex
|
184
|
-
raise Drydock::MissingArgument.new(ex.args)
|
428
|
+
[global_options, cmd_name, command_options, argv]
|
185
429
|
end
|
186
430
|
|
187
|
-
|
188
|
-
|
189
|
-
return unless command?(cmd_str)
|
190
|
-
get_command(cmd_str).call(cmd_str, argv, stdin, @global_options, @command_options)
|
431
|
+
def global_option_names
|
432
|
+
@@global_option_names ||= []
|
191
433
|
end
|
192
434
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
435
|
+
# Grab the current list of command-specific option names. This is a list of the
|
436
|
+
# long names.
|
437
|
+
def current_command_option_names
|
438
|
+
@@command_option_names ||= []
|
439
|
+
@@command_index ||= 0
|
440
|
+
(@@command_option_names[@@command_index] ||= [])
|
441
|
+
end
|
197
442
|
|
198
|
-
def
|
199
|
-
|
443
|
+
def command_index_map
|
444
|
+
@@command_index_map ||= {}
|
200
445
|
end
|
201
446
|
|
202
|
-
def
|
203
|
-
|
447
|
+
def get_command_index(cmd)
|
448
|
+
command_index_map[canonize(cmd)] || -1
|
204
449
|
end
|
205
450
|
|
206
|
-
def
|
207
|
-
|
451
|
+
def command_option_names
|
452
|
+
@@command_option_names ||= []
|
208
453
|
end
|
209
454
|
|
210
|
-
def
|
211
|
-
|
212
|
-
(@commands || {}).has_key? name
|
455
|
+
def global_opts_parser
|
456
|
+
@@global_opts_parser ||= OptionParser.new
|
213
457
|
end
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
cmd.tr('-', '_').to_sym
|
458
|
+
|
459
|
+
def default_command
|
460
|
+
@@default_command ||= nil
|
218
461
|
end
|
219
462
|
|
220
463
|
end
|
221
464
|
|
222
|
-
Drydock
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
end_eval
|
465
|
+
include Drydock
|
466
|
+
|
467
|
+
trap ("SIGINT") do
|
468
|
+
puts "#{$/}Exiting..."
|
469
|
+
exit 1
|
228
470
|
end
|
229
471
|
|
230
472
|
|
473
|
+
at_exit {
|
474
|
+
begin
|
475
|
+
Drydock.run!(ARGV, STDIN) if Drydock.run? && !Drydock.has_run?
|
476
|
+
rescue => ex
|
477
|
+
STDERR.puts "ERROR: #{ex.message}"
|
478
|
+
STDERR.puts ex.backtrace if Drydock.debug?
|
479
|
+
end
|
480
|
+
}
|
231
481
|
|
232
482
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../lib/drydock"
|
2
|
+
require "rubygems"
|
3
|
+
require "test/spec"
|
4
|
+
require "mocha"
|
5
|
+
|
6
|
+
class Test::Unit::TestCase
|
7
|
+
def test_command_direct(cmd, argv, &b)
|
8
|
+
Drydock::Command.new(cmd, &b).call(*argv)
|
9
|
+
end
|
10
|
+
def test_command(*args, &b)
|
11
|
+
command(*args, &b)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class JohnWestSmokedOysters < Drydock::Command; end;
|
16
|
+
|
17
|
+
Drydock.run = false
|
18
|
+
|
19
|
+
context "command" do
|
20
|
+
|
21
|
+
setup do
|
22
|
+
@mock = mock()
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should know a command alias" do
|
26
|
+
@mock.expects(:called).with(:eat_alias)
|
27
|
+
test_command_direct(:eat, [:eat_alias]) { |obj,argv|
|
28
|
+
@mock.called(obj.alias)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "should accept a custom command class" do
|
33
|
+
@mock.expects(:called).with(JohnWestSmokedOysters)
|
34
|
+
test_command(:eat => JohnWestSmokedOysters) { |obj,argv|
|
35
|
+
@mock.called(obj.class)
|
36
|
+
}
|
37
|
+
Drydock.run!(['eat'])
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
metadata
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delano-drydock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delano Mandelbaum
|
8
|
-
- Blake Mizerany
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
@@ -14,7 +13,7 @@ date: 2008-08-17 00:00:00 -07:00
|
|
14
13
|
default_executable:
|
15
14
|
dependencies: []
|
16
15
|
|
17
|
-
description:
|
16
|
+
description: A seaworthy DSL for writing command line apps inspired by Blake Mizerany's Frylock
|
18
17
|
email: delano@solutious.com
|
19
18
|
executables: []
|
20
19
|
|
@@ -23,12 +22,39 @@ extensions: []
|
|
23
22
|
extra_rdoc_files:
|
24
23
|
- README.rdoc
|
25
24
|
- LICENSE.txt
|
25
|
+
- CHANGES.txt
|
26
26
|
files:
|
27
|
+
- CHANGES.txt
|
27
28
|
- LICENSE.txt
|
28
29
|
- README.rdoc
|
30
|
+
- Rakefile
|
29
31
|
- bin/example
|
30
|
-
-
|
32
|
+
- drydock.gemspec
|
31
33
|
- lib/drydock.rb
|
34
|
+
- test/command_test.rb
|
35
|
+
- doc
|
36
|
+
- doc/classes
|
37
|
+
- doc/classes/Drydock
|
38
|
+
- doc/classes/Drydock/Command.html
|
39
|
+
- doc/classes/Drydock/InvalidArgument.html
|
40
|
+
- doc/classes/Drydock/MissingArgument.html
|
41
|
+
- doc/classes/Drydock/NoCommandsDefined.html
|
42
|
+
- doc/classes/Drydock/UnknownCommand.html
|
43
|
+
- doc/classes/Drydock.html
|
44
|
+
- doc/created.rid
|
45
|
+
- doc/files
|
46
|
+
- doc/files/bin
|
47
|
+
- doc/files/bin/example.html
|
48
|
+
- doc/files/CHANGES_txt.html
|
49
|
+
- doc/files/lib
|
50
|
+
- doc/files/lib/drydock_rb.html
|
51
|
+
- doc/files/LICENSE_txt.html
|
52
|
+
- doc/files/README_rdoc.html
|
53
|
+
- doc/fr_class_index.html
|
54
|
+
- doc/fr_file_index.html
|
55
|
+
- doc/fr_method_index.html
|
56
|
+
- doc/index.html
|
57
|
+
- doc/rdoc-style.css
|
32
58
|
has_rdoc: true
|
33
59
|
homepage: http://github.com/delano/drydock
|
34
60
|
post_install_message:
|
@@ -36,7 +62,7 @@ rdoc_options:
|
|
36
62
|
- --line-numbers
|
37
63
|
- --inline-source
|
38
64
|
- --title
|
39
|
-
- "Drydock:
|
65
|
+
- "Drydock: a seaworthy DSL for command-line apps"
|
40
66
|
- --main
|
41
67
|
- README.rdoc
|
42
68
|
require_paths:
|
@@ -55,10 +81,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
81
|
version:
|
56
82
|
requirements: []
|
57
83
|
|
58
|
-
rubyforge_project:
|
84
|
+
rubyforge_project: drydock
|
59
85
|
rubygems_version: 1.2.0
|
60
86
|
signing_key:
|
61
87
|
specification_version: 1
|
62
|
-
summary:
|
88
|
+
summary: A seaworthy DSL for writing command line apps
|
63
89
|
test_files: []
|
64
90
|
|
data/lib/drydock/exceptions.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
module Drylock
|
2
|
-
|
3
|
-
class UnknownCommand < RuntimeError
|
4
|
-
attr_reader :name
|
5
|
-
def initialize(name)
|
6
|
-
@name = name || :unknown
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
class NoCommandsDefined < RuntimeError
|
11
|
-
end
|
12
|
-
|
13
|
-
class InvalidArgument < RuntimeError
|
14
|
-
attr_accessor :args
|
15
|
-
def initialize(args)
|
16
|
-
# We grab just the name of the argument
|
17
|
-
@args = args || []
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class MissingArgument < InvalidArgument
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|