class Fixtures # Class methods to tie fixture joining into the standard process for generating fixtures. class << self # Called by individual Fixtures instances just before they insert fixtures. # This allows templating to occur at the correct time (ie after all fixtures # have been loaded and configured) -- resolution of references naturally requires # that all join tables are available. def template_all_loaded_fixtures all_loaded_fixtures.each_pair do |table_name, fixtures| fixtures.template_fixtures end # note indexing and reference resolution must execute after all # fixtures have been templated because you never know which fixture(s) # will recieve new entries. Additionally, indexing and resolution must # run separately, because reference resolution requires the target ids # to be set. all_loaded_fixtures.values.each {|fixtures| index_fixtures(fixtures) } all_loaded_fixtures.values.each {|fixtures| resolve_references(fixtures)} end # Retreives the fixture by the given table name. Raises an error if the fixture has # not yet been loaded. def fixture(table_name) fixture = all_loaded_fixtures[table_name.to_s] raise ArgumentError, "No fixture loaded for: #{table_name}" unless fixture fixture end protected def index_fixtures(fixtures) # first find entries with an id and record the ids so that they will be skipped skip_indicies = [] fixtures.each_pair do |name, fixture| skip_indicies << fixture["id"].to_i if fixture.has_key?("id") end # next find and index entries that do not have an id defined index = fixtures.offset fixtures.each_pair do |name, fixture| # skip entries that already have an id defined next if fixture.has_key?("id") # find the next available index # note this must happen before the id assignment, # in case index 1 is marked for skipping while true index += 1 break unless skip_indicies.include?(index) end fixture["id"] = index end end def resolve_references(fixtures) fixtures.each_pair do |name, fixture| # search the fixture for join references fixture.each_pair do |join_ref, join_name| # next if the key isn't a join reference next unless join_ref.kind_of?(Array) foreign_key = join_ref.first join_table_name = join_ref.last # next if the foreign key is already defined next if fixture.has_key?(foreign_key) begin # raise an error if the join table isn't loaded; the reference cannot be resolved unless Fixtures.all_loaded_fixtures.has_key?(join_table_name) raise ArgumentError, "The join table '#{join_table_name}' has not been loaded." end join_fixtures = Fixtures.all_loaded_fixtures[join_table_name] # raise an error if the join entry isn't in the join table; the reference cannot be resolved unless join_fixtures.has_key?(join_name) raise ArgumentError, "The join entry '#{join_name}' doesn't exist in '#{join_table_name}'." end join_entry = join_fixtures[join_name] # raise an exception if a join_id was not found unless join_entry.has_key?("id") raise ArgumentError, "No id present in join entry '#{join_name}'." end rescue raise ArgumentError, "Cannot resolve reference '#{join_reference} => #{join_name}' in '#{@table_name}.#{name}'. #{$!}" end # set the join id fixture[foreign_key] = join_entry["id"] end # delete the join references fixture.delete_if {|key,value| key.kind_of?(Array) } end end end end