P
Perry Smith
# 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_methodwrap_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?"]
# 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_methodwrap_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?"]