Skip to content

Instantly share code, notes, and snippets.

@jemmyw
Created April 16, 2011 02:38
Show Gist options
  • Save jemmyw/922804 to your computer and use it in GitHub Desktop.
Save jemmyw/922804 to your computer and use it in GitHub Desktop.
World(FactoryGirlStepHelpers)
module DataStepHelpers
def str_to_name(str)
str.to_s.strip.gsub(/\s+/m, '_').underscore
end
def get_instance(name)
instance_variable_get('@%s' % str_to_name(name).singularize)
end
def db_token(str)
eval("\"#{str.gsub(/"/m, '\"')}\"")
end
# Find the association on an active record object
def find_association_by_name(instance, name)
name = str_to_name(name)
instance.class.reflect_on_association(name.to_s.singularize.to_sym) ||
instance.class.reflect_on_association(name.to_s.pluralize.to_sym)
end
# Find the first association that accepts the given object on an active record object
# A macro can be passed specifying the type of association (:belongs_to, :has_many, :has_one)
def find_association_for(instance, object, macro=nil)
instance.class.reflect_on_all_associations(macro).detect do |association|
if association.options[:polymorphic]
unless association.collection?
association.active_record == object
end
else
object.is_a?(association.klass)
end
end
end
# Given an instance, object and association on the instance, finds the inverse
# association on the object for the instance.
def find_inverse_association(instance, object, association)
if association.collection?
find_association_for(object, instance, :belongs_to)
else
find_association_for(object, instance, :has_many)
end
end
# Assign one object to another. This involves searching the first
# objects methods for assignment or collection associated with the
# second object. If invert is true then this will run the same
# method inverted.
def assign_object_without_association(instance, object, invert = true)
member_object_method_name = object.class.name.underscore + '='
collection_object_method_name = object.class.name.pluralize.underscore
if invert
assign_object_without_association(object, instance, false) rescue nil
end
if instance.respond_to?(member_object_method_name)
instance.send(member_object_method_name, object)
elsif instance.respond_to?(collection_object_method_name)
instance.send(collection_object_method_name) << object
else
fail "Could not associate #{object.class.name} with #{instance.class.name}"
end
instance.save!
instance.reload
end
# Assign an object to an association
def assign_to_association(instance, object, association)
if association.collection?
proxy = instance.send(association.name)
proxy << object
else
instance.send('%s=' % association.name, object)
end
end
# Assign an object to an instanc eusing an association
def assign_object_with_association(instance, object, association, invert = true)
inverse_association = association.inverse_of || find_inverse_association(instance, object, association)
assign_to_association(instance, object, association)
if invert && inverse_association
assign_to_association(object, instance, inverse_association)
object.save!
end
instance.save!
instance.reload
object.reload
end
# Assign an object to an instance. Can specify an association name or object to use. Can
# specify invert to assign the instance to the object as well.
def assign_object_to_instance(instance, object, association_name_or_object = nil, invert = true)
association = association_name_or_object
if association.nil?
association = find_association_for(instance, object)
elsif association.is_a?(String) || association.is_a?(Symbol)
association = find_association_by_name(instance, association)
end
if association.nil?
assign_object_without_association(instance, object, invert)
else
assign_object_with_association(instance, object, association, invert)
end
end
end
World(DataStepHelpers)
Given /^there is an? ([^:]+)$/ do |factory_name|
factory_name = str_to_name(factory_name)
factory = Factory.factories[factory_name.to_sym]
object = Factory(factory.factory_name)
instance_variable_set('@%s' % factory_name.singularize, object)
end
Given /^there is an? (.+):$/ do |factory_name, table|
factory_name = str_to_name(factory_name)
factory = Factory.factories[factory_name.to_sym]
rows = [table.headers] + table.rows
attributes = convert_human_hash_to_attribute_hash(Hash[*rows.flatten], factory.associations)
object = Factory(factory.factory_name, attributes)
instance_variable_set('@%s' % factory_name.singularize, object)
end
Given /^the (.+) has an? ([^:]+)$/ do |instance, association_name|
instance = get_instance(instance)
association = find_association_by_name(instance, association_name)
# If we can't find the association, find the factory and work it out from there
if association.nil?
factory = Factory.factories[str_to_name(association_name).to_sym]
association_name = nil
else
factory = Factory.factories[association.class_name.underscore.to_sym]
end
object = Factory.build(factory.factory_name)
assign_object_to_instance(instance, object, association_name) rescue nil # don't worry if we couldn't assign
instance_variable_set('@%s' % factory.factory_name.to_s.singularize, object)
end
Given /^the (.+) has an? (.+):$/ do |instance, association_name, table|
instance = get_instance(instance)
association = find_association_by_name(instance, association_name)
# If we can't find the association, find the factory and work it out from there
if association.nil?
factory = Factory.factories[str_to_name(association_name).to_sym]
association_name = nil
else
factory = Factory.factories[association.class_name.underscore.to_sym]
end
rows = [table.headers] + table.rows
attributes = convert_human_hash_to_attribute_hash(Hash[*rows.flatten], factory.associations)
object = Factory.build(factory.factory_name, attributes)
assign_object_to_instance(instance, object, association_name)
instance_variable_set('@%s' % factory.factory_name.to_s.singularize, object)
end
Given /^the (.+) is associated with the (.+?)(?: by (.+))?$/ do |child, instance, association_name|
instance = get_instance(instance)
child = get_instance(child)
assign_object_to_instance(instance, child, association_name)
end
Given /^the (.+) has (.+) set to "([^"]*)"$/ do |instance, field, value|
instance = get_instance(instance)
value = case value
when 'nil'
nil
when /^\d+$/
value.to_d
when /^#\{/
db_token(value)
else
value
end
instance.send('%s=' % field, value)
instance.save!
instance.reload
end
Then /^the (.+) should have (.+) set to "([^"]*)"$/ do |instance, field, value|
get_instance(instance).reload.send(field).to_s.should == value
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment