Class Echoe
In: lib/echoe/extensions.rb
lib/echoe/platform.rb
lib/echoe.rb
lib/echoe/extensions.rb
lib/echoe/platform.rb
lib/echoe.rb
Parent: Object

Echoe includes some optional accessors for more advanced gem configuration.

For example, a simple Rakefile might look like this:

  require 'echoe'

  Echoe.new("uncapitalizer") do |p|
    p.author = "Evan Weaver"
    p.summary = "A library that uncapitalizes strings."
    p.url = "http://www.uncapitalizer.com"
    p.docs_host = "uncapitalizer.com:~/www/files/doc/"
    p.runtime_dependencies = ["string_tools >=1.4.0"]
  end

See below for the full list.

Signing gems

Echoe supports signing gems. First, create yourself a public and private key:

  gem cert --build you@yourmail.com

Move them somewhere secret, and add the following environment variables in your .bash_profile or similar:

  export GEM_PRIVATE_KEY='/secret/path/to/gem-private_key.pem'
  export GEM_CERTIFICATE_CHAIN='/secret/path/to/gem-public_cert.pem'

Make sure your environment is up-to-date:

  source ~/.bash_profile

Upload your public_cert.pem file to your website or Rubyforge project, and tell your users to add that certificate to their system via:

  gem cert --add /path/to/public_cert.pem

Finally, package and release your project as normal. Now users can install your gem via:

  sudo gem install gemname -P HighSecurity

Note that you can also set the key and certificate locations in the Rakefile itself. Finally, you can add p.require_signed = true to your Rakefile so that you don‘t accidentally release an unsigned gem if your key is missing.

Metadependencies

Echoe does not force packages to depend on Echoe itself. Instead, it generates a gemspec from your Rakefile and includes that. Downstream repackagers can use the gemspec as-is to build new versions of your gem even without Echoe.

Cross-packaging

Echoe supports platform Rake targets to allow you to cross-package your gems. Just write the spec assuming RUBY_PLATFORM will be what you need it to be for each architecture, and then invoke Rake with the platform name when you‘re cross-packaging.

For example, on JRuby, rake package will build a generic -ruby type gem. But if you want to include a Java-specific extension, you can do one of two things. You can package from within JRuby by checking if RUBY_PLATFORM =~ /java/ and setting p.platform = jruby, or you can run rake java package, which will set RUBY_PLATFORM and p.platform for you.

This way you can run rake java package, rake aix install, or whatever task you need and Echoe will behave just like you‘re packaging from within the target platform.

Test environment setup and teardown

For some applications, you may need to setup and teardown environment state for the entire test suite. This is especially common for integration tests that may need to spawn an external daemon. To support this, you can add a file tests/setup.rb and it will be silently executed before the entire suite runs. Add a similar file tests/teardown.rb in your app to be executed at the end of the entire run.

Note; these files will only get executed if you run the tests via rake. Also, you can set the environment variable VERBOSE=1 to not hide the setup/teardown output.

Accessor options

Descriptive options:

  • author - Your name.
  • email - Your email address.
  • description - A more detailed description of the library.
  • summary - A shorter description of the library.
  • url - A url for the library.
  • install_message - A message to display after the gem is installed.

Versioning options:

  • version - A string for the version number. Parsed from CHANGELOG otherwise.
  • changes - A string describing the most recent changes. Parsed from CHANGELOG otherwise.

Common packaging options:

  • runtime_dependencies - An array of runtime dependencies for this gem. For example, [‘mongrel’, ‘activesupport >= 2.0.2’].
  • development_dependencies - An array of development dependencies for this gem. For example, [‘rake >=0.7.1’].
  • extension_pattern - A filename array, glob array, or regex for extension files that need to be run at install time. Defaults to "ext/**/extconf.rb".

Testing options:

  • clean_pattern - A filename array, glob array, or regex for files that should be removed when rake clean is run.
  • test_pattern - A filename array, glob array, or regex for test runners. Overridden by "test/test_all.rb", if it exists.
  • spec_pattern - A filename array, glob array, or regex for test runners.
  • rcov_options - Any extra flags to pass to RCov when coverage reports are run.

Uncommon packaging options:

  • platform - What platform this gem is for.
  • manifest_name - The name of the manifest file. Defaults to Manifest.
  • need_gem - Whether to generate a gem package. Defaults to true.
  • need_tar_gz - Whether to generate a .tar.gz package. Defaults to true.
  • need_tgz - Whether to generate a .tgz package. Defaults to false.
  • need_zip - Whether to generate a .zip package. Defaults to false.
  • include_rakefile - Include the Rakefile directly within the package. Defaults to true.
  • include_gemspec - Include the generated gemspec file within the package. Defaults to true.
  • ruby_version - Version string for which Ruby to require (for example, ’>= 1.8.4‘.
  • eval - Accepts a proc to be evaluated in the context of the Gem::Specification object. This allows you to set more unusual gemspec options.
  • ignore_pattern - A filename array, glob array, or regex for pathnames that should be ignored when building the manifest.
  • executable_pattern - A filename array, glob array, or regex for files that should be installed as wrapped executables.

Security options:

  • private_key - The path to your gem private key. Defaults to ENV[‘GEM_PRIVATE_KEY’], if available. This accessor is not published in the resulting gemspec.
  • certificate_chain - An array representing your certificate authorization chain. If no one else has signed your certificate, just set it to your own cert. Defaults to ENV[‘GEM_CERTIFICATE_CHAIN’], if available. This accessor is not published in the resulting gemspec.
  • require_signed - Force Echoe to refuse to package your gem if it‘s not properly signed. Default false.

Publishing options:

  • project - The name of the Rubyforge project to upload to. Defaults to the name of the gem.
  • docs_host - A host and filesystem path to publish the documentation to. Defaults to the Rubyforge project.

Documentation options:

  • rdoc_pattern - A filename array, glob array, or regex for filenames that should be passed to RDoc.
  • rdoc_template - A path to an RDoc template. Defaults to the generic template.

Methods

Classes and Modules

Module Echoe::Platform

Attributes

author  [RW]  user-configurable
author  [RW]  user-configurable
bin_files  [RW]  best left alone
bin_files  [RW]  best left alone
certificate_chain  [RW]  user-configurable
certificate_chain  [RW]  user-configurable
changelog  [RW]  user-configurable
changelog  [RW]  user-configurable
changelog_patterns  [RW]  best left alone
changelog_patterns  [RW]  best left alone
changes  [RW]  user-configurable
changes  [RW]  user-configurable
clean_pattern  [RW]  user-configurable
clean_pattern  [RW]  user-configurable
dependencies  [RW]  legacy
dependencies  [RW]  legacy
description  [RW]  user-configurable
description  [RW]  user-configurable
development_dependencies  [RW]  user-configurable
development_dependencies  [RW]  user-configurable
docs_host  [RW]  user-configurable
docs_host  [RW]  user-configurable
email  [RW]  user-configurable
email  [RW]  user-configurable
eval  [RW]  best left alone
eval  [RW]  best left alone
executable_pattern  [RW]  user-configurable
executable_pattern  [RW]  user-configurable
extension_pattern  [RW]  user-configurable
extension_pattern  [RW]  user-configurable
extensions  [RW]  legacy
extensions  [RW]  legacy
extra_deps  [RW]  legacy
extra_deps  [RW]  legacy
files  [RW]  best left alone
files  [RW]  best left alone
gem_bin  [RW]  best left alone
gem_bin  [RW]  best left alone
gemspec_format  [RW]  user-configurable
gemspec_format  [RW]  user-configurable
gemspec_name  [RW]  best left alone
gemspec_name  [RW]  best left alone
has_rdoc  [RW]  best left alone
has_rdoc  [RW]  best left alone
ignore_pattern  [RW]  user-configurable
ignore_pattern  [RW]  user-configurable
include_gemspec  [RW]  best left alone
include_gemspec  [RW]  best left alone
include_rakefile  [RW]  best left alone
include_rakefile  [RW]  best left alone
install_message  [RW]  user-configurable
install_message  [RW]  user-configurable
lib_files  [RW]  best left alone
lib_files  [RW]  best left alone
manifest_name  [RW]  user-configurable
manifest_name  [RW]  user-configurable
name  [RW]  best left alone
name  [RW]  best left alone
need_gem  [RW]  user-configurable
need_gem  [RW]  user-configurable
need_tar_gz  [RW]  user-configurable
need_tar_gz  [RW]  user-configurable
need_tgz  [RW]  user-configurable
need_tgz  [RW]  user-configurable
need_zip  [RW]  user-configurable
need_zip  [RW]  user-configurable
platform  [RW]  user-configurable
platform  [RW]  user-configurable
private_key  [RW]  user-configurable
private_key  [RW]  user-configurable
project  [RW]  user-configurable
project  [RW]  user-configurable
rakefile_name  [RW]  best left alone
rakefile_name  [RW]  best left alone
rcov_options  [RW]  user-configurable
rcov_options  [RW]  user-configurable
rdoc_files  [RW]  legacy
rdoc_files  [RW]  legacy
rdoc_options  [RW]  best left alone
rdoc_options  [RW]  best left alone
rdoc_pattern  [RW]  user-configurable
rdoc_pattern  [RW]  user-configurable
rdoc_template  [RW]  user-configurable
rdoc_template  [RW]  user-configurable
require_signed  [RW]  user-configurable
require_signed  [RW]  user-configurable
retain_gemspec  [RW]  best left alone
retain_gemspec  [RW]  best left alone
ruby_version  [RW]  user-configurable
ruby_version  [RW]  user-configurable
rubyforge_name  [RW]  best left alone
rubyforge_name  [RW]  best left alone
rubygems_version  [RW]  best left alone
rubygems_version  [RW]  best left alone
runtime_dependencies  [RW]  user-configurable
runtime_dependencies  [RW]  user-configurable
spec  [RW]  best left alone
spec  [RW]  best left alone
spec_pattern  [RW]  user-configurable
spec_pattern  [RW]  user-configurable
summary  [RW]  user-configurable
summary  [RW]  user-configurable
test_files  [RW]  best left alone
test_files  [RW]  best left alone
test_pattern  [RW]  user-configurable
test_pattern  [RW]  user-configurable
url  [RW]  user-configurable
url  [RW]  user-configurable
use_sudo  [RW]  best left alone
use_sudo  [RW]  best left alone
version  [RW]  user-configurable
version  [RW]  user-configurable

Public Class methods

[Source]

     # File lib/echoe.rb, line 163
163:   def initialize(name, _version = nil)
164:     # Defaults
165: 
166:     self.name = name
167:     self.project = name.downcase
168:     self.changelog = "CHANGELOG"
169:     self.url = ""
170:     self.author = ""
171:     self.email = ""
172:     self.clean_pattern = ["pkg", "doc", 'build/*', '**/coverage', '**/*.o', '**/*.so', '**/*.a', '**/*.log', "{ext,lib}/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/Makefile", "{ext,lib}/**/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/**/Makefile", "pkg", "*.gem", ".config"]
173:     self.test_pattern = File.exist?("test/test_all.rb") ? "test/test_all.rb" : ['test/**/test_*.rb', 'test/**/*_test.rb']
174:     self.spec_pattern = "spec/**/*_spec.rb"
175:     self.ignore_pattern = /^(pkg|doc)|\.svn|CVS|\.bzr|\.DS|\.git/
176: 
177:     self.changelog_patterns = {
178:         :version => [
179:             /^\s*v([\d\.]+)(\.|\s|$)/,
180:             /\s*\*\s*([\d\.]+)\s*\*\s*$/
181:           ],
182:         :changes => [
183:           /^\s*v([\d\.]+\. .*)/,
184:           /\*\s*[\d\.]+\s*\*\s*(.*)\*\s*[\d\.]+\s*\*$/m
185:         ]
186:       }
187: 
188:     self.description = ""
189:     self.summary = ""
190:     self.install_message = nil
191:     self.executable_pattern = /^bin\//
192:     self.has_rdoc = true
193:     self.use_sudo = !Platform.windows?
194:     self.gem_bin = "gem#{Platform.suffix}"
195:     self.rcov_options = []
196:     self.rdoc_pattern = /^(lib|bin|tasks|ext)|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
197: 
198:     self.gemspec_format = :ruby
199: 
200:     title = (name.downcase == name ? name.capitalize : name)
201:     self.rdoc_options = ['--line-numbers', '--inline-source', '--title', title]
202: 
203:     readme = Dir['*'].detect { |filename| filename =~ /^readme/i }
204:     self.rdoc_options += ['--main', readme] if readme
205: 
206:     self.runtime_dependencies = []
207:     self.development_dependencies = [] # These appear to not work at all
208:     self.manifest_name = "Manifest"
209:     self.extension_pattern = ["ext/**/extconf.rb", "ext/extconf.rb"]
210:     self.private_key = ENV['GEM_PRIVATE_KEY']
211:     self.require_signed = false
212:     self.certificate_chain = ENV['GEM_CERTIFICATE_CHAIN'].to_s.split(/\,\s*/).compact
213: 
214:     self.need_gem = true
215:     self.need_tar_gz = true
216:     self.need_tgz = false
217:     self.need_zip = false
218:     self.platform = $platform
219: 
220:     self.include_rakefile = true
221:     self.include_gemspec = true
222:     self.gemspec_name = "#{name}.gemspec"
223:     self.retain_gemspec = false
224:     self.rakefile_name = "Rakefile"
225:     self.rubygems_version = ">= 1.2"
226: 
227:     yield self if block_given?
228: 
229:     # legacy compatibility
230:     self.runtime_dependencies = dependencies if dependencies and runtime_dependencies.empty?
231:     self.runtime_dependencies = extra_deps if extra_deps and runtime_dependencies.empty?
232:     self.project = rubyforge_name if rubyforge_name
233:     self.rdoc_pattern = rdoc_files if rdoc_files
234:     self.extension_pattern = extensions if extensions
235: 
236:     # read manifest
237:     begin
238:       self.files = File.readlines(manifest_name).map { |x| x.strip } +
239:         [(gemspec_name if include_gemspec)] +
240:         [(rakefile_name if include_rakefile)]
241:       self.files = files.compact.uniq
242:     rescue Errno::ENOENT
243:       unless ARGV.include? "manifest"
244:         puts "Missing manifest. You can build one with 'rake manifest'."
245:         exit 1
246:       else
247:         self.files = []
248:       end
249:     end
250: 
251:     # snag version and changeset
252:     self.version ||= _version
253:     unless version
254:       if File.exist? changelog
255:         parsed = Array(changelog_patterns[:version]).map do |pattern|
256:           open(changelog) do |log|
257:             log.read[pattern, 1]
258:           end
259:         end.compact.first
260:         raise "Could not parse version from #{changelog}" unless parsed
261:         self.version = parsed.chomp(".").strip
262:       else
263:         raise "No #{changelog} found, and no version supplied in Rakefile."
264:       end
265:     end
266: 
267:     unless self.changes
268:       self.changes = if File.exist? changelog
269:         Array(changelog_patterns[:changes]).map do |pattern|
270:           open(changelog) do |log|
271:             log.read[pattern, 1]
272:           end
273:         end.compact.first or ""
274:       else
275:         ""
276:       end
277:     end
278: 
279:     # set some post-defaults
280:     self.certificate_chain = Array(certificate_chain).map {|file| File.expand_path(file)}
281:     self.private_key = File.expand_path(private_key) if private_key
282:     self.description = summary if description.empty?
283:     self.summary = description if summary.empty?
284:     self.clean_pattern = apply_pattern(clean_pattern)
285:     self.extension_pattern = apply_pattern(extension_pattern, files)
286:     self.ignore_pattern = apply_pattern(ignore_pattern)
287:     self.rdoc_pattern = apply_pattern(rdoc_pattern, files) - [manifest_name]
288:     self.executable_pattern = apply_pattern(executable_pattern, files)
289:     self.test_pattern = apply_pattern(test_pattern)
290:     self.spec_pattern = apply_pattern(spec_pattern)
291: 
292:     define_tasks
293:   end

[Source]

     # File lib/echoe.rb, line 163
163:   def initialize(name, _version = nil)
164:     # Defaults
165: 
166:     self.name = name
167:     self.project = name.downcase
168:     self.changelog = "CHANGELOG"
169:     self.url = ""
170:     self.author = ""
171:     self.email = ""
172:     self.clean_pattern = ["pkg", "doc", 'build/*', '**/coverage', '**/*.o', '**/*.so', '**/*.a', '**/*.log', "{ext,lib}/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/Makefile", "{ext,lib}/**/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/**/Makefile", "pkg", "*.gem", ".config"]
173:     self.test_pattern = File.exist?("test/test_all.rb") ? "test/test_all.rb" : ['test/**/test_*.rb', 'test/**/*_test.rb']
174:     self.spec_pattern = "spec/**/*_spec.rb"
175:     self.ignore_pattern = /^(pkg|doc)|\.svn|CVS|\.bzr|\.DS|\.git/
176: 
177:     self.changelog_patterns = {
178:         :version => [
179:             /^\s*v([\d\.]+)(\.|\s|$)/,
180:             /\s*\*\s*([\d\.]+)\s*\*\s*$/
181:           ],
182:         :changes => [
183:           /^\s*v([\d\.]+\. .*)/,
184:           /\*\s*[\d\.]+\s*\*\s*(.*)\*\s*[\d\.]+\s*\*$/m
185:         ]
186:       }
187: 
188:     self.description = ""
189:     self.summary = ""
190:     self.install_message = nil
191:     self.executable_pattern = /^bin\//
192:     self.has_rdoc = true
193:     self.use_sudo = !Platform.windows?
194:     self.gem_bin = "gem#{Platform.suffix}"
195:     self.rcov_options = []
196:     self.rdoc_pattern = /^(lib|bin|tasks|ext)|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
197: 
198:     self.gemspec_format = :ruby
199: 
200:     title = (name.downcase == name ? name.capitalize : name)
201:     self.rdoc_options = ['--line-numbers', '--inline-source', '--title', title]
202: 
203:     readme = Dir['*'].detect { |filename| filename =~ /^readme/i }
204:     self.rdoc_options += ['--main', readme] if readme
205: 
206:     self.runtime_dependencies = []
207:     self.development_dependencies = [] # These appear to not work at all
208:     self.manifest_name = "Manifest"
209:     self.extension_pattern = ["ext/**/extconf.rb", "ext/extconf.rb"]
210:     self.private_key = ENV['GEM_PRIVATE_KEY']
211:     self.require_signed = false
212:     self.certificate_chain = ENV['GEM_CERTIFICATE_CHAIN'].to_s.split(/\,\s*/).compact
213: 
214:     self.need_gem = true
215:     self.need_tar_gz = true
216:     self.need_tgz = false
217:     self.need_zip = false
218:     self.platform = $platform
219: 
220:     self.include_rakefile = true
221:     self.include_gemspec = true
222:     self.gemspec_name = "#{name}.gemspec"
223:     self.retain_gemspec = false
224:     self.rakefile_name = "Rakefile"
225:     self.rubygems_version = ">= 1.2"
226: 
227:     yield self if block_given?
228: 
229:     # legacy compatibility
230:     self.runtime_dependencies = dependencies if dependencies and runtime_dependencies.empty?
231:     self.runtime_dependencies = extra_deps if extra_deps and runtime_dependencies.empty?
232:     self.project = rubyforge_name if rubyforge_name
233:     self.rdoc_pattern = rdoc_files if rdoc_files
234:     self.extension_pattern = extensions if extensions
235: 
236:     # read manifest
237:     begin
238:       self.files = File.readlines(manifest_name).map { |x| x.strip } +
239:         [(gemspec_name if include_gemspec)] +
240:         [(rakefile_name if include_rakefile)]
241:       self.files = files.compact.uniq
242:     rescue Errno::ENOENT
243:       unless ARGV.include? "manifest"
244:         puts "Missing manifest. You can build one with 'rake manifest'."
245:         exit 1
246:       else
247:         self.files = []
248:       end
249:     end
250: 
251:     # snag version and changeset
252:     self.version ||= _version
253:     unless version
254:       if File.exist? changelog
255:         parsed = Array(changelog_patterns[:version]).map do |pattern|
256:           open(changelog) do |log|
257:             log.read[pattern, 1]
258:           end
259:         end.compact.first
260:         raise "Could not parse version from #{changelog}" unless parsed
261:         self.version = parsed.chomp(".").strip
262:       else
263:         raise "No #{changelog} found, and no version supplied in Rakefile."
264:       end
265:     end
266: 
267:     unless self.changes
268:       self.changes = if File.exist? changelog
269:         Array(changelog_patterns[:changes]).map do |pattern|
270:           open(changelog) do |log|
271:             log.read[pattern, 1]
272:           end
273:         end.compact.first or ""
274:       else
275:         ""
276:       end
277:     end
278: 
279:     # set some post-defaults
280:     self.certificate_chain = Array(certificate_chain).map {|file| File.expand_path(file)}
281:     self.private_key = File.expand_path(private_key) if private_key
282:     self.description = summary if description.empty?
283:     self.summary = description if summary.empty?
284:     self.clean_pattern = apply_pattern(clean_pattern)
285:     self.extension_pattern = apply_pattern(extension_pattern, files)
286:     self.ignore_pattern = apply_pattern(ignore_pattern)
287:     self.rdoc_pattern = apply_pattern(rdoc_pattern, files) - [manifest_name]
288:     self.executable_pattern = apply_pattern(executable_pattern, files)
289:     self.test_pattern = apply_pattern(test_pattern)
290:     self.spec_pattern = apply_pattern(spec_pattern)
291: 
292:     define_tasks
293:   end

[Source]

    # File lib/echoe/extensions.rb, line 14
14:   def self.silence
15:     if !ENV['VERBOSE']      
16:       stdout, stderr = $stdout.clone, $stderr.clone
17:       $stdout.reopen(File.new('/tmp/stdout.echoe', 'w'))
18:       $stderr.reopen(File.new('/tmp/stderr.echoe', 'w'))
19:       begin
20:         yield
21:       ensure
22:         $stdout.reopen(stdout)
23:         $stderr.reopen(stderr)
24:       end
25:     else
26:       yield
27:     end
28:   end

[Source]

    # File lib/echoe/extensions.rb, line 14
14:   def self.silence
15:     if !ENV['VERBOSE']      
16:       stdout, stderr = $stdout.clone, $stderr.clone
17:       $stdout.reopen(File.new('/tmp/stdout.echoe', 'w'))
18:       $stderr.reopen(File.new('/tmp/stderr.echoe', 'w'))
19:       begin
20:         yield
21:       ensure
22:         $stdout.reopen(stdout)
23:         $stderr.reopen(stderr)
24:       end
25:     else
26:       yield
27:     end
28:   end

Public Instance methods

[Source]

     # File lib/echoe.rb, line 295
295:   def apply_pattern(pattern, files = nil)
296:     files ||= Dir['**/**']
297:     case pattern
298:       when String, Array
299:         files & (Array(pattern).map do |p|
300:           Dir.glob(p)
301:         end.flatten)
302:       when Regexp
303:         files.select do |file|
304:           file =~ pattern
305:         end
306:       when FileList
307:         pattern.each do |ignorefile|
308:           ignorefiles = File.open(ignorefile).to_a.map(&:chomp)
309:           files = files.select do |file|
310:             ignorefiles.map { |i| File.fnmatch(i, file) }.include?(true)
311:           end
312:         end
313:         files
314:       else
315:         []
316:     end
317:   end

[Source]

     # File lib/echoe.rb, line 295
295:   def apply_pattern(pattern, files = nil)
296:     files ||= Dir['**/**']
297:     case pattern
298:       when String, Array
299:         files & (Array(pattern).map do |p|
300:           Dir.glob(p)
301:         end.flatten)
302:       when Regexp
303:         files.select do |file|
304:           file =~ pattern
305:         end
306:       when FileList
307:         pattern.each do |ignorefile|
308:           ignorefiles = File.open(ignorefile).to_a.map(&:chomp)
309:           files = files.select do |file|
310:             ignorefiles.map { |i| File.fnmatch(i, file) }.include?(true)
311:           end
312:         end
313:         files
314:       else
315:         []
316:     end
317:   end

[Source]

     # File lib/echoe.rb, line 319
319:   def define_tasks
320: 
321:     ### Packaging and Installing
322: 
323:     self.spec = Gem::Specification.new do |s|
324:       s.name = name
325:       s.version = version
326:       # s.specification_version = 3
327:       s.summary = summary
328:       s.author = Array(author).join(", ")
329:       s.email = email
330:       s.homepage = url
331:       s.rubyforge_project = project
332:       s.post_install_message = install_message if install_message
333:       s.description = description
334:       s.required_ruby_version = ruby_version
335:       s.required_rubygems_version = rubygems_version if rubygems_version
336:       s.platform = platform
337:       s.rdoc_options = rdoc_options
338:       s.extra_rdoc_files = rdoc_pattern
339: 
340:       if private_key and File.exist? private_key
341:         s.signing_key = private_key
342:         s.cert_chain = certificate_chain
343:       end
344: 
345:       runtime_dependencies.each do |dep|
346:         dep = dep.split(" ") if dep.is_a? String
347:         s.add_runtime_dependency(*dep)
348:       end
349: 
350:       development_dependencies.each do |dep|
351:         dep = dep.split(" ") if dep.is_a? String
352:         s.add_development_dependency(*dep)
353:       end
354: 
355:       s.files = files
356: 
357:       s.bindir = if executable_pattern.any?
358:         executable_pattern[0].split("/")[0]
359:       else
360:         "bin"
361:       end
362: 
363:       s.executables = executable_pattern.map do |file|
364:         file[(s.bindir.length + 1)..-1]
365:       end
366: 
367:       dirs = Dir['{lib,ext}']
368:       s.extensions = extension_pattern if extension_pattern.any?
369:       s.require_paths = dirs unless dirs.empty?
370:       s.has_rdoc = has_rdoc
371: 
372:       if File.exist? "test/test_all.rb"
373:         s.test_file = "test/test_all.rb"
374:       else
375:         s.test_files = test_pattern
376:       end
377: 
378:       if eval
379:         s.instance_eval &eval
380:       end
381: 
382:     end
383: 
384:     self.lib_files = spec.files.grep(/^lib/)
385:     self.bin_files = spec.files.grep(/^bin/)
386:     self.test_files = spec.files.grep(/^test/)
387: 
388:     Rake::GemPackageTask.new(spec) do |pkg|
389:       pkg.need_tar = @need_tgz
390:       pkg.need_tar_gz = @need_tar_gz
391:       pkg.need_zip = @need_zip
392:     end
393:     
394:     desc "Display Echoe's knowledge of your system"
395:     task :details do
396:       (self.instance_variables.sort - ['@spec']).each do |var|
397:         puts "#{var}: #{instance_variable_get(var).inspect}"
398:       end
399:     end
400:     
401:     desc "Builds the .gemspec"
402:     task :build_gemspec do
403:       # Construct the gemspec file, if needed.
404:       if include_gemspec
405:         File.open(gemspec_name, 'w') do |f|          
406:           case gemspec_format
407:           when :yaml
408:             spec.to_yaml.split("\n").each do |line|
409:               # Don't publish any information about the private key or certificate chain
410:               f.puts line unless line =~ /signing_key|cert_chain|\.pem/
411:             end          
412:           when :ruby
413:             f.puts spec.to_ruby
414:           else
415:             raise "Unknown gemspec format #{gemspec_format.inspect}. Supported formats: :ruby and :yaml"
416:           end
417:         end
418:       end
419:       puts "Gemspec generated"
420:     end
421: 
422:     # Chain it to the gemspec task prerequisite
423:     task gemspec_name.to_sym => [:build_gemspec]
424: 
425:     desc "Generates manifest & gemspec in one go"
426:     task :build => [:manifest, :build_gemspec]
427: 
428:     task :package do
429:       # Chain some cleanup tasks to the default :package task.
430:       # Remove the gemfile if it wasn't actually requested.
431:       unless @need_gem
432:         puts "  Gem file not requested. Removed."
433:         system "rm pkg/*.gem"
434:       end
435:       # Remove the generated gemspec once the packaging is done, to discourage people from modifying it by hand.
436:       if include_gemspec and File.exist? gemspec_name and not retain_gemspec
437:         File.delete gemspec_name
438:       end
439: 
440:       # Test signing status
441:       if private_key and File.exist? private_key
442:         puts "Signing gem."
443:       else
444:         raise "Key required, but not found. Maybe you forget to set ENV['GEM_PRIVATE_KEY']?" if require_signed
445:         puts "Private key not found; gem will not be signed."
446:       end
447:       puts "Targeting \"#{platform}\" platform."
448:     end
449: 
450:     desc 'Install the gem'
451:     task :install => [:clean, :package, :uninstall] do
452:       system "#{'sudo' if use_sudo} #{gem_bin} install pkg/*.gem -P MediumSecurity --no-update-sources"
453:     end
454: 
455:     namespace :install do
456:       desc 'Install the gem including development dependencies'
457:       task :development => [:clean, :package, :uninstall] do
458:         system "#{'sudo' if use_sudo} #{gem_bin} install pkg/*.gem -P MediumSecurity --no-update-sources --development"
459:       end
460:     end
461: 
462:     desc 'Uninstall the gem'
463:     task :uninstall do
464:       system "#{'sudo' if use_sudo} #{gem_bin} uninstall #{name} -a -I -x"
465:     end
466: 
467:     desc 'Package and upload the release to Rubyforge'
468:     task :release => [:clean, :package] do |t|
469: 
470:       say "\n"
471:       if agree "Release #{name}-#{version} to Rubyforge? "
472:         pkg = "pkg/#{name}-#{version}"
473:         pkg_gem = pkg + ".gem"
474:         pkg_tar = pkg + ".tgz"
475:         pkg_tar_gz = pkg + ".tar.gz"
476:         pkg_zip = pkg + ".zip"
477: 
478:         rf = RubyForge.new.configure
479:         puts "Logging in"
480:         rf.login
481: 
482:         c = rf.userconfig
483:         c["release_notes"] = description if description
484:         c["release_changes"] = changes if changes
485:         c["preformatted"] = false
486: 
487:         files = [(@need_tgz ? pkg_tar : nil),
488:                   (@need_tar_gz ? pkg_tar_gz : nil),
489:                   (@need_zip ? pkg_zip : nil),
490:                   (@need_gem ? pkg_gem : nil)].compact
491: 
492:         puts "Releasing #{name} v. #{version}"
493:         self.version = self.version.to_s.ljust(3)
494: 
495:         rf.add_release project, name, version, *files
496:       end
497: 
498:     end
499: 
500:     ### Extension building
501: 
502:     task :lib do
503:       directory "lib"
504:     end
505: 
506:     if extension_pattern.any?
507: 
508:       desc "Compile the binary extension module"
509:       task :compile => [:lib] do
510:         extension_pattern.each do |extension|
511:           ext_dir = File.dirname(extension)
512:           lib_target = nil
513:           Dir.chdir(ext_dir) do
514:             ruby File.basename(extension)
515:             system(RUBY_PLATFORM =~ /win32/ ? 'nmake' : 'make')
516:             lib_target = open('Makefile').readlines.grep(/target_prefix = /).first.split('=').last.chomp("\n").strip
517:           end
518:           Dir["#{ext_dir}/*.#{Config::CONFIG['DLEXT']}"].each do |file|
519:             dir = "lib/#{lib_target}/".gsub('//', '/')
520:             mkdir_p dir
521:             cp file, dir
522:           end
523:         end
524:       end
525: 
526:       task :test => [:compile] if test_pattern.any?
527:       task :spec => :compile if spec_pattern.any?
528: 
529:     end
530: 
531:     ### Cross-platform targets
532: 
533:     Gem::Specification::PLATFORM_CROSS_TARGETS.each do |target|
534:       task target do
535:         reset_target target
536:       end
537:     end
538: 
539:     ### Documentation
540: 
541:     Rake::RDocTask.new(:docs) do |rd|
542:       # rd.main = Dir['*'].detect {|f| f =~ /^readme/i}
543:       rd.options += Array(rdoc_options)
544: 
545:       rd.rdoc_dir = 'doc'
546:       rd.rdoc_files.push(*rdoc_pattern)
547: 
548:       if rdoc_template
549:         rd.template = rdoc_template
550:       elsif ENV['RDOC_TEMPLATE']
551:         rd.template = ENV['RDOC_TEMPLATE']
552:       end
553:     end
554: 
555:     task :doc => [:redocs]
556: 
557:     desc "Publish documentation to #{docs_host ? "'#{docs_host}'" : "rubyforge"}"
558:     task :publish_docs => [:clean, :docs] do
559: 
560:       local_dir = 'doc'
561:       remote_dir_name = project
562:       remote_dir_name += "/#{name}" if project != name
563: 
564:       unless docs_host
565:         config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
566:         pub = Rake::SshDirPublisher.new "#{config["username"]}@rubyforge.org",
567:           "/var/www/gforge-projects/#{remote_dir_name}",
568:           local_dir
569:         if project != name then
570:           def pub.upload
571:             begin
572:               super
573:             rescue
574:               # project directory probably doesn't exist, transfer as a whole
575:               cmd = "scp -qr #{local_dir} #{host}:#{remote_dir}"
576:               puts "Uploading: #{cmd}"
577:               system(cmd)
578:             end
579:           end
580:         end
581:         pub.upload
582:       else
583:         # you may need ssh keys configured for this to work
584:         host, dir = docs_host.split(":")
585:         dir.chomp!("/")
586: 
587:         # XXX too dangerous?
588:         cmd = "ssh #{host} 'rm -rf #{dir}/#{remote_dir_name}'"
589:         puts "Deleting existing docs: #{cmd}"
590:         system(cmd)
591: 
592:         cmd = "scp -qr #{local_dir} #{host}:#{dir}/#{remote_dir_name}"
593:         puts "Uploading: #{cmd}"
594:         system(cmd)
595:       end
596:     end
597: 
598:     desc 'Generate a release announcement, edit it, and post it to Rubyforge.'
599:     task :announce do
600: 
601:       filename = "/tmp/#{name}_#{version}_announcement.txt"
602: 
603:       if !File.exist?(filename) or agree "Overwrite existing announcement file? "
604:         File.open(filename, 'w') do |f|
605:           f.write "Subject: #{name.capitalize} #{version}\n\n"
606:           f.write "#{name.capitalize} has been updated to #{version}. #{name.capitalize} is #{summary.uncapitalize}\n\n"
607:           unless changes.empty?
608:             f.write "Changes in this version: "
609:             if changes.include?("\n")
610:               f.write(changes)
611:             else
612:               f.write(changes.sub(/^\s*[\w\d\.]+\s+/, '').uncapitalize)
613:             end
614:             f.write("\n\n")
615:           end
616:           f.write "More information is available at #{url} .\n\n" unless url.empty?
617:         end
618:       end
619: 
620:       begin
621:         editor = ENV['EDITOR'] || 'nano'
622:         system("#{editor} #{filename}") or raise "Editor '#{editor}' failed to start"
623:         puts File.open(filename).read
624:       end while !agree "Done editing? "
625: 
626:       if agree "Publish announcement to Rubyforge? "
627:         File.open(filename).readlines.detect { |line| line =~ /Subject: (.*)/ }
628:         subject = $1 or raise "Subject line seems to have disappeared"
629: 
630:         body = File.open(filename).readlines.reject { |line| line =~ /Subject: / }.join.gsub("\n\n\n", "\n\n")
631: 
632:         rf = RubyForge.new.configure
633:         rf.login
634:         rf.post_news(project, subject, body)
635:         puts "Published."
636:         File.delete filename
637:       end
638:     end
639: 
640:     ### Clean
641: 
642:     desc 'Clean up auto-generated files'
643:     task :clean do
644:       puts "Cleaning"
645:       clean_pattern.each do |file|
646:         if File.exist?(file)
647:           puts "- #{file}"
648:           rm_rf file
649:         end
650:       end
651:     end
652: 
653:     ### Manifest
654: 
655:     desc "Build a Manifest list"
656:     task :manifest => [:clean] do
657:       puts "Building Manifest"
658:       old_files = files
659:       files = []
660:       Dir['**/**'].sort.each do |file|
661:         next unless file
662:         next if ignore_pattern.include?(file)
663:         next if File.directory?(file)
664:         next if !include_rakefile and file == rakefile_name
665:         files << file
666:       end
667: 
668:       files << rakefile_name if include_rakefile
669:       files << manifest_name
670:       files.uniq!
671: 
672:       File.open(manifest_name, 'w').puts(files)
673: 
674:       (files | old_files).sort.each do |file|
675:         next if file == gemspec_name
676:         sign = " "
677:         if old_files.include?(file) and !files.include?(file)
678:           sign = "-"
679:         elsif files.include?(file) and !old_files.include?(file)
680:           sign = "+"
681:         end
682:         puts "#{sign} #{file}"
683:       end
684:     end
685: 
686:     task :build_manifest => :manifest
687: 
688:     ### Testing
689: 
690:     if test_pattern.any?
691: 
692:       Rake::TestTask.new(:test_inner) do |t|
693:         t.libs = ['lib', 'ext', 'bin', 'test']
694:         t.test_files = test_pattern
695:         t.verbose = true
696:       end
697: 
698:       desc "Run the test suite"
699:       task :test do
700:         if File.exist? 'test/setup.rb'
701:           Echoe.silence do
702:             puts "Setting up test environment"
703:             system("ruby test/setup.rb")
704:           end
705:         end
706:         begin
707:           test = Rake::Task[:test_inner]
708:           if test.respond_to? :already_invoked=
709:             # Method provided by MultiRails
710:             test.already_invoked = false
711:           end
712:           test.invoke
713:         ensure
714:           if File.exist? 'test/teardown.rb'
715:             Echoe.silence do
716:               puts "Tearing down test environment"
717:               system("ruby test/teardown.rb")
718:             end
719:           end
720:         end
721:       end
722: 
723:       task :default => :test
724:     end
725: 
726:     if spec_pattern.any?
727:       desc "Run the spec suite"
728:       Spec::Rake::SpecTask.new('spec') do |t|
729:         t.spec_files = spec_pattern
730:       end
731: 
732:       task :default => :spec
733:     end
734: 
735:     if defined? Rcov
736:       Rcov::RcovTask.new(:coverage) do |t|
737:         t.test_files = test_pattern
738:         t.rcov_opts << rcov_options if rcov_options
739:         t.verbose = true
740:       end
741:       task :rcov => :coverage
742:     end
743: 
744:   end

[Source]

     # File lib/echoe.rb, line 319
319:   def define_tasks
320: 
321:     ### Packaging and Installing
322: 
323:     self.spec = Gem::Specification.new do |s|
324:       s.name = name
325:       s.version = version
326:       # s.specification_version = 3
327:       s.summary = summary
328:       s.author = Array(author).join(", ")
329:       s.email = email
330:       s.homepage = url
331:       s.rubyforge_project = project
332:       s.post_install_message = install_message if install_message
333:       s.description = description
334:       s.required_ruby_version = ruby_version
335:       s.required_rubygems_version = rubygems_version if rubygems_version
336:       s.platform = platform
337:       s.rdoc_options = rdoc_options
338:       s.extra_rdoc_files = rdoc_pattern
339: 
340:       if private_key and File.exist? private_key
341:         s.signing_key = private_key
342:         s.cert_chain = certificate_chain
343:       end
344: 
345:       runtime_dependencies.each do |dep|
346:         dep = dep.split(" ") if dep.is_a? String
347:         s.add_runtime_dependency(*dep)
348:       end
349: 
350:       development_dependencies.each do |dep|
351:         dep = dep.split(" ") if dep.is_a? String
352:         s.add_development_dependency(*dep)
353:       end
354: 
355:       s.files = files
356: 
357:       s.bindir = if executable_pattern.any?
358:         executable_pattern[0].split("/")[0]
359:       else
360:         "bin"
361:       end
362: 
363:       s.executables = executable_pattern.map do |file|
364:         file[(s.bindir.length + 1)..-1]
365:       end
366: 
367:       dirs = Dir['{lib,ext}']
368:       s.extensions = extension_pattern if extension_pattern.any?
369:       s.require_paths = dirs unless dirs.empty?
370:       s.has_rdoc = has_rdoc
371: 
372:       if File.exist? "test/test_all.rb"
373:         s.test_file = "test/test_all.rb"
374:       else
375:         s.test_files = test_pattern
376:       end
377: 
378:       if eval
379:         s.instance_eval &eval
380:       end
381: 
382:     end
383: 
384:     self.lib_files = spec.files.grep(/^lib/)
385:     self.bin_files = spec.files.grep(/^bin/)
386:     self.test_files = spec.files.grep(/^test/)
387: 
388:     Rake::GemPackageTask.new(spec) do |pkg|
389:       pkg.need_tar = @need_tgz
390:       pkg.need_tar_gz = @need_tar_gz
391:       pkg.need_zip = @need_zip
392:     end
393:     
394:     desc "Display Echoe's knowledge of your system"
395:     task :details do
396:       (self.instance_variables.sort - ['@spec']).each do |var|
397:         puts "#{var}: #{instance_variable_get(var).inspect}"
398:       end
399:     end
400:     
401:     desc "Builds the .gemspec"
402:     task :build_gemspec do
403:       # Construct the gemspec file, if needed.
404:       if include_gemspec
405:         File.open(gemspec_name, 'w') do |f|          
406:           case gemspec_format
407:           when :yaml
408:             spec.to_yaml.split("\n").each do |line|
409:               # Don't publish any information about the private key or certificate chain
410:               f.puts line unless line =~ /signing_key|cert_chain|\.pem/
411:             end          
412:           when :ruby
413:             f.puts spec.to_ruby
414:           else
415:             raise "Unknown gemspec format #{gemspec_format.inspect}. Supported formats: :ruby and :yaml"
416:           end
417:         end
418:       end
419:       puts "Gemspec generated"
420:     end
421: 
422:     # Chain it to the gemspec task prerequisite
423:     task gemspec_name.to_sym => [:build_gemspec]
424: 
425:     desc "Generates manifest & gemspec in one go"
426:     task :build => [:manifest, :build_gemspec]
427: 
428:     task :package do
429:       # Chain some cleanup tasks to the default :package task.
430:       # Remove the gemfile if it wasn't actually requested.
431:       unless @need_gem
432:         puts "  Gem file not requested. Removed."
433:         system "rm pkg/*.gem"
434:       end
435:       # Remove the generated gemspec once the packaging is done, to discourage people from modifying it by hand.
436:       if include_gemspec and File.exist? gemspec_name and not retain_gemspec
437:         File.delete gemspec_name
438:       end
439: 
440:       # Test signing status
441:       if private_key and File.exist? private_key
442:         puts "Signing gem."
443:       else
444:         raise "Key required, but not found. Maybe you forget to set ENV['GEM_PRIVATE_KEY']?" if require_signed
445:         puts "Private key not found; gem will not be signed."
446:       end
447:       puts "Targeting \"#{platform}\" platform."
448:     end
449: 
450:     desc 'Install the gem'
451:     task :install => [:clean, :package, :uninstall] do
452:       system "#{'sudo' if use_sudo} #{gem_bin} install pkg/*.gem -P MediumSecurity --no-update-sources"
453:     end
454: 
455:     namespace :install do
456:       desc 'Install the gem including development dependencies'
457:       task :development => [:clean, :package, :uninstall] do
458:         system "#{'sudo' if use_sudo} #{gem_bin} install pkg/*.gem -P MediumSecurity --no-update-sources --development"
459:       end
460:     end
461: 
462:     desc 'Uninstall the gem'
463:     task :uninstall do
464:       system "#{'sudo' if use_sudo} #{gem_bin} uninstall #{name} -a -I -x"
465:     end
466: 
467:     desc 'Package and upload the release to Rubyforge'
468:     task :release => [:clean, :package] do |t|
469: 
470:       say "\n"
471:       if agree "Release #{name}-#{version} to Rubyforge? "
472:         pkg = "pkg/#{name}-#{version}"
473:         pkg_gem = pkg + ".gem"
474:         pkg_tar = pkg + ".tgz"
475:         pkg_tar_gz = pkg + ".tar.gz"
476:         pkg_zip = pkg + ".zip"
477: 
478:         rf = RubyForge.new.configure
479:         puts "Logging in"
480:         rf.login
481: 
482:         c = rf.userconfig
483:         c["release_notes"] = description if description
484:         c["release_changes"] = changes if changes
485:         c["preformatted"] = false
486: 
487:         files = [(@need_tgz ? pkg_tar : nil),
488:                   (@need_tar_gz ? pkg_tar_gz : nil),
489:                   (@need_zip ? pkg_zip : nil),
490:                   (@need_gem ? pkg_gem : nil)].compact
491: 
492:         puts "Releasing #{name} v. #{version}"
493:         self.version = self.version.to_s.ljust(3)
494: 
495:         rf.add_release project, name, version, *files
496:       end
497: 
498:     end
499: 
500:     ### Extension building
501: 
502:     task :lib do
503:       directory "lib"
504:     end
505: 
506:     if extension_pattern.any?
507: 
508:       desc "Compile the binary extension module"
509:       task :compile => [:lib] do
510:         extension_pattern.each do |extension|
511:           ext_dir = File.dirname(extension)
512:           lib_target = nil
513:           Dir.chdir(ext_dir) do
514:             ruby File.basename(extension)
515:             system(RUBY_PLATFORM =~ /win32/ ? 'nmake' : 'make')
516:             lib_target = open('Makefile').readlines.grep(/target_prefix = /).first.split('=').last.chomp("\n").strip
517:           end
518:           Dir["#{ext_dir}/*.#{Config::CONFIG['DLEXT']}"].each do |file|
519:             dir = "lib/#{lib_target}/".gsub('//', '/')
520:             mkdir_p dir
521:             cp file, dir
522:           end
523:         end
524:       end
525: 
526:       task :test => [:compile] if test_pattern.any?
527:       task :spec => :compile if spec_pattern.any?
528: 
529:     end
530: 
531:     ### Cross-platform targets
532: 
533:     Gem::Specification::PLATFORM_CROSS_TARGETS.each do |target|
534:       task target do
535:         reset_target target
536:       end
537:     end
538: 
539:     ### Documentation
540: 
541:     Rake::RDocTask.new(:docs) do |rd|
542:       # rd.main = Dir['*'].detect {|f| f =~ /^readme/i}
543:       rd.options += Array(rdoc_options)
544: 
545:       rd.rdoc_dir = 'doc'
546:       rd.rdoc_files.push(*rdoc_pattern)
547: 
548:       if rdoc_template
549:         rd.template = rdoc_template
550:       elsif ENV['RDOC_TEMPLATE']
551:         rd.template = ENV['RDOC_TEMPLATE']
552:       end
553:     end
554: 
555:     task :doc => [:redocs]
556: 
557:     desc "Publish documentation to #{docs_host ? "'#{docs_host}'" : "rubyforge"}"
558:     task :publish_docs => [:clean, :docs] do
559: 
560:       local_dir = 'doc'
561:       remote_dir_name = project
562:       remote_dir_name += "/#{name}" if project != name
563: 
564:       unless docs_host
565:         config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
566:         pub = Rake::SshDirPublisher.new "#{config["username"]}@rubyforge.org",
567:           "/var/www/gforge-projects/#{remote_dir_name}",
568:           local_dir
569:         if project != name then
570:           def pub.upload
571:             begin
572:               super
573:             rescue
574:               # project directory probably doesn't exist, transfer as a whole
575:               cmd = "scp -qr #{local_dir} #{host}:#{remote_dir}"
576:               puts "Uploading: #{cmd}"
577:               system(cmd)
578:             end
579:           end
580:         end
581:         pub.upload
582:       else
583:         # you may need ssh keys configured for this to work
584:         host, dir = docs_host.split(":")
585:         dir.chomp!("/")
586: 
587:         # XXX too dangerous?
588:         cmd = "ssh #{host} 'rm -rf #{dir}/#{remote_dir_name}'"
589:         puts "Deleting existing docs: #{cmd}"
590:         system(cmd)
591: 
592:         cmd = "scp -qr #{local_dir} #{host}:#{dir}/#{remote_dir_name}"
593:         puts "Uploading: #{cmd}"
594:         system(cmd)
595:       end
596:     end
597: 
598:     desc 'Generate a release announcement, edit it, and post it to Rubyforge.'
599:     task :announce do
600: 
601:       filename = "/tmp/#{name}_#{version}_announcement.txt"
602: 
603:       if !File.exist?(filename) or agree "Overwrite existing announcement file? "
604:         File.open(filename, 'w') do |f|
605:           f.write "Subject: #{name.capitalize} #{version}\n\n"
606:           f.write "#{name.capitalize} has been updated to #{version}. #{name.capitalize} is #{summary.uncapitalize}\n\n"
607:           unless changes.empty?
608:             f.write "Changes in this version: "
609:             if changes.include?("\n")
610:               f.write(changes)
611:             else
612:               f.write(changes.sub(/^\s*[\w\d\.]+\s+/, '').uncapitalize)
613:             end
614:             f.write("\n\n")
615:           end
616:           f.write "More information is available at #{url} .\n\n" unless url.empty?
617:         end
618:       end
619: 
620:       begin
621:         editor = ENV['EDITOR'] || 'nano'
622:         system("#{editor} #{filename}") or raise "Editor '#{editor}' failed to start"
623:         puts File.open(filename).read
624:       end while !agree "Done editing? "
625: 
626:       if agree "Publish announcement to Rubyforge? "
627:         File.open(filename).readlines.detect { |line| line =~ /Subject: (.*)/ }
628:         subject = $1 or raise "Subject line seems to have disappeared"
629: 
630:         body = File.open(filename).readlines.reject { |line| line =~ /Subject: / }.join.gsub("\n\n\n", "\n\n")
631: 
632:         rf = RubyForge.new.configure
633:         rf.login
634:         rf.post_news(project, subject, body)
635:         puts "Published."
636:         File.delete filename
637:       end
638:     end
639: 
640:     ### Clean
641: 
642:     desc 'Clean up auto-generated files'
643:     task :clean do
644:       puts "Cleaning"
645:       clean_pattern.each do |file|
646:         if File.exist?(file)
647:           puts "- #{file}"
648:           rm_rf file
649:         end
650:       end
651:     end
652: 
653:     ### Manifest
654: 
655:     desc "Build a Manifest list"
656:     task :manifest => [:clean] do
657:       puts "Building Manifest"
658:       old_files = files
659:       files = []
660:       Dir['**/**'].sort.each do |file|
661:         next unless file
662:         next if ignore_pattern.include?(file)
663:         next if File.directory?(file)
664:         next if !include_rakefile and file == rakefile_name
665:         files << file
666:       end
667: 
668:       files << rakefile_name if include_rakefile
669:       files << manifest_name
670:       files.uniq!
671: 
672:       File.open(manifest_name, 'w').puts(files)
673: 
674:       (files | old_files).sort.each do |file|
675:         next if file == gemspec_name
676:         sign = " "
677:         if old_files.include?(file) and !files.include?(file)
678:           sign = "-"
679:         elsif files.include?(file) and !old_files.include?(file)
680:           sign = "+"
681:         end
682:         puts "#{sign} #{file}"
683:       end
684:     end
685: 
686:     task :build_manifest => :manifest
687: 
688:     ### Testing
689: 
690:     if test_pattern.any?
691: 
692:       Rake::TestTask.new(:test_inner) do |t|
693:         t.libs = ['lib', 'ext', 'bin', 'test']
694:         t.test_files = test_pattern
695:         t.verbose = true
696:       end
697: 
698:       desc "Run the test suite"
699:       task :test do
700:         if File.exist? 'test/setup.rb'
701:           Echoe.silence do
702:             puts "Setting up test environment"
703:             system("ruby test/setup.rb")
704:           end
705:         end
706:         begin
707:           test = Rake::Task[:test_inner]
708:           if test.respond_to? :already_invoked=
709:             # Method provided by MultiRails
710:             test.already_invoked = false
711:           end
712:           test.invoke
713:         ensure
714:           if File.exist? 'test/teardown.rb'
715:             Echoe.silence do
716:               puts "Tearing down test environment"
717:               system("ruby test/teardown.rb")
718:             end
719:           end
720:         end
721:       end
722: 
723:       task :default => :test
724:     end
725: 
726:     if spec_pattern.any?
727:       desc "Run the spec suite"
728:       Spec::Rake::SpecTask.new('spec') do |t|
729:         t.spec_files = spec_pattern
730:       end
731: 
732:       task :default => :spec
733:     end
734: 
735:     if defined? Rcov
736:       Rcov::RcovTask.new(:coverage) do |t|
737:         t.test_files = test_pattern
738:         t.rcov_opts << rcov_options if rcov_options
739:         t.verbose = true
740:       end
741:       task :rcov => :coverage
742:     end
743: 
744:   end

[Validate]