Limit private callback lookup. - #58
Conversation
dwbutler
commented
Dec 15, 2012
Thanks for catching that! This is a good idea, but this code won't work in Ruby 1.8.7 because private_methods returns an array of strings. #1.9.3"hello".private_methods(false)=>[:initialize,:initialize_copy]#1.8.7"hello".private_methods(false)=>["initialize_copy","initialize"]In a previous commit I ended up mapping the return value to an array of symbols. Would be good to see some tests included! =) |
Background: Commit 71937c0 introduced private callbacks, however, the use of "private_method_defined?" returns true all the way down the class hierarchy and thus causes trouble with a very common transition: Given an event "event :fail transitions_to :failed". If you don't explicitly define the "fail" event handler, "private_method_defined?" will still return true since Kernel#fail is defined for any object. Transitioning with "fail!" then causes a runtime error.
svoop
commented
Dec 15, 2012
As you suggested, I've added |
dwbutler
commented
Jan 10, 2013
@geekq, think we can get a bugfix 0.8.7 release soon? =) |
geekq
commented
Jan 10, 2013
Sorry - was busy with my current project.
Going to do this this weekend/monday ETA: 2013-01-14 |
geekq
commented
Jan 16, 2013
The change will brake class hierarchies with private callback methods. But it is less harm, than unintentionally calling some private methods, especially in kernel. So going to merge... Would like to test with ruby-1.9.3, ruby-1.8.7 and jruby. Unfortunately my current rbenv for 1.8.7 and 1.8.6 broken. Need to repair that first. |
dwbutler
commented
Jan 17, 2013
Wouldn't defining the methods as |
dwbutler
commented
Jan 17, 2013
After some testing I've determined the following about protected methods defined on a parent class: (this is consistent in 1.9.3 and 1.8.7):
Based on these results, I say we add |
dwbutler
commented
Jan 17, 2013
I made a gist to help me understand and document all the craziness behind private methods, protected methods, and inheritance: |
geekq
commented
Jan 19, 2013
Hi, I've prepared my continuous integration environment for testing with various ruby versions. Not yet on travis-ci.org, just on my notebook. Can now review/try out/merge. @sven Thanks for the test and for the improved 1.8.7 compatibility! @david Thanks for the 1.8.7 investigation and for the 'protected method' idea! I think, using protected methods as callbacks is the best way to go:
Best Regards, Vladimir (geekq) |
dwbutler
commented
Jan 20, 2013
Thanks! My idea was actually to support both private and protected methods, by using both |
geekq
commented
Jan 20, 2013
OK, adding support for private methods again ;-) - but only in the immediate class now. Big surprise: respond_to? returns true for inherited protected methods (for me). But it can change one more time in Ruby2. Meta programming is hard and it is even harder with a moving target like Ruby 1.9 ;-) So I'll keep all the 3 checks even if the second one currently seems to be unneeded on 1.8.7-p371 and 1.9.3-rc1 |
dwbutler
commented
Jan 20, 2013
Great! I like how to checks are documented now with some comments! =D Otherwise it would be quite confusing to understand why all those checks are necessary. |
Support for private callbacks introduced in commit 71937c0 is a good thing, however, the way private callbacks are looked up caused a nasty issue in one of my models dealing with credit cards:
Now try to transition with
fail!and - kaboom - runtime error. The problem is the lookup in the workflow gem:Eventhough no private event handler
failis defined in the model,private_method_defined?still returnstrueas it does for any object due toKernel#fail.The problem is quite nasty and since "fail" appears to be a rather common transition in workflows, using another event name is not the best solution. But there's an easy way to limit the method lookup:
Which is exactly what this pull request contains :-)