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:
-
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. Defaults to generated RDoc on GitHub pages for the project.f -
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 whenrake 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 toManifest
. -
need_gem
- Whether to generate a gem package. Defaults totrue
. -
need_tar_gz
- Whether to generate a.tar.gz
package. Defaults totrue
. -
need_tgz
- Whether to generate a.tgz
package. Defaults tofalse
. -
need_zip
- Whether to generate a.zip
package. Defaults tofalse
. -
include_rakefile
- Include the Rakefile directly within the package. Defaults totrue
. -
include_gemspec
- Include the generated gemspec file within the package. Defaults totrue
. -
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 theGem::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. -
require_paths
- Non-standard requirement paths to add to the gem definition. -
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, 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, if available. This accessor is not published in the resulting gemspec. -
require_signed
- ForceEchoe
to refuse to package your gem if it's not properly signed. Default false.
Publishing options:
-
project
- The name of the Rubyforge project. Defaults to the name of the gem. -
docs_host
- A host and filesystem path to publish the documentation to. Defaults to GitHub pages for the project. SSH upload to an accessible static file host also works.
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.
Attributes
best left alone
user-configurable
user-configurable
best left alone
user-configurable
user-configurable
legacy
user-configurable
user-configurable
user-configurable
user-configurable
best left alone
user-configurable
user-configurable
legacy
legacy
best left alone
best left alone
user-configurable
best left alone
user-configurable
best left alone
best left alone
user-configurable
best left alone
user-configurable
user-configurable
best left alone
user-configurable
user-configurable
user-configurable
user-configurable
user-configurable
user-configurable
user-configurable
best left alone
user-configurable
legacy
best left alone
user-configurable
user-configurable
user-configurable
user-configurable
best left alone
user-configurable
best left alone
user-configurable
best left alone
user-configurable
user-configurable
best left alone
user-configurable
user-configurable
best left alone
user-configurable
Public Class Methods
# 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
# 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
# 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
# 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
# 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