Hi friends, I found a bug (?) with routes.url_helpers. Let''s say my routes file contains resources :fruits Now I have the following setup: module A end module B include A end A.module_eval do include Rails.application.routes.url_helpers end Object.new.extend(A).fruit_path #=> That works. Object.new.extend(B).fruit_path #=> NoMethodError: undefined method `fruit_path'' for #<Object:0x98e56d0> In a proper Ruby setup B should have references to any method in A. Obviously, this doesn''t work with url_helpers. I didn''t check its implementation so far, is there any magic done inside the url_helpers that breaks the expected behaviour? Nick -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-core/-/jcLxKZFW8zwJ. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
I''d like to state that this behaviour usually works in Ruby: module A end module B include A end A.module_eval do def a "Hey from A!" end end Object.new.extend(B).a #=> "Hey from A!" On Wednesday, June 27, 2012 6:43:00 PM UTC+2, Nick Sutterer wrote:> > Hi friends, > > I found a bug (?) with routes.url_helpers. Let''s say my routes file > contains > > resources :fruits > > Now I have the following setup: > > module A > end > > module B > include A > end > > A.module_eval do > include Rails.application.routes.url_helpers > end > > Object.new.extend(A).fruit_path #=> That works. > Object.new.extend(B).fruit_path #=> NoMethodError: undefined method > `fruit_path'' for #<Object:0x98e56d0> > > In a proper Ruby setup B should have references to any method in A. > Obviously, this doesn''t work with url_helpers. I didn''t check its > implementation so far, is there any magic done inside the url_helpers that > breaks the expected behaviour? > > Nick >-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-core/-/XbjtmqCrsOQJ. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
I just got educated by drogus that the problem is the module_eval with include: module UrlHelpers def fruit_path end end A.module_eval do include UrlHelpers end Object.new.extend(B).fruit_path #=> NoMethodError: undefined method `fruit_path'' for #<Object:0x964c540> So obviously, when including modules into source modules it is not propagated properly to the includer. On Thursday, June 28, 2012 9:41:13 AM UTC+2, Nick Sutterer wrote:> > I''d like to state that this behaviour usually works in Ruby: > > module A > end > > module B > include A > end > > A.module_eval do > def a > "Hey from A!" > end > end > > Object.new.extend(B).a #=> "Hey from A!" > > On Wednesday, June 27, 2012 6:43:00 PM UTC+2, Nick Sutterer wrote: >> >> Hi friends, >> >> I found a bug (?) with routes.url_helpers. Let''s say my routes file >> contains >> >> resources :fruits >> >> Now I have the following setup: >> >> module A >> end >> >> module B >> include A >> end >> >> A.module_eval do >> include Rails.application.routes.url_helpers >> end >> >> Object.new.extend(A).fruit_path #=> That works. >> Object.new.extend(B).fruit_path #=> NoMethodError: undefined method >> `fruit_path'' for #<Object:0x98e56d0> >> >> In a proper Ruby setup B should have references to any method in A. >> Obviously, this doesn''t work with url_helpers. I didn''t check its >> implementation so far, is there any magic done inside the url_helpers that >> breaks the expected behaviour? >> >> Nick >> >-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-core/-/v6y6jFdjktMJ. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On Fri, Jun 29, 2012 at 11:08 AM, Nick Sutterer <apotonick@gmail.com> wrote: I just got educated by drogus that the problem is the module_eval with> include: >This is a gotcha in Ruby. As you probably know, the interpreter keeps a linear representation of the ancestors of a base class or module. Algorithms that walk up the ancestors go over that linearization following pointers up, as in a linked list, rather than following pointers recursively which would be the immediate mental model for this. OK, if you add methods or constants to any class or module in that ancestry chain they are seen: module M end class C include M end module M def foo end end C.new.foo # WORKS If you include more modules into the base class or module, their methods are found: class C end module M def foo end end class C include M end C.new.foo # WORKS The linear ancestry that exists behind the scenes gets updated to reflect the new ancestor. But if once the linearization is done you modify the 2nd-degree ancestors, those are not propagated: module M end class C include M end module N def bar end end module M include N end C.new.bar # DOES NOT WORK As you see the linearization of the ancestry chain of C does not get updated with N, albeit if you computed the ancestry chain in that very moment N should belong to it. I asked for the rationale behind this, conceptually does not seem coherent. Matz said it could be changed if someone came with an implementation that was performant enough[*]. Xavier [*] http://www.ruby-forum.com/topic/1458576 -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.