-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
anonymous class
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,31 +7,16 @@ | |
module FactoryGirl | ||
class Proxy #:nodoc: | ||
def initialize(klass, callbacks = []) | ||
@callbacks = callbacks.inject({}) do |result, callback| | ||
result[callback.name] ||= [] | ||
result[callback.name] << callback | ||
result | ||
end | ||
|
||
@instance = NullInstanceWrapper.new | ||
end | ||
|
||
def get(attribute) | ||
@instance.get(attribute) | ||
end | ||
|
||
def set(attribute, value) | ||
@instance.set(attribute.name, value) | ||
@callbacks = process_callbacks(callbacks) | ||
@proxy = ObjectWrapper.new(klass) | ||
end | ||
|
||
def set_ignored(attribute, value) | ||
@instance.set_ignored(attribute.name, value) | ||
end | ||
delegate :get, :set, :set_ignored, :to => :@proxy | ||
|
||
def run_callbacks(name) | ||
if @callbacks[name] | ||
@callbacks[name].each do |callback| | ||
callback.run(@instance.object, self) | ||
callback.run(result_instance, self) | ||
end | ||
end | ||
end | ||
|
@@ -71,10 +56,6 @@ def run_callbacks(name) | |
def association(name, overrides = {}) | ||
end | ||
|
||
def method_missing(method, *args, &block) | ||
get(method) | ||
end | ||
|
||
def result(to_create) | ||
raise NotImplementedError, "Strategies must return a result" | ||
end | ||
|
@@ -85,39 +66,80 @@ def self.ensure_strategy_exists!(strategy) | |
end | ||
end | ||
|
||
class InstanceWrapper | ||
attr_reader :object | ||
def initialize(object = nil) | ||
@object = object | ||
@ignored_attributes = {} | ||
private | ||
|
||
def method_missing(method, *args, &block) | ||
get(method) | ||
end | ||
|
||
def process_callbacks(callbacks) | ||
callbacks.inject({}) do |result, callback| | ||
result[callback.name] ||= [] | ||
result[callback.name] << callback | ||
result | ||
end | ||
end | ||
|
||
def result_instance | ||
@proxy.object | ||
end | ||
|
||
def result_hash | ||
@proxy.to_hash | ||
end | ||
|
||
class ObjectWrapper | ||
def initialize(klass) | ||
@klass = klass | ||
@attributes = [] | ||
@cached_attribute_values = {} | ||
end | ||
|
||
def to_hash | ||
@attributes.inject({}) do |result, attribute| | ||
result[attribute] = get(attribute) | ||
result | ||
end | ||
end | ||
|
||
def object | ||
@object ||= @klass.new | ||
assign_object_attributes | ||
@object | ||
end | ||
|
||
def set(attribute, value) | ||
define_attribute(attribute, value) | ||
@attributes << attribute.name | ||
end | ||
|
||
def set_ignored(attribute, value) | ||
@ignored_attributes[attribute] = value | ||
define_attribute(attribute, value) | ||
end | ||
|
||
def get(attribute) | ||
if @ignored_attributes.has_key?(attribute) | ||
@ignored_attributes[attribute] | ||
else | ||
get_attr(attribute) | ||
end | ||
@cached_attribute_values[attribute] ||= anonymous_instance.send(attribute) | ||
This comment has been minimized.
Sorry, something went wrong. |
||
end | ||
end | ||
|
||
class NullInstanceWrapper < InstanceWrapper | ||
def get_attr(attribute); end | ||
def set(attribute, value); end | ||
end | ||
private | ||
|
||
class ClassInstanceWrapper < InstanceWrapper | ||
This comment has been minimized.
Sorry, something went wrong.
metaskills
Contributor
|
||
def get_attr(attribute); @object.send(attribute); end | ||
def set(attribute, value); @object.send(:"#{attribute}=", value); end | ||
end | ||
def define_attribute(attribute, value) | ||
anonymous_class.send(:define_method, attribute.name, value) | ||
end | ||
|
||
class HashInstanceWrapper < InstanceWrapper | ||
def get_attr(attribute); @object[attribute]; end | ||
def set(attribute, value); @object[attribute] = value; end | ||
def assign_object_attributes | ||
(@attributes - @cached_attribute_values.keys).each do |attribute| | ||
@object.send("#{attribute}=", get(attribute)) | ||
end | ||
end | ||
|
||
def anonymous_class | ||
@anonymous_class ||= Class.new | ||
end | ||
|
||
def anonymous_instance | ||
@anonymous_instance ||= anonymous_class.new | ||
end | ||
end | ||
end | ||
end |
4 comments
on commit fba6f33
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not tracked down the tests that would have failed if they were not deleted or change in this commit, but I have a gut feeling theses tests are so white-box and contrived that a critical error was introduced in 2.3.2. No longer do your lazy attribute blocks allow you to talk to your model. Instead you now get:
NoMethodError: undefined method `killer_instance_method' for #<#<Class:0x10c1afa60>:0x10c1aeea8>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@metaskills can you provide a test that passed before 2.3.2 that currently fails on master regarding this?
Remember, you only have access to the resulting model instance in the after_*
callbacks. It's always been this way. You've never ever been able to access attributes that existed on the model instance from within FG attributes themselves, so it doesn't actually matter that these methods are on an anonymous class.
Again, an example (instead of a gut feeling) would be great help here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@metaskills looks like I was wrong - I'll take a look to see how this actually worked before and see what I can do. A pull request would be appreciated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Josh! I started a proper issue thread here #264
What good is sending methods that you expect your model to respond to (deep in
@proxy.@object
) to the anonymous instance? It has no logic for the attribute. So previous version relying on talking to their models in lazy blocks end up talking to a stupid anonymous class instance with no delegation.