Report abuse


			
class Fixture
  attr_reader :class_name

  def find_id
    if @class_name.is_a?(Class)
      klass = @class_name
    else
      klass = Object.const_get(@class_name) rescue nil
    end
    if klass
      self[klass.primary_key]
    else
      # if we can't find the class just assume id
      self['id']
    end
  end
end

def build_fixture_accessors(fixture_file, fixtures)
  accessor_name = File.basename(fixture_file, '.*')
  file_name = accessor_name.singularize if ActiveRecord::Base.pluralize_table_names
  fixtures = fixtures.delete_if { |k, v| v.find_id.nil? }
  if fixtures.empty?
    ""
  else
<<-CODE
begin
  require_dependency '#{file_name}'
rescue LoadError
  # Let's hope the developer has included it himself
end
#{file_name.upcase}_MAP = {
  #{fixtures.map { |k, v| ":#{k} => #{v.find_id}"}.join(",\n  ")}
}
def #{accessor_name}(fixture_name)
  #{fixtures.values[0].class_name}.find(#{file_name.upcase}_MAP[fixture_name])
end
CODE
  end
end

class Rake::Task
  def detract(prerequisite)
    @prerequisites.delete(prerequisite)
  end
end

FIXTURES_LAST_MOD = File.join(RAILS_ROOT, 'tmp', 'fixtures_last_modified')

desc 'sets last time fixtures were loaded'
task :touch do
  FileUtils.touch(FIXTURES_LAST_MOD)
end

namespace :db do
  namespace :fixtures do
    desc 'checks whether fixtures were modified before loading'
    task :lazy_loader do
      reload_fixtures = true
      if File.exists?(FIXTURES_LAST_MOD)
        last_loaded_at = File.mtime(FIXTURES_LAST_MOD)
        reload_fixtures = false if Dir["test/fixtures/**/*.yml"].entries.find {|f| File.mtime(f) > last_loaded_at}.nil?
      end
      if reload_fixtures
        original_env, RAILS_ENV = RAILS_ENV, 'test' # doubt this makes a difference, but let's be safe
        Rake::Task["db:fixtures:load_fixtures_and_create_accessors"].invoke
        RAILS_ENV = original_env
      end
    end

    desc "loads fixtures and creates fixture accessors file to include"
    task :load_fixtures_and_create_accessors => :environment do
      require 'active_record/fixtures'
      fixture_accessors = []
      ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
      fixture_files = Dir.glob(File.join(RAILS_ROOT, 'test', 'fixtures', '*')).reject { |file| File.directory?(file) }
      fixture_files.each do |fixture_file|
        fixtures = Fixtures.create_fixtures('test/fixtures', File.basename(fixture_file, '.*'))
        unless File.extname(fixture_file) == '.csv'
          fixture_accessors << build_fixture_accessors(fixture_file, fixtures)
        end
      end
      File.open(File.dirname(__FILE__) + '/../../test/fixture_accessors.rb', 'w+' ) do |file|
        file.write(fixture_accessors.join("\n"))
      end 
    end
  end
end

Rake::Task['db:fixtures:load_fixtures_and_create_accessors'].enhance(['touch'])

%w(units functionals integration recent uncommitted).each do |task|
  Rake::Task["test:#{task}"].detract('db:test:prepare')
  Rake::Task["test:#{task}"].enhance(['environment','db:fixtures:lazy_loader'])
end