From efc07f4c5a707d299b14c95ad2ce79d09be15a57 Mon Sep 17 00:00:00 2001 From: Ginty Date: Wed, 26 May 2010 22:20:33 -0500 Subject: [PATCH] Added ability to assign attributes via a block --- README.rdoc | 13 +++++++++++-- lib/cranky.rb | 8 ++++++-- spec/cranky_spec.rb | 7 +++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/README.rdoc b/README.rdoc index 4a8049e..491a578 100644 --- a/README.rdoc +++ b/README.rdoc @@ -129,7 +129,7 @@ So a nice tip is to implement default associations like this (assuming you're us # Return the default address if it already exists, or call the address factory to make one def default_address # If the default address exists, but has been cleared from the database... - @default_address = nil if @default_address && !Account.exists?(@default_address.id) + @default_address = nil if @default_address && !Address.exists?(@default_address.id) @default_address ||= create(:address) end @@ -164,7 +164,16 @@ Most of your factories are likely to simply define a list of mimimum attribute v Note that you don't have to worry about handling the overrides here, they will be applied automatically if present, just define the defaults. -The best thing about this is that there are no pesky blocks to worry about. The define argument is just a regular hash, you have complete freedom to choose how to generate the values to be passed into it. +The define argument is just a regular hash, you have complete freedom to choose how to generate the values to be passed into it. + +If you like you can generate attributes with a block: + + def user + define :name => "Jimmy", + :email => lambda{|u| "#{u.name.downcase}@home.com"}, + :role => "pleb", + :address => default_address + end The define method will return the object, you can grab this for additional manipulation as you would expect... diff --git a/lib/cranky.rb b/lib/cranky.rb index ddbda40..629c0e2 100644 --- a/lib/cranky.rb +++ b/lib/cranky.rb @@ -62,11 +62,15 @@ def crank_it(what, save, attrs) def define(attrs={}) final_attrs = attrs.merge(@attrs.last) - #item = (attrs[:class] ? attrs[:class] : @what.last).to_s.camelcase.constantize.new item = get_constant(attrs[:class] ? attrs[:class] : @what.last).new final_attrs.delete(:class) + # Assign all explicit attributes first final_attrs.each do |attr, value| - item.send("#{attr}=", value) if item.respond_to?("#{attr}=") + item.send("#{attr}=", value) if item.respond_to?("#{attr}=") && !value.respond_to?("call") + end + # Then call any blocks + final_attrs.each do |attr, value| + item.send("#{attr}=", value.call(item)) if item.respond_to?("#{attr}=") && value.respond_to?("call") end item end diff --git a/spec/cranky_spec.rb b/spec/cranky_spec.rb index e17ec3c..7246d96 100644 --- a/spec/cranky_spec.rb +++ b/spec/cranky_spec.rb @@ -79,6 +79,13 @@ Factory.build(:user).argument_received.should == nil Factory.build(:user, :argument_supplied => true).argument_received.should == true end + + it "should allow blocks to be passed into the define method" do + Factory.build(:user, :name => "jenny", :email => lambda{ |u| "#{u.name}@home.com" }).email.should == "jenny@home.com" + Factory.build(:user, :name => lambda{"jimmy" + " cranky"}).name.should == "jimmy cranky" + Factory.build(:user, :name => "jenny", :email => Proc.new{ |u| "#{u.name}@home.com" }).email.should == "jenny@home.com" + Factory.build(:user, :name => Proc.new{"jimmy" + " cranky"}).name.should == "jimmy cranky" + end end