class Echoe

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.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:

Versioning options:

Common packaging options:

Testing options:

Uncommon packaging options:

Security options:

Publishing options:

Documentation options:

Attributes

author[RW]

user-configurable

bin_files[RW]

best left alone

certificate_chain[RW]

user-configurable

changelog[RW]

user-configurable

changelog_patterns[RW]

best left alone

changes[RW]

user-configurable

clean_pattern[RW]

user-configurable

dependencies[RW]

legacy

description[RW]

user-configurable

development_dependencies[RW]

user-configurable

docs_host[RW]

user-configurable

email[RW]

user-configurable

eval[RW]

best left alone

executable_pattern[RW]

user-configurable

extension_pattern[RW]

user-configurable

extensions[RW]

legacy

extra_deps[RW]

legacy

files[RW]

best left alone

gem_bin[RW]

best left alone

gemspec_format[RW]

user-configurable

gemspec_name[RW]

best left alone

ignore_pattern[RW]

user-configurable

include_gemspec[RW]

best left alone

include_rakefile[RW]

best left alone

install_message[RW]

user-configurable

lib_files[RW]

best left alone

licenses[RW]

user-configurable

manifest_name[RW]

user-configurable

name[RW]

best left alone

need_gem[RW]

user-configurable

need_tar_gz[RW]

user-configurable

need_tgz[RW]

user-configurable

need_zip[RW]

user-configurable

platform[RW]

user-configurable

private_key[RW]

user-configurable

project[RW]

user-configurable

rakefile_name[RW]

best left alone

rcov_options[RW]

user-configurable

rdoc_files[RW]

legacy

rdoc_options[RW]

best left alone

rdoc_pattern[RW]

user-configurable

rdoc_template[RW]

user-configurable

require_paths[RW]

user-configurable

require_signed[RW]

user-configurable

retain_gemspec[RW]

best left alone

ruby_version[RW]

user-configurable

rubygems_version[RW]

best left alone

runtime_dependencies[RW]

user-configurable

spec[RW]

best left alone

spec_pattern[RW]

user-configurable

summary[RW]

user-configurable

test_files[RW]

best left alone

test_pattern[RW]

user-configurable

url[RW]

user-configurable

use_sudo[RW]

best left alone

version[RW]

user-configurable

Public Class Methods

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

Private Instance Methods

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