require 'corundum/tasklib' require 'rspec/core' module Corundum #TODO: this should take two command generators as arguments: the test runner, #and the coverage tool - then the various tasks are the result of the #collaboration of those two. # class RSpec < TaskLib def default_namespace :rspec end def default_configuration(toolkit) setting(:task_options, nested( :pattern => './spec{,/*/**}/*_spec.rb', :ruby_opts => nil, :rspec_configs => nil, :rspec_opts => nil, :warning => false, :verbose => true, :fail_on_error => true, :ruby_opts => [], :rspec_path => 'rspec', :rspec_opts => %w{--format documentation --out last_run --color --format documentation}, :failure_message => "Spec examples failed.", :files_to_run => "spec" )) setting(:gemspec_path, toolkit.gemspec_path) setting(:qa_finished_path, toolkit.finished_files.qa) end def resolve_configuration #XXX Que? @task_options.rspec_configs = task_options.rspec_opts @task_options.rspec_opts = [] @task_options.rspec_path = %x"which #{task_options.rspec_path}".chomp end #XXX some point in the future, there needs to be a composible command #object def ruby_command(options) cmd_parts = [] cmd_parts << RUBY cmd_parts << options.ruby_opts cmd_parts << "-w" if options.warning if /^1\.8/ =~ RUBY_VERSION cmd_parts << "-S" end return cmd_parts end def runner_command(options) cmd_parts = [] cmd_parts << options.rspec_path cmd_parts << options.rspec_opts cmd_parts << options.files_to_run return cmd_parts end def full_command(options) cmd_parts = ruby_command(options) + runner_command(options) return cmd_parts.flatten.compact.reject{|part| part.nil? or part.empty?}.join(" ") end def custom_options options = task_options.dup yield(options) return options end def define_spec_task(name) options = if block_given? custom_options{|options| yield(options) if block_given?} else task_options end task name do RakeFileUtils.send(:verbose, verbose) do if options.files_to_run.empty? puts "No examples matching #{options.pattern} could be found" else begin cmd = full_command(options) puts cmd if options.verbose success = system(cmd) rescue Object => ex p ex puts options.failure_message if options.failure_message end raise("ruby #{cmd} failed") if options.fail_on_error unless success end end end end def define in_namespace do desc "Always run every spec" define_spec_task(:all) desc "Generate specifications documentation" define_spec_task(:doc) do |t| t.rspec_opts = %w{-o /dev/null -f d -o doc/Specifications} t.failure_message = "Failed generating specification docs" t.verbose = false end desc "Run only failing examples listed in last_run" define_spec_task(:quick) do |t| examples = [] begin File.open("last_run", "r") do |fail_list| fail_list.lines.grep(%r{^\s*\d+\)\s*(.*)}) do |line| examples << $1.gsub(/'/){"[']"} end end rescue end unless examples.empty? t.rspec_opts << "--example" t.rspec_opts << "\"#{examples.join("|")}\"" end t.failure_message = "Spec examples failed." end end desc "Run failing examples if any exist, otherwise, run the whole suite" task root_task => in_namespace(:quick) task :qa => in_namespace(:doc) end end end