Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Dynamic module lookup in Ruby
# What do you suppose the output of the examples are?
# Note: If you want to tinker executing these, don't just copy paste the entire file
# as defining everything in the same file acts differently (expected effects of reopening constants)
############## EXAMPLE 1 ##############
module NameHelper
def full_name
"#{first_name} #{last_name}"
end
end
class Person
include NameHelper
def first_name
"Abe"
end
def last_name
"Lincoln"
end
end
module NameHelper
def full_name
"George Washington"
end
end
puts Person.new.full_name
############## EXAMPLE 2 ##############
module NameHelper
def full_name
"#{first_name} #{last_name}"
end
end
class Person
include NameHelper
def first_name
"Abe"
end
def last_name
"Lincoln"
end
end
module NameHelper
prepend(Module.new {
def full_name
"George Washington"
end
})
end
puts Person.new.full_name
############## EXAMPLE 3 ##############
module NameHelper
def full_name
"#{first_name} #{last_name}"
end
end
class Person
include NameHelper
def first_name
"Abe"
end
def last_name
"Lincoln"
end
end
module NameHelper
include(Module.new {
def full_name
"George Washington"
end
})
end
puts Person.new.full_name
# Don't open this until you've guessed the outputs!
# https://bugs.ruby-lang.org/issues/9112
@Fryguy
Copy link

Fryguy commented Feb 23, 2016

That middle one....WAT

@bdunne
Copy link

bdunne commented Feb 23, 2016

The last one is the worst me

@krbullock
Copy link

krbullock commented Feb 23, 2016

This gist doesn't demonstrate the same thing as the bug you referenced. This behaves as one would expect if you remember that including a module just inserts it into the module's/class' inheritance chain. So in example 1, you just reopen NameHelper and redefine full_name, but in 2 and 3 you include a module in NameHelper that implements full_name. Since you end up with Person < NameHelper < #<Module:0xdeadbeef>, and NameHelper overrides full_name, method lookup stops with the "#{first_name} #{last_name}" implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment