From: Perry Smith Date: 2008-02-01T02:33:12+09:00 Subject: weird binding error # Below is code that represents the code I am working on. The line # that reads temp.wrap_with_combined is the problem. I am not sure if # this is a bug in my brain, Rails, or Ruby. And, I'm stumped as to # how to continue to debug it. # # At the point temp.wrap_with_combined is called, temp is a # Cached::Queue according to the dump_me output. The dump_me code and # its output are included here. According to the debugging output, # temp is a Cached::Queue but instead of calling wrap_with_combined in # Cached::Queue or Cached::Base, it calls wrap_with_combined in # Object. I can see this from the debug output. # # I've tried moving the def of wrap_with_combined in Cached::Base so # it gets defined when the subclass is defined. I've tried many # things but it always ends up calling Object#wrap. # # Another clue is, I replace the temp.wrap call with this: # dump_me(temp) # m = temp.class.instance_method(:wrap_with_combined) # m.bind(temp).call # # But I get this error: # ActionView::TemplateError (bind argument must be an instance of Cached::Queue) on line #6 of retain/favorite_queues/new.html.erb: # # So, while the debug says I have a Cached::Queue, the internals of # Ruby say that I do not. # # I've tried to make a simple testcase to show this but I have not # been able to. If ActiveRecord::Base is replaced with a simple base, # the problem goes away. Or if the Cached::Queue is created directly, # the problem goes away. # # Any ideas? # class Object def wrap_with_combined logger.debug "Object wrap returns self" self end end class Cached::Base < ActiveRecord::Base def wrap_with_combined logger.debug "Cached::Base wrap returns wrapped object" wrap_object(self) end def self.inherited(subclass) super(subclass) subclass.class_eval { def wrap_with_combined logger.debug "Alternate place to put wrap." logger.debug "Cached::Base wrap returns wrapped object" wrap_object(self) end } end end class Cached::Queue < Cached::Base # ... end class WrappedBase def self.inherited(subclass) super(subclass) subclass.class_eval { # Define getter methods for each association db_associations.each do |name| eval("def #{name} temp = @cached.#{name} unless temp && cache_valid call_load temp = @cached.#{name} end dump_me(temp) # Problem occurs here wrap calls Object#wrap instead # of Cached::Base#wrap or Cached::Queue#wrap temp.wrap_with_combined end", nil, __FILE__, __LINE__) end def dump_me(obj) klass = obj.class return if klass.nil? logger.debug("DMP: 1 class=#{klass} name=#{klass.name} methods=#{klass.instance_methods(false).inspect}") klass = klass.superclass return if klass.nil? logger.debug("DMP: 2 class=#{klass} name=#{klass.name} methods=#{klass.instance_methods(false).inspect}") klass = klass.superclass return if klass.nil? logger.debug("DMP: 3 class=#{klass} name=#{klass.name} methods=#{klass.instance_methods(false).inspect}") klass = klass.superclass return if klass.nil? logger.debug("DMP: 4 class=#{klass} name=#{klass.name} methods=#{klass.instance_methods(false).inspect}") klass = klass.superclass return if klass.nil? logger.debug("DMP: 5 class=#{klass} name=#{klass.name} methods=#{klass.instance_methods(false).inspect}") end } end end class WrappedQueue < WrappedBase # ... end # DMP: 1 class=Cached::Queue name=Cached::Queue methods=["wrap_with_combined", "favorite_queues", "favorite_queue_ids", "favorite_queues=", "calls", "call_ids", "favorite_queue_ids=", "validate_associated_records_for_favorite_queues", "calls=", "call_ids=", "validate_associated_records_for_calls"] # DMP: 2 class=Cached::Base name=Cached::Base methods=["to_combined"] # DMP: 3 class=ActiveRecord::Base name=ActiveRecord::Base methods=["to_param", "increment", "readonly!", "allow_concurrency", "destroy", "default_timezone", "record_timestamps", "quoted_id", "reload", "save_without_transactions", "save!", "update_attributes", "valid?", "update_attributes!", "verification_timeout", "attributes_before_type_cast", "colorize_logging", "new_record?", "logger", "id_before_type_cast", "save_without_transactions!", "eql?", "toggle!", "pluralize_table_names", "valid_without_callbacks?", "id", "[]", "attribute_present?", "inspect", "column_for_attribute", "[]=", "save_without_validation", "decrement!", "update_attribute", "frozen?", "id=", "hash", "update_attribute_without_validation_skipping", "table_name_suffix", "connection", "configurations", "save_without_validation!", "toggle", "becomes", "attribute_names", "readonly?", "clone", "increment!", "attribute_for_inspect", "attribute_types_cached_by_default", "table_name_prefix", "attributes", "freeze", "save", "schema_format", "decrement", "destroy_without_callbacks", "==", "has_attribute?", "attributes=", "primary_key_prefix_type", "lock_optimistically", "destroy_without_transactions"] # DMP: 4 class=Object name=Object methods=["subclasses_of", "require_or_load", "require", "to_yaml_style", "wrap_with_combined", "with_options", "require_association", "copy_instance_variables_from", "to_yaml_properties", "duplicable?", "instance_exec", "load", "unloadable", "taguri", "to_json", "blank?", "require_dependency", "to_query", "instance_values", "dclone", "remove_subclasses_of", "extend_with_included_modules_from", "taguri=", "to_yaml", "`", "to_param", "returning", "extended_by", "unwrap_to_cached", "send!", "acts_like?"] -- Posted via http://www.ruby-forum.com/.