def mock_model(string_or_model_class, options_and_stubs = {})
if String === string_or_model_class
if Object.const_defined?(string_or_model_class)
model_class = Object.const_get(string_or_model_class)
else
model_class = Object.const_set(string_or_model_class, Class.new do
extend ActiveModel::Naming
end)
end
else
model_class = string_or_model_class
end
unless model_class.kind_of? ActiveModel::Naming
raise ArgumentError.new "The mock_model method can only accept as its first argument:\n* A String representing a Class that does not exist\n* A String representing a Class that extends ActiveModel::Naming\n* A Class that extends ActiveModel::Naming\n\nIt received \#{model_class.inspect}\n"
end
id = options_and_stubs.has_key?(:id) ? options_and_stubs[:id] : next_id
options_and_stubs = options_and_stubs.reverse_merge({
:id => id,
:destroyed? => false,
:marked_for_destruction? => false
})
derived_name = "#{model_class.name}_#{id}"
m = mock(derived_name, options_and_stubs)
m.extend InstanceMethods
m.extend ActiveModel::Conversion
errors = ActiveModel::Errors.new(m)
[:save, :update_attributes].each do |key|
if options_and_stubs[key] == false
errors.stub(:empty?) { false }
end
end
m.stub(:errors) { errors }
m.__send__(:__mock_proxy).instance_eval("def @object.is_a?(other)\n\#{model_class}.ancestors.include?(other)\nend\ndef @object.kind_of?(other)\n\#{model_class}.ancestors.include?(other)\nend\ndef @object.instance_of?(other)\nother == \#{model_class}\nend\ndef @object.class\n\#{model_class}\nend\ndef @object.to_s\n\"\#{model_class.name}_\#{id}\"\nend\n", __FILE__, __LINE__)
yield m if block_given?
m
end