module Spec::Rails::Mocks

def add_stubs(object, stubs = {}) #:nodoc:

:nodoc:
with that name will be created). +stubs+ is a Hash of +method=>value+
Stubs methods on +object+ (if +object+ is a symbol or string a new mock

DEPRECATED - use object.stub!(:method => value, :method2 => value)
def add_stubs(object, stubs = {}) #:nodoc:
  Kernel.warn <<-WARNING
ATION NOTICE: add_stubs is deprecated and will be removed
 future version of rspec-rails. Use this instead:
ct.stub!(:method => value, :method2 => value)
G
  object.stub!(stubs)
end

def mock_model(model_class, options_and_stubs = {})

add_stubs) if +stubs+ is passed.
methods stubbed out. Additional methods may be easily stubbed (via
Creates a mock object instance for a +model_class+ with common
def mock_model(model_class, options_and_stubs = {})
  id = options_and_stubs[:id] || next_id
  options_and_stubs = options_and_stubs.reverse_merge({
    :id => id,
    :to_param => id.to_s,
    :new_record? => false,
    :errors => stub("errors", :count => 0)
  })
  m = mock("#{model_class.name}_#{id}", options_and_stubs)
  m.__send__(:__mock_proxy).instance_eval <<-CODE
    def @target.as_new_record
      self.stub!(:id).and_return nil
      self.stub!(:to_param).and_return nil
      self.stub!(:new_record?).and_return true
      self
    end
    def @target.is_a?(other)
      #{model_class}.ancestors.include?(other)
    end
    def @target.kind_of?(other)
      #{model_class}.ancestors.include?(other)
    end
    def @target.instance_of?(other)
      other == #{model_class}
    end
    def @target.class
      #{model_class}
    end
  CODE
  yield m if block_given?
  m
end

def next_id

def next_id
  @@model_id += 1
end

def stub_model(model_class, stubs={})

end
person.first_name = "David"
stub_model(Person) do |person|
stub_model(Person, :id => 37)
stub_model(Person).as_new_record
stub_model(Person)

== Examples

a look at libraries like unit_record or NullDB.
from the object itself. To completely decouple from the database, take
loading up its columns from the database. It just prevents data access
database-independent. It does not stop the model class itself from
+stub_model+ does not make your examples entirely

== Database Independence

inherently more state-based than interaction-based.
helper), it is especially useful in view examples, which are
While you can use stub_model in any example (model, view, controller,

example a bit more descriptive.
case new_record? will return true, but using +as_new_record+ makes the
set the id to nil. You can also explicitly set :id => nil, in which
the object to behave as a new record, sending it +as_new_record+ will
This means that by default new_record? will return false. If you want
new_record? is overridden to return the result of id.nil?

mocking/stubbing framework.
key/value pair is assigned as a stub return value using RSpec's
submitted values. If the model does not have a matching attribute, the
matching attribute (determined by asking it) are simply assigned the
database*. For each key in +hash_of_stubs+, if the model has a
Creates an instance of +Model+ that is prohibited from accessing the

stub_model(Model, instance_variable_name, hash_of_stubs)
stub_model(Model, hash_of_stubs)
stub_model(Model).as_new_record
stub_model(Model)
:call-seq:
def stub_model(model_class, stubs={})
  stubs = {:id => next_id}.merge(stubs)
  returning model_class.new do |model|
    model.id = stubs.delete(:id)
    model.extend ModelStubber
    stubs.each do |k,v|
      if model.has_attribute?(k)
        model[k] = stubs.delete(k)
      end
    end
    model.stub!(stubs)
    yield model if block_given?
  end
end