Last active
February 23, 2016 16:58
-
-
Save chrisarcand/b425bcbd0b7bfd27addd to your computer and use it in GitHub Desktop.
Dynamic module lookup in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
The last one is the worst me
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
That middle one....WAT