module Foo class Bar BAZ = "bof" ...
一切都是小狗和彩虹,直到我告诉Rake运行我所有的Test :: Unit测试.当它,我得到警告:
bar.rb:3: warning: already initialized constant BAZ
我的习惯是通过使常量初始化有条件地避免这些警告,例如:
... BAZ = "bof" unless const_defined? :BAZ ...
这似乎解决了这个问题,但是这是一个乏味的事情,我从来没有看到任何人以这种方式初始化常量.这让我觉得我可能会做错了.有没有更好的方法来初始化不会产生警告的常量?
更新:通过一些更多的细节,我如何使用这些常量,让我们说,我已经定义了一个令牌类,它有一些人造语言语法的所有字符的常量.我还有一个Scanner类,它读取一个字符串,为每一个生成一个令牌实例.
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现在运行单元测试,而不会发出任何警告.
解决方法
但是,它仅使用您传递给它的路径来确定文件是否已经加载,至少在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,那么它将被安装在site_ruby已经在$LOAD_PATH了.