Ruby 1.8 funkyness with Class.new and inherited
I just found a bug in Sinatra where this code will fail with the error “can’t dup NilClass”:
Class.new(Sinatra::Base) do
get('/') { 'abc' }
end
Sinatra uses the ‘inherited’ method to initialize a number of class variables in new subclasses of Sinatra::Base when they are defined. For normal subclassing, this works great because ‘inherited’ is called before the contents of the class are evaluated. When using Class.new, however, it is called after evaluating the class contents, which means that Sinatra will not have had a chance to set up the variables when ‘get’ is called in this example. Apparently Ruby 1.9 has fixed this issue, but we’re still stuck with it in 1.8.
Run this code and you’ll get:
Inherited!
Some method!
Some method!
Inherited!
class Base
def self.some_method
puts 'Some method!'
end
def self.inherited(subclass)
puts 'Inherited!'
end
end
class Sub < Base
some_method
end
Class.new(Base) do
some_method
end
It would be lovely if quick fix for doing this in Sinatra was to call ‘reset!’ as the first line of the class definition, but unfortunately because inherited is called after the class contents are evaluated all of your routes will be wiped out.
Class.new(Sinatra::Base) do
reset!
get('/') { 'abc' }
end