使类可以访问全局方法

时间:2014-05-26 18:22:11

标签: ruby sinatra

考虑以下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

这里发生了什么以及如何使其发挥作用?

2 个答案:

答案 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"