考虑以下sinatra
应用程序:
require 'sinatra'
def f
settings.development? ? 'development' : 'whatever'
end
class C
def self.f
settings.development? ? 'development' : 'whatever'
end
end
get '/' do
# f # works
C.f # doesn't work, gives "NameError - undefined local variable or method `settings' for C:Class"
end
这里发生了什么以及如何使其发挥作用?
答案 0 :(得分:3)
尝试:
class C
def self.f
Sinatra::Application.settings.development? ? 'development' : 'whatever'
end
end
当require 'sinatra'
发生# include would include the module in Object
# extend only extends the `main` object
extend Sinatra::Delegator
时,会发生什么:
Sinatra::Delegator
main
类负责在get
对象中提供following,以及{{1}} DSL和创建所需的所有好东西settings
Sinatra申请。
答案 1 :(得分:1)
发生的情况是,在定义新类时,您将无法访问外部作用域,因为它为您提供了自己的作用域。
正如上面提到的Uri,要求Sinatra运行extend Sinatra::Delegator
,这会增加所有众所周知的方法。
考虑这种过度简化:
module A
def ping
"pong"
end
end
ping # => throws NoMethodError
extend A
ping # => "pong"
class B
def my_ping
ping
end
end
B.new.my_ping # => throws NoMethodError
为什么呢?由于Ruby的范围规则。
您可以通过将引用传递给外部作用域来解决此问题。
module A
def ping
"pong"
end
end
extend A
ping # => "pong"
class B
class << self
attr_accessor :app
def my_ping
app.ping
end
end
end
B.app = self
B.my_ping # => "pong"