在Ruby中初始化常量的正确方法是什么?

Cod*_*all 10 ruby dependencies warnings

我有一个简单的类定义了一些常量,例如:

module Foo
  class Bar
    BAZ = "bof"
    ...
Run Code Online (Sandbox Code Playgroud)

一切都是小狗和彩虹,直到我告诉Rake进行我的所有Test::Unit测试.当它发生时,我收到警告:

bar.rb:3: warning: already initialized constant BAZ
Run Code Online (Sandbox Code Playgroud)

我的习惯是通过使常量初始化有条件来避免这些警告,例如:

...
BAZ = "bof" unless const_defined? :BAZ
...
Run Code Online (Sandbox Code Playgroud)

这似乎解决了这个问题,但它有点单调乏味,而且我从未见过其他人以这种方式初始化常量.这让我觉得我可能做错了.有没有更好的方法来初始化不会产生警告的常量?

更新:通过更详细地说明我如何使用这些常量,假设我已经定义了一个Token类,它对于所有字符都是常量,这些字符是某种人工语言语法的一部分.我还有一个Scanner类,它读取一个字符流,Token为每个字符生成一个实例.

module Foo
  class Token
    LPAREN = "("
    RPAREN = ")"
    ...
  end

  class Scanner
    def next_token
      case read_char()
        when Token::LPAREN: # Generate a new LPAREN token
        ...
Run Code Online (Sandbox Code Playgroud)

也就是说,在检查应该为给定字符生成什么类型​​的令牌时,我想使用中定义的常量Token.

更新2:Jörg的回答显示问题可能在于我在require语句中构建路径的方式,而不是我如何初始化或使用常量.我重写了我的require语句以消除任何手动路径创建,例如:

# File: $PROJECT_ROOT/lib/foo.rb; trying to load $PROJECT_ROOT/lib/foo/bar.rb
require File.expand_path(File.dirname(__FILE__)) + "foo/bar"
Run Code Online (Sandbox Code Playgroud)

现在写成依靠$LOAD_PATH:

# File: $PROJECT_ROOT/lib/foo.rb; trying to load $PROJECT_ROOT/lib/foo/bar.rb
require 'lib/foo/bar'
Run Code Online (Sandbox Code Playgroud)

我从我的常量初始化语句中删除了条件检查,rake现在运行单元测试而不会抛出任何警告.

Jör*_*tag 11

这种情况发生的唯一方法bar.rbrequire多次d次.这不应该发生,因为require不加载已经加载过一次的文件.

但是,它确实只使用传递给它的路径来确定文件是否已经加载,至少在Ruby 1.8中是这样:

require 'bar'   # => true, file was loaded

require 'bar'   # => false, file had already been loaded

require './bar' # => true, OOPS, I DID IT AGAIN
# bar.rb:3: warning: already initialized constant BAZ
Run Code Online (Sandbox Code Playgroud)

所以,你是对的:这很可能表明你的依赖管理有问题.

典型的警告标志是

总的来说,我的理念是,作为一名图书馆作家,我不应该弄清楚如何把我的图书馆放在上面$LOAD_PATH.这是系统管理员的工作.如果sysadmin使用RubyGems来安装我的库,那么RubyGems会处理它,否则他使用的任何其他包管理系统都应该处理它,如果他使用setup.rb,那么它将被安装在site_ruby,$LOAD_PATH无论如何它已经在.

  • +1回答问题并引用布兰妮斯皮尔斯! (2认同)

mar*_*cog 6

这篇文章的评论中有一个很好的讨论.我认为下面这个说得很好:

当我第一次走向Ruby时,这让我有点恼火.这是我的静态类型洗脑的残余.有三件事可以缓解这是一个真正的问题.1.警告.你可以说它应该是一个例外,但实际上,在其他程序员默默地捕获异常的情况下,会有什么不同?这让我想到了2)不要和蠢货一起工作.只有白痴默默地捕捉异常并继续,只有白痴才会改变以这种方式使用的常数值.这让我想到3)我们俩都不是白痴,所以你会很高兴地知道,这从未发生在我身上.这真的是因为常量在Ruby中非常突出,它们的大概是什么,以及你在代码中有多久可能有一个常数作为L值?

要直接回答你的问题,我不会做任何事情来摆脱警告.只需要警告,警告,继续前进.

  • "警告相当于尚未发生的错误",这是一种很好的态度,即使在Ruby中也是如此.我更喜欢我的代码在没有任何警告的情况下正确运行,甚至是测试代码. (5认同)
  • 如果我多年没有把它钻进我脑中那么警告会导致尚未发生的错误,那会更容易.那好吧... (3认同)