Created
October 1, 2010 17:44
-
-
Save riethmayer/606556 to your computer and use it in GitHub Desktop.
Create Factory unless model exists
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# spec/support/factory_helper.rb | |
module FactoryHelper | |
def self.included(base) | |
base.send(:include, FactoryHelper::InstanceMethods) | |
end | |
module InstanceMethods | |
# Extracts a klass name and the attribute name out of a string | |
# like this: find_or_create_factory_KLASS_NAME_by_ATTRIBUTE | |
# It returns the Class of KLASS_NAME if defined and the ATTRIBUTE | |
# In case KLASS_NAME is no valid constant, the String "KLASS_NAME" | |
# is returned. | |
# ==== Parameters | |
# name of a method | |
def extract_class_and_attributes_from name | |
regexp = /^find_or_create_factory_(.+?)_by_(.+?)$/ | |
attribute = name.to_s | |
return name unless attribute =~ regexp | |
klass_name = $1.capitalize | |
attribute_name = $2 | |
if Kernel.const_defined?(klass_name) | |
[Kernel.const_get(klass_name), attribute_name] | |
else | |
[klass_name, attribute_name] | |
end | |
end | |
# intercepts methods which look like | |
# /^find_or_create_factory_(.+?)_by_(.+?)$/ as where the first | |
# braces match the factory name and the second braces match the | |
# primary attribute you're searching for. | |
# ==== Parameters | |
# name of the method | |
# args for the method | |
def method_missing(name, *args) | |
klass, attribute = extract_class_and_attributes_from name | |
if klass.class == String || attribute.blank? | |
super(name, *args) | |
else | |
find_or_create_factory(klass, attribute, *args) | |
end | |
end | |
private | |
# finds an object or creates one, where the first attribute must | |
# be the field you're searching for (so this must be unique). | |
# | |
# ==== Parameters | |
# klass_name: the name of your model | |
# attributes: e.g. :title => "foo", :bar => "bar" | |
def find_or_create_factory klass, attribute, *attributes | |
attribute = attribute.to_sym | |
obj = klass.send(:where, attribute => attributes[0][attribute]).first | |
obj || Factory(klass.to_s.downcase.to_sym, *attributes) | |
end | |
end | |
end | |
# spec/models/factory_spec_helper.rb | |
require 'spec_helper' | |
describe FactoryHelper do | |
include FactoryHelper | |
describe "#find_or_create_factory_KLASS_NAME_by_ATTRIBUTE" do | |
describe "name extraction" do | |
it "should return the name itself if it doesn't match" do | |
name = "foo" | |
extract_class_and_attributes_from(name).should == name | |
end | |
it "should return the matching klass_name and attribute if the regex matches" do | |
method_name = "find_or_create_factory_klass_by_ATTRIBUTE" | |
name, attribute = extract_class_and_attributes_from method_name | |
name.should == "Klass" | |
attribute.should == "ATTRIBUTE" | |
end | |
it "should convert into a constant if the class has been found" do | |
method_name = "find_or_create_factory_organization_by_ATTRIBUTE" | |
name, attribute = extract_class_and_attributes_from method_name | |
name.should == Organization | |
attribute.should == "ATTRIBUTE" | |
end | |
end | |
describe "finding part" do | |
it "should find an existing organization" do | |
organization = Factory(:organization, :title => "foo") | |
found = find_or_create_factory_organization_by_title(:title => "foo") | |
found.should == organization | |
end | |
end | |
describe "creating part" do | |
it "should create a nonexisting organization" do | |
organization = Organization.find_by_title "foo" | |
organization.destroy! if organization | |
Organization.find_by_title("foo").should be_nil | |
find_or_create_factory_organization_by_title(:title => "foo").should_not be_nil | |
Organization.find_by_title("foo").should_not be_nil | |
end | |
it "should raise a method missing if you try to create nonsense" do | |
lambda {find_or_create_something_nonexistant_by_foo(:foo => "foo")}. | |
should raise_error | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment