Skip to content
This repository
Browse code

Overrides become methods defined on each instance of the evaluator

There were some big issues with trying to undefine specific methods on
the Evaluator. After investigating maybe inheriting from BasicObject (or
ActiveSupport::BasicObject since BasicObject is 1.9+), that turned out
to be too much of a pain because it undefines almost everything,
including class and a handful of other methods necessary for Evaluator
to work properly.

The second solution was to undefine all private methods. The problem is,
when other libraries defining methods (private or otherwise) on Object
are loaded *after* factory girl, those methods get added and Evaluator
sees those methods on Object. So, that solution didn't directly work either.

This commit removes undefining methods (the sole reason of which was to
capture with method_missing and process ourselves, returning the
override or cached value) and instead introduces a new concept -
iterating over each override and defining it as a method on the
evaluator INSTANCE. This means that overrides don't collide because
they're on the instance and we don't have to worry about undefining
methods so that method_missing kicks in. This is the most stable and
guaranteed way to get this to work because the overrides are applied to
each instance at runtime.

Closes #279, #285
  • Loading branch information...
commit f50550c1f01f608a88a6a5547b3ec8ee7f0e38e6 1 parent 850116d
Joshua Clayton authored January 28, 2012
10  lib/factory_girl/evaluator.rb
@@ -11,13 +11,21 @@ def self.attribute_list
11 11
         end
12 12
       end
13 13
     end
14  
-    undef_method(:id) if method_defined?(:id)
  14
+
  15
+    private_instance_methods.each do |method|
  16
+      undef_method(method) unless method =~ /^__|initialize/
  17
+    end
15 18
 
16 19
     def initialize(build_strategy, overrides = {})
17 20
       @build_strategy    = build_strategy
18 21
       @overrides         = overrides
19 22
       @cached_attributes = overrides
20 23
 
  24
+      singleton = class << self; self end
  25
+      @overrides.each do |name, value|
  26
+        singleton.send :define_method, name, lambda { value }
  27
+      end
  28
+
21 29
       @build_strategy.add_observer(CallbackRunner.new(self.class.callbacks, self))
22 30
     end
23 31
 
47  spec/acceptance/attribute_existing_on_object_spec.rb
@@ -19,3 +19,50 @@
19 19
   its(:link)   { should == "http://example.com" }
20 20
   its(:sleep)  { should == -5 }
21 21
 end
  22
+
  23
+describe "assigning overrides that are also private methods on object" do
  24
+  before do
  25
+    define_model("Website",  :format => :string, :y => :integer, :more_format => :string, :some_funky_method => :string)
  26
+
  27
+    Object.class_eval do
  28
+      private
  29
+      def some_funky_method(args)
  30
+      end
  31
+    end
  32
+
  33
+    FactoryGirl.define do
  34
+      factory :website do
  35
+        more_format { "format: #{format}" }
  36
+      end
  37
+    end
  38
+  end
  39
+
  40
+  after do
  41
+    Object.send(:undef_method, :some_funky_method)
  42
+  end
  43
+
  44
+  subject { FactoryGirl.build(:website, :format => "Great", :y => 12345, :some_funky_method => "foobar!") }
  45
+  its(:format)            { should == "Great" }
  46
+  its(:y)                 { should == 12345 }
  47
+  its(:more_format)       { should == "format: Great" }
  48
+  its(:some_funky_method) { should == "foobar!" }
  49
+end
  50
+
  51
+describe "accessing methods from the instance within a dynamic attribute that is also a private method on object" do
  52
+  before do
  53
+    define_model("Website", :more_format => :string) do
  54
+      def format
  55
+        "This is an awesome format"
  56
+      end
  57
+    end
  58
+
  59
+    FactoryGirl.define do
  60
+      factory :website do
  61
+        more_format { "format: #{format}" }
  62
+      end
  63
+    end
  64
+  end
  65
+
  66
+  subject           { FactoryGirl.build(:website) }
  67
+  its(:more_format) { should == "format: This is an awesome format" }
  68
+end

0 notes on commit f50550c

Please sign in to comment.
Something went wrong with that request. Please try again.