lib/rspec/core/configuration.rb



module Rspec
  module Core
    class Configuration
      # Control what examples are run by filtering 
      attr_accessor :filter

      # Control what examples are not run by filtering 
      attr_accessor :exclusion_filter

      # Run all examples if the run is filtered, and no examples were found.
      attr_writer :run_all_when_everything_filtered

      attr_reader :options

      def initialize
        @run_all_when_everything_filtered = false
        @hooks = { 
          :before => { :each => [], :all => [], :suite => [] }, 
          :after => { :each => [], :all => [], :suite => [] } 
        }
        @include_or_extend_modules = []
        @filter, @exclusion_filter = nil, nil
        @options = default_options
      end
      
      def default_options
        {
          :color_enabled => false,
          :mock_framework => nil,
          :use_transactional_examples => true,
          :profile_examples => false,
          :files_to_run => [],
          :filename_pattern => '**/*_spec.rb',
          :formatter_class => Rspec::Core::Formatters::ProgressFormatter,
          :backtrace_clean_patterns => [/\/lib\/ruby\//, 
                                        /bin\/rcov:/, 
                                        /vendor\/rails/, 
                                        /bin\/rspec/, 
                                        /bin\/spec/,
                                        /lib\/rspec\/(core|expectations|matchers|mocks)/]
        }
      end
      
      def cleaned_from_backtrace?(line)
        @options[:backtrace_clean_patterns].any? { |regex| line =~ regex }
      end

      def backtrace_clean_patterns
        @options[:backtrace_clean_patterns]
      end

      def mock_framework=(use_me_to_mock)
        @options[:mock_framework] = use_me_to_mock
      end

      def use_transactional_examples=(value)
        @options[:use_transactional_examples] = value
      end

      def use_transactional_examples?
        @options[:use_transactional_examples]
      end
      
      def require_mock_framework_adapter
        require case @options[:mock_framework].to_s
        when "", /rspec/i
          'rspec/core/mocking/with_rspec'
        when /mocha/i
          'rspec/core/mocking/with_mocha'
        when /rr/i
          'rspec/core/mocking/with_rr'
        when /flexmock/i
          'rspec/core/mocking/with_flexmock'
        else
          'rspec/core/mocking/with_absolutely_nothing'
        end 
      end

      def filename_pattern
        @options[:filename_pattern]
      end

      def filename_pattern=(new_pattern)
        @options[:filename_pattern] = new_pattern
      end 

      def color_enabled=(on_or_off)
        @options[:color_enabled] = on_or_off
      end

      def full_backtrace=(bool)
        @options[:backtrace_clean_patterns].clear
      end

      def libs=(libs)
        libs.map {|lib| $LOAD_PATH.unshift lib}
      end

      def debug=(bool)
        return unless bool
        begin
          require 'ruby-debug'
        rescue LoadError
          raise <<-EOM

#{'*'*50}
You must install ruby-debug to run rspec with the --debug option.

If you have ruby-debug installed as a ruby gem, then you need to either
require 'rubygems' or configure the RUBYOPT environment variable with
the value 'rubygems'.
#{'*'*50}
EOM
        end
      end

      def color_enabled?
        @options[:color_enabled]
      end

      def line_number=(line_number)
        filter_run :line_number => line_number.to_i
      end

      def full_description=(description)
        filter_run :full_description => /#{description}/
      end
      
      # Enable profiling of example run - defaults to false
      def profile_examples
        @options[:profile_examples]
      end
      
      def profile_examples=(on_or_off)
        @options[:profile_examples] = on_or_off
      end
     
      def formatter_class
        @options[:formatter_class]
      end
     
      def formatter=(formatter_to_use)
        formatter_class = case formatter_to_use.to_s
        when 'd', 'doc', 'documentation', 's', 'n', 'spec', 'nested'
          Rspec::Core::Formatters::DocumentationFormatter
        when 'progress' 
          Rspec::Core::Formatters::ProgressFormatter
        else 
          raise ArgumentError, "Formatter '#{formatter_to_use}' unknown - maybe you meant 'documentation' or 'progress'?."
        end
        @options[:formatter_class] = formatter_class
      end
        
      def formatter
        @formatter ||= formatter_class.new
      end
      
      def files_to_run
        @options[:files_to_run]
      end
      
      def files_or_directories_to_run=(*files)
        @options[:files_to_run] = files.flatten.inject([]) do |result, file|
          if File.directory?(file)
            filename_pattern.split(",").each do |pattern|
              result += Dir["#{file}/#{pattern.strip}"]
            end
          else
            path, line_number = file.split(':')
            self.line_number = line_number if line_number
            result << path
          end
          result
        end
      end

      # E.g. alias_example_to :crazy_slow, :speed => 'crazy_slow' defines
      # crazy_slow as an example variant that has the crazy_slow speed option
      def alias_example_to(new_name, extra_options={})
        Rspec::Core::ExampleGroup.alias_example_to(new_name, extra_options)
      end

      def filter_run(options={})
        @filter = options unless @filter and @filter[:line_number] || @filter[:full_description]
      end

      def run_all_when_everything_filtered?
        @run_all_when_everything_filtered
      end

      def output
        $stdout
      end

      def puts(msg="")
        output.puts(msg)    
      end

      def include(mod, options={})
        @include_or_extend_modules << [:include, mod, options]
      end

      def extend(mod, options={})
        @include_or_extend_modules << [:extend, mod, options]
      end

      def find_modules(group)
        @include_or_extend_modules.select do |include_or_extend, mod, filters|
          group.all_apply?(filters)
        end
      end

      def before(each_or_all=:each, options={}, &block)
        @hooks[:before][each_or_all] << [options, block]
      end

      def after(each_or_all=:each, options={}, &block)
        @hooks[:after][each_or_all] << [options, block]
      end

      def find_hook(hook, each_or_all, group)
        @hooks[hook][each_or_all].select do |filters, block|
          group.all_apply?(filters)
        end.map { |filters, block| block }
      end

      def configure_mock_framework
        require_mock_framework_adapter
        Rspec::Core::ExampleGroup.send(:include, Rspec::Core::MockFrameworkAdapter)
      end

      def require_files_to_run
        files_to_run.map {|f| require f }
      end

    end
  end
end