隐藏绑定中的顶级常量

Shadowing a top-level constant within a binding

我想在模板方法中隐藏 ENV,这样如果请求的键不存在于真实的 ENV 中,我可以引发错误。显然我不想在其他地方隐藏常量 - 只是在特定方法(特定绑定)中。这可能吗?

解释器: - 我知道 Hash#fetch 的存在,而且我无时无刻不在使用它。但是,我想在生成配置文件的 ERB 模板中使用它。这个配置文件可能会被比平时更多的人接触,并不是每个人都熟悉 Ruby 为丢失的哈希键返回 nil 的行为。我还在一个系统上工作,最近,配置错误(或直接的错误配置,或对格式的误解)导致了明显的生产失败。失败是操作员错误。因此,我想建立一个约定,仅在该模板内,这将导致加薪。此外,我有一个 gem、strict_env,它已经做到了 - 但你必须记住使用 STRICT_ENV 而不是 ENV,并且每个 "you have to" 针对此特定工作流的声明,在这种特定情况下,对我来说是一个危险信号,因为我想要更稳健。我当然可以选择更严格的模板语言并使用该语言的逻辑来提升(例如,Mustache),但由于团队已经对 ERB 有一定的了解,并且 Rails 认可 ERB-templated-YML 作为可行的配置方法(即使你可能不同意)如果我也能坚持那个工作流程就好了。这就是为什么我想在本地更改 ENV[] 的行为。

当钥匙不存在时,您可以使用ENV.fetch(key)来提高。

除此之外,您可以创建一个 class 并委托给 ENV,例如:

class Configuration
  def self.[](key)
    ENV.fetch(key)
  end
end

但是从 #fetch 而不是 #[] 引发错误更像 Ruby 因为这与哈希的行为相同。

最后你可以打补丁 ENV,但这通常不是一件好事:

def ENV.[](key)
  fetch(key)
end

据我所知,您不能使用 refinements 来本地化这个猴子补丁,因为 ENV 是一个对象,而不是 class 并且它的 class 是对象。

ERB#result 采用可选绑定:

require 'erb'

class Foo
  ENV = { 'RUBY_VERSION' => '1.2.3' }
  def get_binding
    binding
  end
end

template = "Ruby version: <%= ENV['RUBY_VERSION'] %>"

ERB.new(template).result
#=> "Ruby version: 2.1.3"

b = Foo.new.get_binding

ERB.new(template).result b
#=> "Ruby version: 1.2.3"