delano-rye 0.3.2
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/CHANGES.txt +34 -0
- data/LICENSE.txt +19 -0
- data/README.rdoc +185 -0
- data/Rakefile +83 -0
- data/bin/try +148 -0
- data/lib/esc.rb +301 -0
- data/lib/rye.rb +155 -0
- data/lib/rye/box.rb +312 -0
- data/lib/rye/cmd.rb +59 -0
- data/lib/rye/rap.rb +83 -0
- data/lib/rye/set.rb +147 -0
- data/lib/sys.rb +274 -0
- data/rye.gemspec +56 -0
- data/test/10_rye_test.rb +63 -0
- metadata +90 -0
data/lib/rye/set.rb
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module Rye
|
|
2
|
+
|
|
3
|
+
# = Rye::Set
|
|
4
|
+
#
|
|
5
|
+
#
|
|
6
|
+
class Set
|
|
7
|
+
attr_reader :name
|
|
8
|
+
attr_reader :boxes
|
|
9
|
+
|
|
10
|
+
# * +name+ The name of the set of machines
|
|
11
|
+
# * +opts+ a hash of optional arguments
|
|
12
|
+
#
|
|
13
|
+
# The +opts+ hash is used as defaults for all for all Rye::Box objects.
|
|
14
|
+
# All args supported by Rye::Box are available here with the addition of:
|
|
15
|
+
#
|
|
16
|
+
# * :parallel => run the commands in parallel? true or false (default).
|
|
17
|
+
#
|
|
18
|
+
def initialize(name='default', opts={})
|
|
19
|
+
@name = name
|
|
20
|
+
@boxes = []
|
|
21
|
+
|
|
22
|
+
# These opts are use by Rye::Box and also passed to Net::SSH
|
|
23
|
+
@opts = {
|
|
24
|
+
:parallel => false,
|
|
25
|
+
:user => Rye.sysinfo.user,
|
|
26
|
+
:safe => true,
|
|
27
|
+
:port => 22,
|
|
28
|
+
:keys => [],
|
|
29
|
+
:password => nil,
|
|
30
|
+
:proxy => nil,
|
|
31
|
+
:debug => nil,
|
|
32
|
+
:error => STDERR,
|
|
33
|
+
}.merge(opts)
|
|
34
|
+
|
|
35
|
+
@parallel = @opts.delete(:parallel) # Rye::Box doesn't have :parallel
|
|
36
|
+
|
|
37
|
+
@safe = @opts.delete(:safe)
|
|
38
|
+
@debug = @opts.delete(:debug)
|
|
39
|
+
@error = @opts.delete(:error)
|
|
40
|
+
|
|
41
|
+
add_keys(@opts[:keys])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# * +boxes+ one or more boxes. Rye::Box objects will be added directly
|
|
45
|
+
# to the set. Hostnames will be used to create new instances of Rye::Box
|
|
46
|
+
# and those will be added to the list.
|
|
47
|
+
def add_box(*boxes)
|
|
48
|
+
boxes = boxes.flatten.compact
|
|
49
|
+
@boxes += boxes.collect do |box|
|
|
50
|
+
box.is_a?(Rye::Box) ? box.add_keys(@keys) : Rye::Box.new(box, @opts)
|
|
51
|
+
end
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
alias :add_boxes :add_box
|
|
55
|
+
|
|
56
|
+
# Add one or more private keys to the SSH Agent.
|
|
57
|
+
# * +additional_keys+ is a list of file paths to private keys
|
|
58
|
+
# Returns the instance of Rye::Set
|
|
59
|
+
def add_key(*additional_keys)
|
|
60
|
+
additional_keys = [additional_keys].flatten.compact || []
|
|
61
|
+
Rye.add_keys(additional_keys)
|
|
62
|
+
self
|
|
63
|
+
end
|
|
64
|
+
alias :add_keys :add_key
|
|
65
|
+
|
|
66
|
+
# Add an environment variable. +n+ and +v+ are the name and value.
|
|
67
|
+
# Returns the instance of Rye::Set
|
|
68
|
+
def add_env(n, v)
|
|
69
|
+
run_command(:add_env, n, v)
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
alias :add_environment_variable :add_env
|
|
73
|
+
|
|
74
|
+
# See Rye.keys
|
|
75
|
+
def keys
|
|
76
|
+
Rye.keys
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# See Rye::Box.[]
|
|
80
|
+
def [](key=nil)
|
|
81
|
+
run_command(:cd, key)
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
alias :cd :'[]'
|
|
85
|
+
|
|
86
|
+
# Catches calls to Rye::Box commands. If +meth+ is the name of an
|
|
87
|
+
# instance method defined in Rye::Cmd then we call it against all
|
|
88
|
+
# the boxes in +@boxes+. Otherwise this method raises a
|
|
89
|
+
# Rye::CommandNotFound exception. It will also raise a Rye::NoBoxes
|
|
90
|
+
# exception if this set has no boxes defined.
|
|
91
|
+
#
|
|
92
|
+
# Returns a Rye::Rap object containing the responses from each Rye::Box.
|
|
93
|
+
def method_missing(meth, *args)
|
|
94
|
+
# Ruby 1.8 populates Module.instance_methods with Strings. 1.9 uses Symbols.
|
|
95
|
+
meth = (Rye.sysinfo.ruby[1] == 8) ? meth.to_s : meth.to_sym
|
|
96
|
+
raise Rye::NoBoxes if @boxes.empty?
|
|
97
|
+
raise Rye::CommandNotFound, meth.to_s unless Rye::Cmd.instance_methods.member?(meth)
|
|
98
|
+
run_command(meth, *args)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# Determines whether to call the serial or parallel method, then calls it.
|
|
104
|
+
def run_command(meth, *args)
|
|
105
|
+
runner = @parallel ? :run_command_parallel : :run_command_serial
|
|
106
|
+
self.send(runner, meth, *args)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# Run the command on all boxes in parallel
|
|
111
|
+
def run_command_parallel(meth, *args)
|
|
112
|
+
debug "P: #{meth} on #{@boxes.size} boxes (#{@boxes.collect {|b| b.host }.join(', ')})"
|
|
113
|
+
threads = []
|
|
114
|
+
|
|
115
|
+
raps = Rye::Rap.new(self)
|
|
116
|
+
(@boxes || []).each do |box|
|
|
117
|
+
threads << Thread.new do
|
|
118
|
+
Thread.current[:rap] = box.send(meth, *args) # Store the result in the thread
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
threads.each do |t|
|
|
123
|
+
sleep 0.01 # Give the thread some breathing room
|
|
124
|
+
t.join # Wait for the thread to finish
|
|
125
|
+
raps << t[:rap] # Grab the result
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
raps
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# Run the command on all boxes in serial
|
|
133
|
+
def run_command_serial(meth, *args)
|
|
134
|
+
debug "S: #{meth} on #{@boxes.size} boxes (#{@boxes.collect {|b| b.host }.join(', ')})"
|
|
135
|
+
raps = Rye::Rap.new(self)
|
|
136
|
+
(@boxes || []).each do |box|
|
|
137
|
+
raps << box.send(meth, *args)
|
|
138
|
+
end
|
|
139
|
+
raps
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def debug(msg); @debug.puts msg if @debug; end
|
|
143
|
+
def error(msg); @error.puts msg if @error; end
|
|
144
|
+
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
end
|
data/lib/sys.rb
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
|
|
3
|
+
# SystemInfo
|
|
4
|
+
#
|
|
5
|
+
# A container for the platform specific system information.
|
|
6
|
+
# Portions of this code were originally from Amazon's EC2 AMI tools,
|
|
7
|
+
# specifically lib/platform.rb.
|
|
8
|
+
class SystemInfo #:nodoc:all
|
|
9
|
+
VERSION = 2
|
|
10
|
+
IMPLEMENTATIONS = [
|
|
11
|
+
|
|
12
|
+
# These are for JRuby, System.getproperty('os.name').
|
|
13
|
+
# For a list of all values, see: http://lopica.sourceforge.net/os.html
|
|
14
|
+
[/mac\s*os\s*x/i, :unix, :osx ],
|
|
15
|
+
[/sunos/i, :unix, :solaris ],
|
|
16
|
+
[/windows\s*ce/i, :win32, :windows ],
|
|
17
|
+
[/windows/i, :win32, :windows ],
|
|
18
|
+
[/osx/i, :unix, :osx ],
|
|
19
|
+
|
|
20
|
+
# TODO: implement other windows matches: # /djgpp|(cyg|ms|bcc)win|mingw/ (from mongrel)
|
|
21
|
+
|
|
22
|
+
# These are for RUBY_PLATFORM and JRuby
|
|
23
|
+
[/java/i, :java, :java ],
|
|
24
|
+
[/darwin/i, :unix, :osx ],
|
|
25
|
+
[/linux/i, :unix, :linux ],
|
|
26
|
+
[/freebsd/i, :unix, :freebsd ],
|
|
27
|
+
[/netbsd/i, :unix, :netbsd ],
|
|
28
|
+
[/solaris/i, :unix, :solaris ],
|
|
29
|
+
[/irix/i, :unix, :irix ],
|
|
30
|
+
[/cygwin/i, :unix, :cygwin ],
|
|
31
|
+
[/mswin/i, :win32, :windows ],
|
|
32
|
+
[/mingw/i, :win32, :mingw ],
|
|
33
|
+
[/bccwin/i, :win32, :bccwin ],
|
|
34
|
+
[/wince/i, :win32, :wince ],
|
|
35
|
+
[/vms/i, :vms, :vms ],
|
|
36
|
+
[/os2/i, :os2, :os2 ],
|
|
37
|
+
[nil, :unknown, :unknown ],
|
|
38
|
+
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
ARCHITECTURES = [
|
|
42
|
+
[/(i\d86)/i, :i386 ],
|
|
43
|
+
[/x86_64/i, :x86_64 ],
|
|
44
|
+
[/x86/i, :i386 ], # JRuby
|
|
45
|
+
[/ia64/i, :ia64 ],
|
|
46
|
+
[/alpha/i, :alpha ],
|
|
47
|
+
[/sparc/i, :sparc ],
|
|
48
|
+
[/mips/i, :mips ],
|
|
49
|
+
[/powerpc/i, :powerpc ],
|
|
50
|
+
[/universal/i,:universal ],
|
|
51
|
+
[nil, :unknown ],
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
attr_reader :os
|
|
57
|
+
attr_reader :implementation
|
|
58
|
+
attr_reader :architecture
|
|
59
|
+
attr_reader :hostname
|
|
60
|
+
attr_reader :ipaddress
|
|
61
|
+
attr_reader :uptime
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
alias :impl :implementation
|
|
65
|
+
alias :arch :architecture
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def initialize
|
|
69
|
+
@os, @implementation, @architecture = guess
|
|
70
|
+
@hostname, @ipaddress, @uptime = get_info
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# guess
|
|
74
|
+
#
|
|
75
|
+
# This is called at require-time in stella.rb. It guesses
|
|
76
|
+
# the current operating system, implementation, architecture.
|
|
77
|
+
# Returns [os, impl, arch]
|
|
78
|
+
def guess
|
|
79
|
+
os = :unknown
|
|
80
|
+
impl = :unknown
|
|
81
|
+
arch = :unknown
|
|
82
|
+
IMPLEMENTATIONS.each do |r, o, i|
|
|
83
|
+
if r and RUBY_PLATFORM =~ r
|
|
84
|
+
os, impl = [o, i]
|
|
85
|
+
break
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
ARCHITECTURES.each do |r, a|
|
|
89
|
+
if r and RUBY_PLATFORM =~ r
|
|
90
|
+
arch = a
|
|
91
|
+
break
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
#
|
|
96
|
+
if os == :win32
|
|
97
|
+
#require 'Win32API'
|
|
98
|
+
|
|
99
|
+
# If we're running in java, we'll need to look elsewhere
|
|
100
|
+
# for the implementation and architecture.
|
|
101
|
+
# We'll replace IMPL and ARCH with what we find.
|
|
102
|
+
elsif os == :java
|
|
103
|
+
require 'java'
|
|
104
|
+
include_class java.lang.System
|
|
105
|
+
|
|
106
|
+
osname = System.getProperty("os.name")
|
|
107
|
+
IMPLEMENTATIONS.each do |r, o, i|
|
|
108
|
+
if r and osname =~ r
|
|
109
|
+
impl = i
|
|
110
|
+
break
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
osarch = System.getProperty("os.arch")
|
|
115
|
+
ARCHITECTURES.each do |r, a|
|
|
116
|
+
if r and osarch =~ r
|
|
117
|
+
arch = a
|
|
118
|
+
break
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
[os, impl, arch]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# get_info
|
|
128
|
+
#
|
|
129
|
+
# Returns [hostname, ipaddr, uptime] for the local machine
|
|
130
|
+
def get_info
|
|
131
|
+
hostname = :unknown
|
|
132
|
+
ipaddr = :unknown
|
|
133
|
+
uptime = :unknown
|
|
134
|
+
|
|
135
|
+
begin
|
|
136
|
+
hostname = local_hostname
|
|
137
|
+
ipaddr = local_ip_address
|
|
138
|
+
uptime = local_uptime
|
|
139
|
+
rescue => ex
|
|
140
|
+
# Be silent!
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
[hostname, ipaddr, uptime]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# local_hostname
|
|
147
|
+
#
|
|
148
|
+
# Return the hostname for the local machine
|
|
149
|
+
def local_hostname
|
|
150
|
+
Socket.gethostname
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# local_uptime
|
|
154
|
+
#
|
|
155
|
+
# Returns the local uptime in hours. Use Win32API in Windows,
|
|
156
|
+
# 'sysctl -b kern.boottime' os osx, and 'who -b' on unix.
|
|
157
|
+
# Based on Ruby Quiz solutions by: Matthias Reitinger
|
|
158
|
+
# On Windows, see also: net statistics server
|
|
159
|
+
def local_uptime
|
|
160
|
+
|
|
161
|
+
# Each method must return uptime in seconds
|
|
162
|
+
methods = {
|
|
163
|
+
|
|
164
|
+
:win32_windows => lambda {
|
|
165
|
+
# Win32API is required in self.guess
|
|
166
|
+
getTickCount = Win32API.new("kernel32", "GetTickCount", nil, 'L')
|
|
167
|
+
((getTickCount.call()).to_f / 1000).to_f
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
# Ya, this is kinda wack. Ruby -> Java -> Kernel32. See:
|
|
171
|
+
# http://www.oreillynet.com/ruby/blog/2008/01/jruby_meets_the_windows_api_1.html
|
|
172
|
+
# http://msdn.microsoft.com/en-us/library/ms724408(VS.85).aspx
|
|
173
|
+
# Ruby 1.9.1: Win32API is now deprecated in favor of using the DL library.
|
|
174
|
+
:java_windows => lambda {
|
|
175
|
+
kernel32 = com.sun.jna.NativeLibrary.getInstance('kernel32')
|
|
176
|
+
buf = java.nio.ByteBuffer.allocate(256)
|
|
177
|
+
(kernel32.getFunction('GetTickCount').invokeInt([256, buf].to_java).to_f / 1000).to_f
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
:unix_osx => lambda {
|
|
181
|
+
# This is faster than who and could work on BSD also.
|
|
182
|
+
(Time.now.to_f - Time.at(`sysctl -b kern.boottime 2>/dev/null`.unpack('L').first).to_f).to_f
|
|
183
|
+
},
|
|
184
|
+
# This should work for most unix flavours.
|
|
185
|
+
:unix => lambda {
|
|
186
|
+
# who is sloooooow. Use File.read('/proc/uptime')
|
|
187
|
+
(Time.now.to_f - Time.parse(`who -b 2>/dev/null`).to_f)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
hours = 0
|
|
192
|
+
|
|
193
|
+
begin
|
|
194
|
+
key = platform
|
|
195
|
+
method = (methods.has_key? key) ? methods[key] : methods[:unix]
|
|
196
|
+
hours = (method.call) / 3600 # seconds to hours
|
|
197
|
+
rescue => ex
|
|
198
|
+
end
|
|
199
|
+
hours
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
#
|
|
204
|
+
# Return the local IP address which receives external traffic
|
|
205
|
+
# from: http://coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/
|
|
206
|
+
# NOTE: This <em>does not</em> open a connection to the IP address.
|
|
207
|
+
def local_ip_address
|
|
208
|
+
# turn off reverse DNS resolution temporarily
|
|
209
|
+
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
|
|
210
|
+
UDPSocket.open {|s| s.connect('75.101.137.7', 1); s.addr.last } # Solutious IP
|
|
211
|
+
ensure
|
|
212
|
+
Socket.do_not_reverse_lookup = orig
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
#
|
|
216
|
+
# Returns the local IP address based on the hostname.
|
|
217
|
+
# According to coderrr (see comments on blog link above), this implementation
|
|
218
|
+
# doesn't guarantee that it will return the address for the interface external
|
|
219
|
+
# traffic goes through. It's also possible the hostname isn't resolvable to the
|
|
220
|
+
# local IP.
|
|
221
|
+
def local_ip_address_alt
|
|
222
|
+
ipaddr = :unknown
|
|
223
|
+
begin
|
|
224
|
+
saddr = Socket.getaddrinfo( Socket.gethostname, nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
|
|
225
|
+
ipaddr = saddr.select{|type| type[0] == 'AF_INET' }[0][3]
|
|
226
|
+
rescue => ex
|
|
227
|
+
end
|
|
228
|
+
ipaddr
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# returns a symbol in the form: os_implementation. This is used throughout Stella
|
|
232
|
+
# for platform specific support.
|
|
233
|
+
def platform
|
|
234
|
+
"#{@os}_#{@implementation}".to_sym
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Returns Ruby version as an array
|
|
238
|
+
def ruby
|
|
239
|
+
RUBY_VERSION.split('.').map { |v| v.to_i }
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Returns the environment PATH as an Array
|
|
243
|
+
def paths
|
|
244
|
+
if @os == :unix
|
|
245
|
+
(ENV['PATH'] || '').split(':')
|
|
246
|
+
elsif
|
|
247
|
+
(ENV['PATH'] || '').split(';') # Note tested!
|
|
248
|
+
else
|
|
249
|
+
raise "paths not implemented for: #{@os}"
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def user
|
|
254
|
+
ENV['USER']
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def home
|
|
258
|
+
if @os == :unix
|
|
259
|
+
File.expand_path(ENV['HOME'])
|
|
260
|
+
elsif @os == :win32
|
|
261
|
+
File.expand_path(ENV['USERPROFILE'])
|
|
262
|
+
else
|
|
263
|
+
raise "paths not implemented for: #{@os}"
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Print friendly system information.
|
|
268
|
+
def to_s
|
|
269
|
+
sprintf("Hostname: %s#{$/}IP Address: %s#{$/}System: %s#{$/}Uptime: %.2f (hours)#{$/}Ruby: #{ruby.join('.')}",
|
|
270
|
+
@hostname, @ipaddress, "#{@os}-#{@implementation}-#{@architecture}", @uptime)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
end
|
data/rye.gemspec
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
@spec = Gem::Specification.new do |s|
|
|
2
|
+
s.name = "rye"
|
|
3
|
+
s.rubyforge_project = "rye"
|
|
4
|
+
s.version = "0.3.2"
|
|
5
|
+
s.summary = "Rye: Run system commands via SSH locally and remotely in a Ruby way."
|
|
6
|
+
s.description = s.summary
|
|
7
|
+
s.author = "Delano Mandelbaum"
|
|
8
|
+
s.email = "delano@solutious.com"
|
|
9
|
+
s.homepage = "http://solutious.com/"
|
|
10
|
+
|
|
11
|
+
# = DEPENDENCIES =
|
|
12
|
+
# Add all gem dependencies
|
|
13
|
+
s.add_dependency 'net-ssh'
|
|
14
|
+
s.add_dependency 'highline'
|
|
15
|
+
|
|
16
|
+
# = MANIFEST =
|
|
17
|
+
# The complete list of files to be included in the release. When GitHub packages your gem,
|
|
18
|
+
# it doesn't allow you to run any command that accesses the filesystem. You will get an
|
|
19
|
+
# error. You can ask your VCS for the list of versioned files:
|
|
20
|
+
# git ls-files
|
|
21
|
+
# svn list -R
|
|
22
|
+
s.files = %w(
|
|
23
|
+
CHANGES.txt
|
|
24
|
+
LICENSE.txt
|
|
25
|
+
README.rdoc
|
|
26
|
+
Rakefile
|
|
27
|
+
bin/try
|
|
28
|
+
lib/esc.rb
|
|
29
|
+
lib/rye.rb
|
|
30
|
+
lib/rye/box.rb
|
|
31
|
+
lib/rye/cmd.rb
|
|
32
|
+
lib/rye/rap.rb
|
|
33
|
+
lib/rye/set.rb
|
|
34
|
+
lib/sys.rb
|
|
35
|
+
rye.gemspec
|
|
36
|
+
test/10_rye_test.rb
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# = EXECUTABLES =
|
|
40
|
+
# The list of executables in your project (if any). Don't include the path,
|
|
41
|
+
# just the base filename.
|
|
42
|
+
#s.executables = %w[]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
s.extra_rdoc_files = %w[README.rdoc LICENSE.txt]
|
|
46
|
+
s.has_rdoc = true
|
|
47
|
+
s.rdoc_options = ["--line-numbers", "--title", s.summary, "--main", "README.rdoc"]
|
|
48
|
+
s.require_paths = %w[lib]
|
|
49
|
+
s.rubygems_version = '1.3.0'
|
|
50
|
+
|
|
51
|
+
if s.respond_to? :specification_version then
|
|
52
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
53
|
+
s.specification_version = 2
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|