Skip to content

Instantly share code, notes, and snippets.

@xaviershay
Created July 5, 2013 21:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xaviershay/5937392 to your computer and use it in GitHub Desktop.
Save xaviershay/5937392 to your computer and use it in GitHub Desktop.
Unexpected behaviour defining Ruby classes anonymously.
true
repro.rb:16:in `block in <main>': uninitialized constant B (NameError)
from repro.rb:13:in `initialize'
from repro.rb:13:in `new'
from repro.rb:13:in `<main>'
module A
B = Object.new
end
class Works
include A
Thing = B
end
p Works::Thing == A::B
fails = Class.new do
include A
Thing = B
end
p fails::Thing == A::B
@elskwid
Copy link

elskwid commented Jul 6, 2013

@xaviershay, Ruby is looking that constant (on line 16) up in the context of a block passed to class_eval so it's looking in Object in this case. It's janky but you could do this:

module A
  B = Object.new
end

class Works
  include A

  Thing = B
end

p Works::Thing == A::B

Fails = Class.new

class Fails
  include  A

  Thing = B
end

p Fails.ancestors.inspect
p Fails::Thing == A::B
# => true
# => "[Fails, A, Object, Kernel, BasicObject]"
# => true

@elskwid
Copy link

elskwid commented Jul 6, 2013

Which amounts to the same thing as the first set up with an extra step. I love it when I post it and then look at it. ha ha. 😁

@elskwid
Copy link

elskwid commented Jul 6, 2013

This was the janky thing I meant to post.

module A
  B = Object.new

  def self.included(base)
    base.const_set("Thing", A::B)
  end
end

class Works
  include A

  Thing = B
end

p Works::Thing == A::B

fails = Class.new do
  include A
end

p fails.ancestors.inspect
p fails::Thing == A::B
# => true
# => "[#<Class:0x007fe982855688>, A, Object, Kernel, BasicObject]"
# => true

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