# Creates specially named factory methods for easily instantiating new model
# objects with a set of preloaded data. The name of the helper methods
# are based on the name of the model under test. model_factory_helper
# generates several methods that can be used in your specs.
#
# model_factory_helper also automatically generates a specification which
# verifies that your model should be valid when instantiated using the
# default_attributes that you supplied.
#
# == Calling
# Currently model_factory_helper must be passed:
# * A reference to the context that the spec is run (+self+)
# * The reference to the model class under test
# * A <tt>:default_attributes</tt> option, which should be a Hash of all the default
# values for the model's attributes.
#
# == Generated Methods
# TODO: Document model_factory_helper generated methods
#
# == Example
# A typical (horribly contrived) spec for a basic model could look like:
# model_factory_helper(self, Person, :default_attributes => { :name => "Steve", :vegetarian => false })
#
# describe User do
# it_should_require_fields :name
#
# before(:each) do
# @user = user_with(:all)
# end
#
# it "should allow user to eat_meat by default" do
# lambda { @user.eat_meat }.should_not raise_error
# end
#
# it "should raise error when vegetarians eat meat" do
# lambda { user_with(:vegetarian => true).eat_meat }.should raise_error
# end
# end
def model_factory_helper(calling_spec, model_class, options)
raise "factory_method requires default_attributes" unless options.has_key?(:default_attributes)
raise "factory_method default_attributes must be a Hash" unless options[:default_attributes].is_a?(Hash)

proper_class_name = model_class.name
lowered_class_name = model_class.name.downcase

calling_spec.instance_eval <<-"end;"
module #{proper_class_name}HelperFactory

def #{lowered_class_name}_default_attributes(options = {})
#{options[:default_attributes].inspect}.merge(options)
end

def #{lowered_class_name}_with(options = {})
options = {} if options == :all
#{proper_class_name}.new(#{lowered_class_name}_default_attributes(options))
end

def #{lowered_class_name}_without(field)
#{proper_class_name}.new(#{lowered_class_name}_default_attributes(field => nil))
end

def it_should_require_fields(*fields)
fields.each do |field|
it "should be invalid without \#{field} attribute" do
#{lowered_class_name}_without(field).should_not be_valid
end
end
end
alias it_should_require_field it_should_require_fields

describe #{proper_class_name}, "instantiated with default attributes" do
it "should be valid" do
#{lowered_class_name}_with(:all).should be_valid
end
end
end

include #{proper_class_name}HelperFactory
end;
end