delano-drydock 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.
- data/LICENSE.txt +22 -0
- data/README.rdoc +57 -0
- data/bin/example +170 -0
- data/lib/drydock/exceptions.rb +24 -0
- data/lib/drydock.rb +232 -0
- metadata +64 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2008 Delano Mandelbaum
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
= Drydock - Easy Command line apps
|
2
|
+
|
3
|
+
Inspired by "github-gem":http://github.com/defunkt/github-gem
|
4
|
+
|
5
|
+
Inspired by "bmizerany-frylock":http://github.com/bmizerany/frylock/tree
|
6
|
+
|
7
|
+
== Overview
|
8
|
+
|
9
|
+
Drydock is a DSL for command line apps.
|
10
|
+
|
11
|
+
== Install
|
12
|
+
|
13
|
+
git clone git://github.com/delano/drydock.git
|
14
|
+
|
15
|
+
|
16
|
+
== Examples
|
17
|
+
|
18
|
+
See bin/example for more.
|
19
|
+
|
20
|
+
<pre><code>
|
21
|
+
require 'rubygems'
|
22
|
+
require 'drydock'
|
23
|
+
|
24
|
+
default :welcome
|
25
|
+
|
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
|
+
|
31
|
+
command :welcome do
|
32
|
+
# Example: ruby bin/example
|
33
|
+
|
34
|
+
puts "Meatwad: Science is a mystery to man, isn't it Frylock?"
|
35
|
+
print "Frylock: At least we have some commands: "
|
36
|
+
|
37
|
+
# The commands method returns a hash of Frylock::Command objects
|
38
|
+
puts commands.keys.inject([]) { |list, command| list << command.to_s }.sort.join(', ')
|
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
|
45
|
+
|
46
|
+
puts "Frylock: So, did they ever find your car?"
|
47
|
+
|
48
|
+
# The keys to the hash are the long string from the option definition.
|
49
|
+
# If only the short string is provided, those will be used instead (i.e. :f).
|
50
|
+
puts (!options[:found]) ? "Carl: No" :
|
51
|
+
"Carl: Oh, they found part of it, hangin' from a trestle near the turnpike."
|
52
|
+
end
|
53
|
+
</code></pre>
|
54
|
+
|
55
|
+
== License
|
56
|
+
|
57
|
+
See LICENSE.txt
|
data/bin/example
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
DRYDOCK_HOME = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
4
|
+
$: << File.join(DRYDOCK_HOME, 'lib')
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'drydock'
|
8
|
+
|
9
|
+
default :welcome
|
10
|
+
|
11
|
+
|
12
|
+
before do
|
13
|
+
# You can execute a block before the requests command is executed. Instance
|
14
|
+
# variables defined here will be available to all commands.
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
command :welcome do
|
19
|
+
# Example: ruby bin/example
|
20
|
+
|
21
|
+
puts "Meatwad: Science is a mystery to man, isn't it Frylock?"
|
22
|
+
print "Frylock: At least we have some commands: "
|
23
|
+
|
24
|
+
# The commands method returns a hash of Drydock::Command objects
|
25
|
+
puts commands.keys.inject([]) { |list, command| list << command.to_s }.sort.join(', ')
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
option :f, :found, "A boolean value. Did you find the car?"
|
30
|
+
command :findcar do |options|
|
31
|
+
# +options+ is a hash containing the options defined above
|
32
|
+
# Example: ruby bin/example -f findcar
|
33
|
+
|
34
|
+
puts "Frylock: So, did they ever find your car?"
|
35
|
+
|
36
|
+
# The keys to the hash are the long string from the option definition.
|
37
|
+
# If only the short string is provided, those will be used instead (i.e. :f).
|
38
|
+
puts (!options[:found]) ? "Carl: No" :
|
39
|
+
"Carl: Oh, they found part of it, hangin' from a trestle near the turnpike."
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
global_usage "USAGE: #{File.basename($0)} [global options] command [command options]"
|
45
|
+
global_option :s, :seconds, "Display values in seconds"
|
46
|
+
global_option :v, :verbose, "Verbosity level (i.e. -vvv is greater than -v)" do |v|
|
47
|
+
# Use instance variables to maintain values between option blocks.
|
48
|
+
# This will increment for every -v found (i.e. -vvv)
|
49
|
+
@val ||= 0
|
50
|
+
@val += 1
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
usage "ruby bin/example [--seconds] [-vv] time"
|
55
|
+
command :date do |options, argv, global_options|
|
56
|
+
# +argv+ contains the unnamed arguments
|
57
|
+
# +global_options+ contains hash of the options defined with global_options
|
58
|
+
|
59
|
+
require 'time'
|
60
|
+
now = Time.now
|
61
|
+
puts "More verbosely, the date is now: " if (global_options[:verbose] || 0) >= 2
|
62
|
+
puts (global_options[:seconds]) ? now.to_i : now.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
option :c, :check, "Check response codes for each URI"
|
67
|
+
option :d, :delim, String, "Output delimiter"
|
68
|
+
option :t, :timeout, Float, "Timeout value for HTTP request" do |v|
|
69
|
+
# You can provide an block to process the option value.
|
70
|
+
# This block must return the final value.
|
71
|
+
v = 10 if (v > 10)
|
72
|
+
v
|
73
|
+
end
|
74
|
+
|
75
|
+
usage 'echo "http://github.com/" | ruby bin/example process -c -d " " -t 15 http://solutious.com/'
|
76
|
+
command :processuris do |options, argv, global_options, stdin, cmd|
|
77
|
+
# +stdin+ is either an IO object or a custom object defined with a stdin block (see below)
|
78
|
+
# +cmd+ is the string used to evoke this command. Useful with alias_command (see below).
|
79
|
+
|
80
|
+
require 'net/http'
|
81
|
+
require 'uri'
|
82
|
+
require 'timeout'
|
83
|
+
|
84
|
+
uris = [stdin, argv].flatten # Combine the argv and stdin arrays
|
85
|
+
delim = options[:delim] || ','
|
86
|
+
timeout = options[:timeout] || 5
|
87
|
+
code = :notchecked # The default code when :check is false
|
88
|
+
|
89
|
+
if uris.empty?
|
90
|
+
puts "Frylock: You didn't provide any URIs. "
|
91
|
+
puts "Master Shake: Ya, see #{$0} #{cmd} -h"
|
92
|
+
exit 0
|
93
|
+
end
|
94
|
+
|
95
|
+
uris.each_with_index do |uri, index|
|
96
|
+
code = response_code(uri, timeout) if (options[:check])
|
97
|
+
puts [index+1, uri, code].join(delim)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
alias_command :process, :processuris
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
stdin do |stdin, output|
|
106
|
+
# Pre-process STDIN for all commands. This example returns an array of lines.
|
107
|
+
# The command processuris uses this array.
|
108
|
+
|
109
|
+
# We only want piped data. If this is not included
|
110
|
+
# execution will wait for input from the user.
|
111
|
+
unless stdin.tty?
|
112
|
+
|
113
|
+
while !stdin.eof? do
|
114
|
+
line = stdin.readline
|
115
|
+
line.chomp!
|
116
|
+
(output ||= []) << line
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
output
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
# response_code
|
126
|
+
#
|
127
|
+
# return the HTTP response code for the given URI
|
128
|
+
# +uri+ A valid HTTP URI
|
129
|
+
# +duration+ The timeout threshold (in seconds) for the request.
|
130
|
+
def response_code(uri_str, duration=5)
|
131
|
+
response = :unavailable
|
132
|
+
begin
|
133
|
+
uri = (uri_str.kind_of? URI::HTTP) ? uri_str : URI.parse(uri_str)
|
134
|
+
timeout(duration) do
|
135
|
+
response = Net::HTTP.get_response(uri).code
|
136
|
+
end
|
137
|
+
rescue Exception => ex
|
138
|
+
end
|
139
|
+
response
|
140
|
+
end
|
141
|
+
|
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
|
@@ -0,0 +1,24 @@
|
|
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
|
data/lib/drydock.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
require 'drydock/exceptions'
|
6
|
+
|
7
|
+
module Drydock
|
8
|
+
class Command
|
9
|
+
attr_reader :cmd, :index
|
10
|
+
def initialize(cmd, index, &b)
|
11
|
+
@cmd = (cmd.kind_of?(Symbol)) ? cmd.to_s : cmd
|
12
|
+
@index = index
|
13
|
+
@b = b
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(cmd_str, argv, stdin, global_options, options)
|
17
|
+
block_args = [options, argv, global_options, stdin, cmd_str, self]
|
18
|
+
@b.call(*block_args[0..(@b.arity-1)])
|
19
|
+
end
|
20
|
+
def to_s
|
21
|
+
@cmd.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Drydock
|
27
|
+
extend self
|
28
|
+
|
29
|
+
FORWARDED_METHODS = %w(command before alias_command global_option global_usage usage option stdin default commands).freeze
|
30
|
+
|
31
|
+
def default(cmd)
|
32
|
+
@default_command = canonize(cmd)
|
33
|
+
end
|
34
|
+
|
35
|
+
def stdin(&b)
|
36
|
+
@stdin_block = b
|
37
|
+
end
|
38
|
+
def before(&b)
|
39
|
+
@before_block = b
|
40
|
+
end
|
41
|
+
|
42
|
+
# global_usage
|
43
|
+
# ex: usage "Usage: frylla [global options] command [command options]"
|
44
|
+
def global_usage(msg)
|
45
|
+
@global_opts_parser ||= OptionParser.new
|
46
|
+
@global_options ||= OpenStruct.new
|
47
|
+
|
48
|
+
@global_opts_parser.banner = msg
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
# process_arguments
|
54
|
+
#
|
55
|
+
# Split the +argv+ array into global args and command args and
|
56
|
+
# find the command name.
|
57
|
+
# i.e. ./script -H push -f (-H is a global arg, push is the command, -f is a command arg)
|
58
|
+
# returns [global_options, cmd, command_options, argv]
|
59
|
+
def process_arguments(argv)
|
60
|
+
global_options = command_options = {}
|
61
|
+
cmd = nil
|
62
|
+
|
63
|
+
global_parser = @global_opts_parser
|
64
|
+
|
65
|
+
global_options = global_parser.getopts(argv)
|
66
|
+
global_options = global_options.keys.inject({}) do |hash, key|
|
67
|
+
hash[key.to_sym] = global_options[key]
|
68
|
+
hash
|
69
|
+
end
|
70
|
+
|
71
|
+
cmd_name = (argv.empty?) ? @default_command : argv.shift
|
72
|
+
raise UnknownCommand.new(cmd_name) unless command?(cmd_name)
|
73
|
+
|
74
|
+
cmd = get_command(cmd_name)
|
75
|
+
command_parser = @command_opts_parser[cmd.index]
|
76
|
+
|
77
|
+
command_options = command_parser.getopts(argv) if (!argv.empty? && command_parser)
|
78
|
+
command_options = command_options.keys.inject({}) do |hash, key|
|
79
|
+
hash[key.to_sym] = command_options[key]
|
80
|
+
hash
|
81
|
+
end
|
82
|
+
|
83
|
+
[global_options, cmd_name, command_options, argv]
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
def usage(msg)
|
89
|
+
get_current_option_parser.banner = msg
|
90
|
+
end
|
91
|
+
|
92
|
+
# get_current_option_parser
|
93
|
+
#
|
94
|
+
# Grab the options parser for the current command or create it if it doesn't exist.
|
95
|
+
def get_current_option_parser
|
96
|
+
@command_opts_parser ||= []
|
97
|
+
@command_index ||= 0
|
98
|
+
(@command_opts_parser[@command_index] ||= OptionParser.new)
|
99
|
+
end
|
100
|
+
|
101
|
+
def global_option(*args, &b)
|
102
|
+
@global_opts_parser ||= OptionParser.new
|
103
|
+
args.unshift(@global_opts_parser)
|
104
|
+
option_parser(args, &b)
|
105
|
+
end
|
106
|
+
|
107
|
+
def option(*args, &b)
|
108
|
+
args.unshift(get_current_option_parser)
|
109
|
+
option_parser(args, &b)
|
110
|
+
end
|
111
|
+
|
112
|
+
# option_parser
|
113
|
+
#
|
114
|
+
# Processes calls to option and global_option. Symbols are converted into
|
115
|
+
# OptionParser style strings (:h and :help become '-h' and '--help'). If a
|
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"]
|
124
|
+
def option_parser(args=[], &b)
|
125
|
+
return if args.empty?
|
126
|
+
opts_parser = args.shift
|
127
|
+
|
128
|
+
symbol_switches = []
|
129
|
+
args.each_with_index do |arg, index|
|
130
|
+
if arg.is_a? Symbol
|
131
|
+
args[index] = (arg.to_s.length == 1) ? "-#{arg.to_s}" : "--#{arg.to_s}"
|
132
|
+
symbol_switches << args[index]
|
133
|
+
elsif arg.kind_of?(Class)
|
134
|
+
symbol_switches.each do |arg|
|
135
|
+
arg << "=S"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
if args.size == 1
|
141
|
+
opts_parser.on(args.shift)
|
142
|
+
else
|
143
|
+
opts_parser.on(*args) do |v|
|
144
|
+
block_args = [v, opts_parser]
|
145
|
+
result = (b.nil?) ? v : b.call(*block_args[0..(b.arity-1)])
|
146
|
+
end
|
147
|
+
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
|
+
|
158
|
+
@command_index += 1
|
159
|
+
end
|
160
|
+
|
161
|
+
def alias_command(aliaz, cmd)
|
162
|
+
return unless @commands.has_key? cmd
|
163
|
+
@commands[aliaz] = @commands[cmd]
|
164
|
+
end
|
165
|
+
|
166
|
+
def run!(argv, stdin=nil)
|
167
|
+
raise NoCommandsDefined.new unless @commands
|
168
|
+
@global_options, cmd_name, @command_options, argv = process_arguments(argv)
|
169
|
+
|
170
|
+
cmd_name ||= @default_command
|
171
|
+
|
172
|
+
raise UnknownCommand.new(cmd_name) unless command?(cmd_name)
|
173
|
+
|
174
|
+
stdin = (defined? @stdin_block) ? @stdin_block.call(stdin, []) : stdin
|
175
|
+
@before_block.call if defined? @before_block
|
176
|
+
|
177
|
+
|
178
|
+
call_command(cmd_name, argv, stdin)
|
179
|
+
|
180
|
+
|
181
|
+
rescue OptionParser::InvalidOption => ex
|
182
|
+
raise Drydock::InvalidArgument.new(ex.args)
|
183
|
+
rescue OptionParser::MissingArgument => ex
|
184
|
+
raise Drydock::MissingArgument.new(ex.args)
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def call_command(cmd_str, argv=[], stdin=nil)
|
189
|
+
return unless command?(cmd_str)
|
190
|
+
get_command(cmd_str).call(cmd_str, argv, stdin, @global_options, @command_options)
|
191
|
+
end
|
192
|
+
|
193
|
+
def get_command(cmd)
|
194
|
+
return unless command?(cmd)
|
195
|
+
@commands[canonize(cmd)]
|
196
|
+
end
|
197
|
+
|
198
|
+
def commands
|
199
|
+
@commands
|
200
|
+
end
|
201
|
+
|
202
|
+
def run
|
203
|
+
@run || true
|
204
|
+
end
|
205
|
+
|
206
|
+
def run=(v)
|
207
|
+
@run = v
|
208
|
+
end
|
209
|
+
|
210
|
+
def command?(cmd)
|
211
|
+
name = canonize(cmd)
|
212
|
+
(@commands || {}).has_key? name
|
213
|
+
end
|
214
|
+
def canonize(cmd)
|
215
|
+
return unless cmd
|
216
|
+
return cmd if cmd.kind_of?(Symbol)
|
217
|
+
cmd.tr('-', '_').to_sym
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
Drydock::FORWARDED_METHODS.each do |m|
|
223
|
+
eval(<<-end_eval, binding, "(Drydock)", __LINE__)
|
224
|
+
def #{m}(*args, &b)
|
225
|
+
Drydock.#{m}(*args, &b)
|
226
|
+
end
|
227
|
+
end_eval
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
|
232
|
+
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: delano-drydock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Delano Mandelbaum
|
8
|
+
- Blake Mizerany
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2008-08-17 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: Command line apps made easy
|
18
|
+
email: delano@solutious.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- README.rdoc
|
25
|
+
- LICENSE.txt
|
26
|
+
files:
|
27
|
+
- LICENSE.txt
|
28
|
+
- README.rdoc
|
29
|
+
- bin/example
|
30
|
+
- lib/drydock/exceptions.rb
|
31
|
+
- lib/drydock.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/delano/drydock
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options:
|
36
|
+
- --line-numbers
|
37
|
+
- --inline-source
|
38
|
+
- --title
|
39
|
+
- "Drydock: Easy command-line apps"
|
40
|
+
- --main
|
41
|
+
- README.rdoc
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.2.0
|
60
|
+
signing_key:
|
61
|
+
specification_version: 1
|
62
|
+
summary: Command line apps made easy
|
63
|
+
test_files: []
|
64
|
+
|