Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add table-specific configuration #64

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ pkg/
.idea/*
*.db
tmp/fixture_builder.yml
test/fixtures/magical_creatures.yml
test/fixtures/**/*.yml
Gemfile.lock
*.gem
48 changes: 22 additions & 26 deletions lib/fixture_builder/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,38 +92,33 @@ def dump_empty_fixtures_for_all_tables
end

def dump_tables
default_date_format = Date::DATE_FORMATS[:default]
Date::DATE_FORMATS[:default] = Date::DATE_FORMATS[:db]
begin
fixtures = tables.inject([]) do |files, table_name|
table_klass = table_name.classify.constantize rescue nil
if table_klass && table_klass < ActiveRecord::Base
rows = table_klass.unscoped do
table_klass.order(:id).all.collect do |obj|
attrs = obj.attributes.select { |attr_name| table_klass.column_names.include?(attr_name) }
attrs.inject({}) do |hash, (attr_name, value)|
hash[attr_name] = serialized_value_if_needed(table_klass, attr_name, value)
hash
end
fixtures = tables.inject([]) do |files, table_name|
table_klass = fixture_classes[table_name] || table_name.classify.constantize rescue nil
if table_klass && table_klass < ActiveRecord::Base
rows = table_klass.unscoped do
table_klass.order(:id).all.collect do |obj|
attrs = obj.attributes.select { |attr_name| table_klass.column_names.include?(attr_name) }
attrs.inject({}) do |hash, (attr_name, value)|
hash[attr_name] = serialized_value_if_needed(table_klass, attr_name, value)
hash
end
end
else
rows = ActiveRecord::Base.connection.select_all(select_sql % {table: ActiveRecord::Base.connection.quote_table_name(table_name)})
end
next files if rows.empty?
else
rows = ActiveRecord::Base.connection.select_all(select_sql % {table: ActiveRecord::Base.connection.quote_table_name(table_name)})
end
next files if rows.empty?

row_index = '000'
fixture_data = rows.inject({}) do |hash, record|
hash.merge(record_name(record, table_name, row_index) => record)
end
row_index = '000'
fixture_data = rows.inject({}) do |hash, record|
hash.merge(record_name(record, table_name, row_index) => record)
end

write_fixture_file fixture_data, table_name
write_fixture_file fixture_data, table_name

files + [File.basename(fixture_file(table_name))]
end
ensure
Date::DATE_FORMATS[:default] = default_date_format
files + [File.basename(fixture_file(table_name))]
end

say "Built #{fixtures.to_sentence}"
end

Expand Down Expand Up @@ -154,7 +149,8 @@ def write_fixture_file(fixture_data, table_name)
end

def fixture_file(table_name)
fixtures_dir("#{table_name}.yml")
file_name = fixture_files[table_name] || table_name
fixtures_dir("#{file_name}.yml")
end
end
end
40 changes: 39 additions & 1 deletion lib/fixture_builder/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,45 @@ def fixture_directory
end

def fixtures_dir(path = '')
File.expand_path(File.join(fixture_directory, path))
subdirs = path.split('/')
path = subdirs.pop || ''
dir = File.expand_path(File.join(fixture_directory, *subdirs))

FileUtils.mkdir_p(dir)
File.join(dir, path)
end

# This allows for configuring fixtures for a given database table; you may
# set the model class for the table (e.g. for legacy tables) and the name
# of the resulting fixture file for the table (e.g. for nested fixtures).
#
# For example:
#
# FixtureBuilder.configure do |fbuilder|
# fbuilder.configure_tables(wibbles: {
# class: Legacy::Things,
# file: 'legacy/things'
# })
# end
#
# This will tell the builder to use the `Legacy::Things` class to serialize
# fixtured dumped from the `wibbles` table, and to dump the `wibbles` table
# into the `legacy_things.yml` file. This also works with nested
# directories, which will map to namespaced fixtures.
def configure_tables(configuration)
configuration.each do |table_name, table_config|
table_name = table_name.to_s
fixture_classes.merge!(table_name => table_config[:class])
fixture_files.merge!(table_name => table_config[:file])
end
end

def fixture_classes
@fixture_classes ||= {}
end

def fixture_files
@fixture_files ||= {}
end

private
Expand Down
2 changes: 1 addition & 1 deletion lib/fixture_builder/delegations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module FixtureBuilder
module Delegations
module Configuration
def self.included(base)
methods_to_delegate = [:fixtures_dir, :tables, :legacy_fixtures].concat(::FixtureBuilder::Configuration::ACCESSIBLE_ATTRIBUTES).flatten
methods_to_delegate = [:fixtures_dir, :tables, :legacy_fixtures, :fixture_classes, :fixture_files].concat(::FixtureBuilder::Configuration::ACCESSIBLE_ATTRIBUTES).flatten
methods_to_delegate.each do |meth|
base.delegate(meth, :to => :@configuration)
end
Expand Down
6 changes: 3 additions & 3 deletions lib/fixture_builder/namer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def name(custom_name, *model_objects)
raise "Cannot name an object blank" unless custom_name.present?
model_objects.each do |model_object|
raise "Cannot name a blank object" unless model_object.present?
key = [model_object.class.table_name, model_object.id]
key = [model_object.class.table_name, model_object.id.to_s]
raise "Cannot set name for #{key.inspect} object twice" if @custom_names[key]
@custom_names[key] = custom_name
model_object
Expand All @@ -34,15 +34,15 @@ def populate_custom_names(created_fixtures)
# Rails 3.0 and earlier, create_fixtures returns an array of tuples
created_fixtures.each do |fixture|
name = fixture[0]
id = fixture[1]['id'].to_i
id = fixture[1]['id'].to_s
table_name = fixture[1].model_class.table_name
key = [table_name, id]
@custom_names[key] = name
end
end

def record_name(record_hash, table_name, row_index)
key = [table_name, record_hash['id'].to_i]
key = [table_name, record_hash['id'].to_s]
name = case
when name_proc = @model_name_procs[table_name]
name_proc.call(record_hash, row_index.succ!)
Expand Down
82 changes: 81 additions & 1 deletion test/fixture_builder_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ def test_ivar_naming
assert_equal 'king_of_gnomes', generated_fixture.keys.first
end

def test_ivar_naming_with_uuid_primary_key
create_and_blow_away_old_db
force_fixture_generation

FixtureBuilder.configure do |fbuilder|
fbuilder.files_to_check += Dir[test_path("*.rb")]
fbuilder.factory do
@you_know_who = Unnameable.create!
end
end
generated_fixture = YAML.load(File.open(test_path("fixtures/unnameables.yml")))
assert_equal 'you_know_who', generated_fixture.keys.first
end

def test_serialization
create_and_blow_away_old_db
force_fixture_generation
Expand Down Expand Up @@ -80,7 +94,13 @@ def test_absolute_rails_fixtures_path
end

def test_fixtures_dir
assert_match /test\/fixtures$/, FixtureBuilder.configuration.send(:fixtures_dir).to_s
file_path = "wibble.yml"
assert_match(/test\/fixtures\/#{file_path}$/, FixtureBuilder.configuration.send(:fixtures_dir, file_path).to_s)
end

def test_nested_fixtures_dir
file_path = "foo/bar/wibble.yml"
assert_match(/test\/fixtures\/#{file_path}$/, FixtureBuilder.configuration.send(:fixtures_dir, file_path).to_s)
end

def test_rebuilding_due_to_differing_file_hashes
Expand Down Expand Up @@ -115,4 +135,64 @@ def test_sha1_digests
assert_equal first_modified_time, second_modified_time
end
end

def test_set_fixture_class
create_and_blow_away_old_db
force_fixture_generation

old_klass = MagicalCreature
new_klass = Class.new(ActiveRecord::Base) do
self.table_name = "magical_creatures"
serialize :powers, Array
end
Object.instance_eval { remove_const(:MagicalCreature) }

FixtureBuilder.configure do |fbuilder|
fbuilder.configure_tables(magical_creatures: { class: new_klass })

fbuilder.files_to_check += Dir[test_path("*.rb")]
fbuilder.factory do
@enty = new_klass.create(:name => 'Enty', :species => 'ent',
:powers => %w{shading rooting seeding})
end
end
generated_fixture = YAML.load(File.open(test_path("fixtures/magical_creatures.yml")))
assert_equal "---\n- shading\n- rooting\n- seeding\n", generated_fixture['enty']['powers']
ensure
Object.const_set(:MagicalCreature, old_klass)
end

def test_set_fixture_file
create_and_blow_away_old_db
force_fixture_generation

FixtureBuilder.configure do |fbuilder|
fbuilder.configure_tables(magical_creatures: { file: "wibbles" })

fbuilder.files_to_check += Dir[test_path("*.rb")]
fbuilder.factory do
@enty = MagicalCreature.create(:name => 'Enty', :species => 'ent',
:powers => %w{shading rooting seeding})
end
end
generated_fixture = YAML.load(File.open(test_path("fixtures/wibbles.yml")))
assert_equal "---\n- shading\n- rooting\n- seeding\n", generated_fixture['enty']['powers']
end

def test_set_fixture_file_with_namespace
create_and_blow_away_old_db
force_fixture_generation

FixtureBuilder.configure do |fbuilder|
fbuilder.configure_tables(magical_creatures: { file: "legacy/wibbles" })

fbuilder.files_to_check += Dir[test_path("*.rb")]
fbuilder.factory do
@enty = MagicalCreature.create(:name => 'Enty', :species => 'ent',
:powers => %w{shading rooting seeding})
end
end
generated_fixture = YAML.load(File.open(test_path("fixtures/legacy/wibbles.yml")))
assert_equal "---\n- shading\n- rooting\n- seeding\n", generated_fixture['enty']['powers']
end
end
25 changes: 20 additions & 5 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,34 @@ class MagicalCreature < ActiveRecord::Base
end
end

class Unnameable < ActiveRecord::Base; end

def create_and_blow_away_old_db
ActiveRecord::Base.configurations['test'] = {
'adapter' => 'sqlite3',
'database' => 'test.db'
}
if ActiveRecord::VERSION::MAJOR >= 7
ActiveRecord::Base.configurations = {
test: {
'adapter' => 'sqlite3',
'database' => 'test.db'
}
}
else
ActiveRecord::Base.configurations['test'] = {
'adapter' => 'sqlite3',
'database' => 'test.db'
}
end
ActiveRecord::Base.establish_connection(:test)

ActiveRecord::Base.connection.create_table(:magical_creatures, :force => true) do |t|
ActiveRecord::Base.connection.create_table(:magical_creatures, force: true) do |t|
t.column :name, :string
t.column :species, :string
t.column :powers, :string
t.column :deleted, :boolean, :default => false, :null => false
end

ActiveRecord::Base.connection.create_table(:unnameables, force: true, id: false) do |t|
t.column :id, :uuid, primary: true
end
end

def force_fixture_generation
Expand Down