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

前端之家收集整理的这篇文章主要介绍了在Ruby中初始化常量的正确方法是什么?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个简单的类来定义一些常量,例如:
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现在运行单元测试,而不会发出任何警告.

解决方法

这可能发生的唯一方法是当bar.rb需要多次时.这不应该发生,因为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,那么它将被安装在site_ruby已经在$LOAD_PATH了.

猜你在找的Ruby相关文章