volontariat/voluntary

View on GitHub
dummy/features/step_definitions/factory_steps.rb

Summary

Maintainability
D
2 days
Test Coverage
module FactoryMethods
  def create_from_table(model_name, table, extra = {})
    factory_name = model_name.gsub(/\W+/, '_').downcase.singularize.to_sym
    is_singular = model_name.to_s.singularize == model_name.to_s
    
    hashes = if is_singular
       if table.kind_of?(Hash)
         [table]
       else
         [table.rows_hash]
       end
     elsif table.is_a?(Array)
       table
     else
       table.hashes
     end
            
    @klass = factory_name.to_s.classify.constantize
    @they = hashes.map do |hash|
      hash = hash.merge(extra).inject({}) do |h,(k,v)|
        k = k.gsub(/\W+/,'_')
        
        # mongo db model classes are not responding to serialized attributes
        # TODO: take care of serialized attributes in future mongo db model implementations here
        if @klass.respond_to?(:serialized_attributes) && @klass.serialized_attributes[k] == Array
          v = v.split(/\s*,\s*/)
        end
        
        h.update(k.to_sym => v)
      end
      
      hash.keys.each do |attribute|
        set_value(hash, attribute)
      end
      
      eval("set_#{factory_name}_defaults(hash)") if "#{factory_name.to_s.classify}FactoryMethods".constantize rescue nil
      
      object = nil
      
      object = @klass.where(name: hash[:name]).first if hash.has_key? :name
      object = object ? object : Factory.build(factory_name, hash)
      
      yield object if block_given?
      
      object.save!
      
      object
    end
    
    if is_singular
      @it = @they.last
      instance_variable_set("@#{factory_name}", @it)
    end
  end
  
  private
  
  def set_value(hash, attribute)
    value = hash[attribute]
    
    if value.match '@' 
      if eval(value)
        hash[attribute] = eval(value) 
      else
        hash.delete attribute
      end
    elsif @klass.reflections.values.select{|v| v.macro == :belongs_to }.map(&:name).include? attribute
      reflection_value = @klass.reflections.values.select{|v| v.name == attribute }.first
      
      if reflection_value.options[:polymorphic]
        polymorphic_type = "#{@klass.name}::#{attribute.to_s.upcase}_TYPES".constantize.first
        resource = polymorphic_type.classify.constantize.find_by_name(value)
        hash[attribute] = resource || create_from_table(polymorphic_type.tableize, [{ 'name' => value }])
      else
        resource = attribute.to_s.classify.constantize.find_by_name(value)
        hash[attribute] = resource || create_from_table(attribute.to_s.tableize, [{ 'name' => value }])
      end
    end
  end
end

World(FactoryMethods)

Given %r{^I have a (.+)$} do |model_name|
  create_from_table(model_name, {}, 'user' => @me)
end

Given %r{^I have the following (.+):$} do |child, table|
  step "that me has the following #{child}:", table
end

Given %r{^the following (.+):$} do |model_name, table|
  create_from_table(model_name, table)
end

Given %r{^that (.+) has the following (.+):$} do |parent, child, table|
  child= child.gsub(/\W+/,'_')
  parent = parent.gsub(/\W+/,'_').downcase.sub(/^_/, '')
  parent_instance = instance_variable_get("@#{parent}")
  parent_class = parent_instance.class
  
  if assoc = parent_class.reflect_on_association(child.to_sym) || parent_class.reflect_on_association(child.pluralize.to_sym)
    parent = (assoc.options[:as] || parent).to_s
    child = (assoc.options[:class_name] || child).to_s
  end
  
  if child.classify.constantize.method_defined?(parent.pluralize)
    create_from_table(child, table, parent.pluralize => [parent_instance])
  elsif child.classify.constantize.method_defined?(parent)
    create_from_table(child, table, parent => parent_instance)
  else
    create_from_table(child, table)
    
    if assoc.macro == :has_many
      parent_instance.send("#{assoc.name}=", @they)
    else
      parent_instance.send("#{assoc.name}=", @they.first)
    end
  end
end