Permalink
Browse files

added ModelDefinition::StubProxy so that you can relate stubs to othe…

…r stubs that haven't been created yet.
  • Loading branch information...
1 parent 90e93a5 commit 2d72b3d8396a3a6576185c2341cf2834198b8bdf @technoweenie committed Aug 27, 2008
View
@@ -2,6 +2,7 @@
require 'model_stubbing/definition'
require 'model_stubbing/model'
require 'model_stubbing/stub'
+require 'model_stubbing/stub_proxy'
module ModelStubbing
# Gets a hash of all current definitions.
@@ -112,16 +112,7 @@ def connection
protected
def method_missing(model_name, stub_name, *args)
- named_model = @definition.models[model_name]
- if named_model.nil?
- raise "No #{model_name.inspect} model found when calling #{model_name}(#{stub_name})"
- end
- stub = named_model.stubs[stub_name]
- if stub.nil?
- raise "No #{stub_name.inspect} stub found in the #{model_name.inspect} model when calling #{model_name}(#{stub_name})"
- else
- stub
- end
+ StubProxy.new(@definition, model_name, stub_name)
end
end
end
View
@@ -47,7 +47,13 @@ def record(attributes = {})
ModelStubbing.records[this_record_key] = instantiate(this_record_key, attributes)
end
end
-
+
+ # Same as #record, but does not instantiate stubs.
+ def record_without_stubs
+ this_record_key = record_key(attributes)
+ instantiate(this_record_key, attributes, false)
+ end
+
def inspect
"(ModelStubbing::Stub(#{@name.inspect} => #{attributes.inspect}))"
end
@@ -69,7 +75,7 @@ def insert(attributes = {})
def with(attributes)
@attributes.inject({}) do |attr, (key, value)|
attr_value = attributes[key] || value
- attr_value = attr_value.record if attr_value.is_a?(Stub)
+ attr_value = attr_value.record if (attr_value.is_a?(Stub) || attr_value.is_a?(StubProxy))
attr.update key => attr_value
end
end
@@ -78,7 +84,7 @@ def only(*keys)
keys = Set.new Array(keys)
@attributes.inject({}) do |attr, (key, value)|
if keys.include?(key)
- attr.update key => (value.is_a?(Stub) ? value.record : value)
+ attr.update key => ((value.is_a?(Stub) || value.is_a?(StubProxy)) ? value.record : value)
else
attr
end
@@ -91,17 +97,22 @@ def except(*keys)
if keys.include?(key)
attr
else
- attr.update key => (value.is_a?(Stub) ? value.record : value)
+ attr.update key => ((value.is_a?(Stub) || value.is_a?(StubProxy)) ? value.record : value)
end
end
end
def connection
@connection ||= @model.connection
end
-
+
+ # duck typing with StubProxy
+ def method_name
+ nil
+ end
+
private
- def instantiate(this_record_key, attributes)
+ def instantiate(this_record_key, attributes, with_stubs = true)
case attributes[:id]
when :new
is_new_record = true
@@ -128,26 +139,35 @@ def instantiate(this_record_key, attributes)
record.stubbed_attributes = stubbed_attributes.merge(:id => record.id)
stubbed_attributes.each do |key, value|
meta.send :attr_accessor, key unless record.respond_to?("#{key}=")
- if value.is_a? Stub
- # set foreign key
- record.send("#{stubbed_attributes.column_name_for(key)}=", value.record.id)
- # set association
- record.send("#{key}=", value.record)
- elsif value.is_a? Array
- records = value.map { |v| v.is_a?(Stub) ? v.record : v }
- records.compact!
-
- # when assigning has_many instantiated stubs, temporarily act as new
- # otherwise AR inserts rows
- nr, record.new_record = record.new_record?, true
- record.send("#{key}=", records)
- record.new_record = nr
- else
- duped_value = case value
- when TrueClass, FalseClass, Fixnum, Float, NilClass, Symbol then value
- else value.dup
- end
- record.send("#{key}=", duped_value)
+ case value
+ when StubProxy, Stub
+ if with_stubs
+ if value.method_name
+ record.send("#{key}=", value.record_without_stubs)
+ else
+ # set foreign key
+ record.send("#{stubbed_attributes.column_name_for(key)}=", value.record_without_stubs.id)
+ # set association
+ record.send("#{key}=", value.record)
+ end
+ end
+ when Array
+ if with_stubs
+ records = value.map { |v| (v.is_a?(Stub) || v.is_a?(StubProxy)) ? v.record : v }
+ records.compact!
+
+ # when assigning has_many instantiated stubs, temporarily act as new
+ # otherwise AR inserts rows
+ nr, record.new_record = record.new_record?, true
+ record.send("#{key}=", records)
+ record.new_record = nr
+ end
+ else
+ duped_value = case value
+ when TrueClass, FalseClass, Fixnum, Float, NilClass, Symbol then value
+ else value.dup
+ end
+ record.send("#{key}=", duped_value)
end
end
record
@@ -182,7 +202,11 @@ def value_list
list = inject([]) do |fixtures, (key, value)|
column_name = column_name_for key
column = column_for column_name
- value = value.record.id if value.is_a?(Stub)
+ case value
+ when Stub then value = value.record_without_stubs.id
+ when StubProxy
+ value = value.method_name ? value.record : value.record_without_stubs.id
+ end
quoted = @stub.connection ? @stub.connection.quote(value, column) : %("#{value.to_s}")
fixtures << quoted.gsub('[^\]\\n', "\n").gsub('[^\]\\r', "\r")
end.join(", ")
@@ -191,12 +215,12 @@ def value_list
def column_name_for(key)
(@keys ||= {})[key] ||= begin
value = self[key]
- if value.is_a? Stub
+ if value.is_a?(Stub) || value.is_a?(StubProxy)
if defined?(ActiveRecord)
if reflection = model_class.reflect_on_association(key)
reflection.primary_key_name
else
- raise "No reflection '#{key}' found for #{model_class.name} while guessing column_name"
+ "#{key}_id".sub(/_id_id/, '_id')
end
else
"#{key}_id"
@@ -0,0 +1,74 @@
+module ModelStubbing
+ # Used when attaching stubs to other stubs in definitions. The stub doesn't
+ # actually have to exist until the Definition is being inserted into the database.
+ #
+ # model Post do
+ # stub :title => 'foo', :author => users(:default)
+ # end
+ #
+ # You can also call specific methods from the stub.
+ #
+ # model Blog do
+ # stub :latest_post => posts(:default), :latest_post_title => posts(:default).title
+ # end
+ #
+ class StubProxy
+ attr_reader :method_name, :proxy_definition, :proxy_model_name, :proxy_stub_name
+
+ def initialize(definition, model_name, stub_name, method_name = nil)
+ @proxy_definition = definition
+ @proxy_model_name = model_name
+ @proxy_stub_name = stub_name
+ @method_name = method_name
+ @model = @stub = nil
+ end
+
+ def record
+ @stub ||= fetch_stub
+ @method_name ? @stub.record_without_stubs.send(@method_name) : @stub.record_without_stubs
+ end
+
+ alias_method :record_without_stubs, :record
+
+ def ==(other)
+ if other.is_a?(StubProxy)
+ other.proxy_definition == @proxy_definition && other.proxy_model_name == @proxy_model_name && other.proxy_stub_name == @proxy_stub_name && other.method_name == @method_name
+ elsif !@method_name && other.is_a?(Stub)
+ other.model.definition == @proxy_definition && other.model.name == @proxy_model_name && @proxy_stub_name == other.name
+ else
+ super
+ end
+ end
+
+ def id
+ method_missing(:id)
+ end
+
+ def inspect
+ "(ModelStubbing::StubProxy[#{@proxy_model_name}(#{@proxy_stub_name.inspect})#{".#{@method_name}" if @method_name}]"
+ end
+
+ protected
+ def fetch_stub
+ @model = @proxy_definition.models[@proxy_model_name]
+ if @model.nil?
+ raise "No #{@proxy_model_name.inspect} model found when calling #{@proxy_model_name}(#{@proxy_stub_name.inspect})"
+ end
+ @stub = @model.stubs[@proxy_stub_name]
+ if @stub.nil?
+ raise "No #{@proxy_stub_name.inspect} stub found in the #{@proxy_model_name.inspect} model when calling #{@proxy_model_name}(#{@proxy_stub_name})"
+ else
+ @stub
+ end
+ end
+
+ def method_missing(name, *args)
+ if args.empty?
+ @method_name = name.to_sym
+ self
+ else
+ super
+ end
+ end
+ end
+end
View
@@ -81,11 +81,11 @@ module ModelStubbing
it "dups each model" do
@defn.models.each do |name, model|
- duped_model = @copy.models[name]
+ duped_model = @copy.models[name]
model.should == duped_model
model.should_not be_equal(duped_model)
model.stubs.each do |key, stub|
- duped_stub = @copy.models[name].stubs[key]
+ duped_stub = @copy.models[name].stubs[key]
stub.should == duped_stub
stub.should_not be_equal(duped_stub)
end
@@ -94,7 +94,7 @@ module ModelStubbing
it "dups each stub" do
@defn.stubs.each do |name, stub|
- duped_stub = @copy.stubs[name]
+ duped_stub = @copy.stubs[name]
stub.should == duped_stub
stub.should_not be_equal(duped_stub)
end
View
@@ -135,13 +135,13 @@ def User.table_name
end
model User do
- stub :admin, :admin => true # inherits from default fixture
+ stub :admin, :admin => true, :edited_post => model_stubbing_posts(:default) # inherits from default fixture
end
model Post do
# uses admin user fixture above
- stub :title => 'initial', :user => all_stubs(:admin_model_stubbing_user), :published_at => current_time + 5.days
- stub :nice_one, :title => 'nice one', :tags => [all_stubs(:foo_model_stubbing_tag), all_stubs(:bar_model_stubbing_tag)]
+ stub :title => 'initial', :user => model_stubbing_users(:admin), :published_at => current_time + 5.days, :editor_id => model_stubbing_users(:admin).id
+ stub :nice_one, :title => 'nice one', :tags => [model_stubbing_tags(:foo), model_stubbing_tags(:bar)]
end
end
View
@@ -12,4 +12,11 @@
require 'spec'
end
+begin
+ require 'ruby-debug'
+ Debugger.start
+rescue LoadError
+ # no debugger
+end
+
require File.join(File.dirname(__FILE__), 'models')
View
@@ -0,0 +1,68 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+
+module ModelStubbing
+ describe StubProxy do
+ before :all do
+ @definition = ModelStubbing.definitions[:default]
+ @model = @definition.models[:model_stubbing_tags]
+ @stub = @model.stubs[:foo]
+ end
+
+ describe "with model name and stub name" do
+ before :all do
+ @stub_proxy = StubProxy.new(@definition, @model.name, @stub.name)
+ end
+
+ it "has no #method_name" do
+ @stub_proxy.method_name.should be_nil
+ end
+
+ it "returns @stub.record for #record" do
+ @stub_proxy.record.should == @stub.record
+ end
+
+ it "equals the stub" do
+ @stub_proxy.should == @stub
+ end
+ end
+
+ describe "with model name, stub name, and method name" do
+ before :all do
+ @stub_proxy = StubProxy.new(@definition, @model.name, @stub.name)
+ @stub_proxy.name
+ end
+
+ it "has #method_name" do
+ @stub_proxy.method_name.should == :name
+ end
+
+ it "returns @stub.record.name for #record" do
+ @stub_proxy.record.should == @stub.record.name
+ end
+
+ it "does not equal the stub" do
+ @stub_proxy.should_not == @stub
+ end
+ end
+
+ describe "missing valid stub name" do
+ before :all do
+ @stub_proxy = StubProxy.new(@definition, @model.name, :abc)
+ end
+
+ it "raises exception with #record" do
+ lambda { @stub_proxy.record }.should raise_error
+ end
+ end
+
+ describe "missing valid model name" do
+ before :all do
+ @stub_proxy = StubProxy.new(@definition, :abc, @stub.name)
+ end
+
+ it "raises exception with #record" do
+ lambda { @stub_proxy.record }.should raise_error
+ end
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 2d72b3d

Please sign in to comment.