Asp Forum
Home
|
Login
|
Register
|
Search
Forums
>
comp.lang.ruby
weird binding error
Perry Smith
1/31/2008 5:33:00 PM
# 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-...
.
2 Answers
ara.t.howard
1/31/2008 6:12:00 PM
0
On Jan 31, 2008, at 10:33 AM, Perry Smith wrote:
> # Problem occurs here wrap calls Object#wrap instead
> # of Cached::Base#wrap or Cached::Queue#wrap
> temp.wrap_with_combined
there really isn't enough code there to say, but i'm guessing you have
a 'has_many' association and are calling 'wrap_with_combined' on a
*Array*, thus defining it on Object intercepts this call.
perhaps an explanation of what you are trying to do?
regards.
a @
http://codeforp...
--
it is not enough to be compassionate. you must act.
h.h. the 14th dalai lama
Perry Smith
2/1/2008 4:42:00 AM
0
ara howard wrote:
> On Jan 31, 2008, at 10:33 AM, Perry Smith wrote:
>
>> # Problem occurs here wrap calls Object#wrap instead
>> # of Cached::Base#wrap or Cached::Queue#wrap
>> temp.wrap_with_combined
>
> there really isn't enough code there to say, but i'm guessing you have
> a 'has_many' association and are calling 'wrap_with_combined' on a
> *Array*, thus defining it on Object intercepts this call.
>
> perhaps an explanation of what you are trying to do?
>
> regards.
>
> a @
http://codeforp...
Thanks Howard.
I found a way to dump out ancestors and I found a thread talking about
association proxies. In that thread, it tells to do (from memory) (
class << temp; self; end).ancestors
Doing this produces a list of associations and proxies, etc (as you
predicted). And Cached::Queue is not in the list.
I added wrap and unwrap methods to a couple of the association classes
and that solved my problem. I am not yet to what I think is a general
solution but I'm at least understanding what is happening at little
more.
What am I doing? I have a legacy system that is remote called Retain.
For each concept, like a PMR, I have three classes. Retain::PMR,
Cached::PMR, and Combined::PMR. Retain::PMR goes to retain and gets the
data. Cached::PMR is a subclass of ActiveRecord::Base and uses all the
normal ActiveRecord features. Combined::PMR is the magic that glues
them together. For any request, I look to see if I have it in
Cached::PMR. I use time stamps to expire it, etc. If it is there and
current, I just present that. If not, I go to Retain::PMR to get the
data from Retain and save it in Cached::PMR. All the usual rails code
(the controllers and views) work with Combined objects (or thats the
idea).
Most of the magic is done with method_method and respond_to? so when
pmr.owner comes, it goes to a Combined instance's method_missing which
(if the cache is deemed valid) is forwarded on to the Cached
(ActiveRecord) instance. When the request completes, it is "wrapped" so
the result is a Combined instance -- not a Cached instance.
Most things, the "wrapped" version is self. For instances of bases
which are a subclass of Cached::Base, the wrapped version is the
equivalent Combined version. For somethings like Arrays and Hash, the
wrap version is an Arrary or Hash with each value wrapped.
Right now, my biggest question is how does the association do this
magic? I haven't found it yet. Driving home I thought I need to look
for places that do things like class << self and other things like that
which modify the metaclass of an object. I've been looking at
initialize and those things but that hasn't told me anything. But I'm
wondering how an object that isn't an Array (to pick an example) says
"Array#...." when inspected or when name is called, etc.
Thank you for your help
--
Posted via
http://www.ruby-...
.
Servizio di avviso nuovi messaggi
Ricevi direttamente nella tua mail i nuovi messaggi per
weird binding error
Inserendo la tua e-mail nella casella sotto, riceverai un avviso tramite posta elettronica ogni volta che il motore di ricerca troverà un nuovo messaggio per te
Il servizio è completamente GRATUITO!
x
Login to ForumsZone
Login with Google
Login with E-Mail & Password