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

时间:2010-12-26 01:26:03

标签: ruby dependencies warnings

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

module Foo
  class Bar
    BAZ = "bof"
    ...

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

bar.rb:3: warning: already initialized constant BAZ

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

...
BAZ = "bof" unless const_defined? :BAZ
...

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

更新:通过更详细的说明我如何使用这些常量,假设我已经定义了一个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
        ...

也就是说,在检查应该为给定字符生成哪种令牌时,我想使用Token中定义的常量。

更新2 Jörg's answer显示问题可能出在我在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"

现在编写为依赖于$LOAD_PATH

# File: $PROJECT_ROOT/lib/foo.rb; trying to load $PROJECT_ROOT/lib/foo/bar.rb
require 'lib/foo/bar'

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

2 个答案:

答案 0 :(得分:11)

这种情况发生的唯一方法是bar.rb多次require次。这不应该发生,因为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

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

典型警告标志

  • 手动构建文件路径,而不仅仅依赖$LOAD_PATH

    require "File.expand_path('../lib/bar', File.dirname(__FILE__))"
    
  • 在任何地方操纵$LOAD_PATH,除了可能是您图书馆的主要入口点:

    path = File.expand_path(File.dirname(__FILE__))
    $LOAD_PATH << path unless $LOAD_PATH.include?(path)
    

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

答案 1 :(得分:6)

this post的评论中对此进行了很好的讨论。我认为下面这个说得很好:

  

当我第一次感到有些困扰时,这让我很烦   走到Ruby。这是一个残余   我的静态类型洗脑。三   事情可以缓解这种情况   真正的问题。 1.警告。您   可以说它应该是一个例外,   但实际上,这将是怎样的   在其他一些情况下不同   程序员默默地抓住了   例外?这让我想起了号码   2)不要与蠢货一起工作。只有蠢货   默默地捕捉异常并继续   只有白痴才会改变常数   以这种方式使用。这让我想到了   3)我们俩都不是白痴,所以你会   很高兴知道这有趣   从未发生在我身上。是真的   因为常量在Ruby中脱颖而出   无论如何,什么与他们的upcase,和   你多久有一次   常量作为代码中的L值?

要直接回答你的问题,我不会做任何事情来摆脱警告。只需将警告视为警告,然后再继续。