【问题标题】:Where to place "require" in Ruby code?在 Ruby 代码中将“require”放在哪里?
【发布时间】:2014-01-16 12:49:18
【问题描述】:

我正在使用 Ruby 2.0,我有两个文件:hello.rbassets/display.rb

hello.rb

class Hello
  def self.run_it(name)
    ui = Display.new(name)
    ui.say_hi
  end
end

require_relative "assets/display"

Hello.run_it("Someone")

assets/display.rb

class Hello::Display
  def initialize(name = "World")
    @name = name
  end

  def say_hi  
    puts "Hello #{@name}"  
  end
end

如果在 hello.rb 中我将 require_relative "assets/display" 移动到 class Hello(第一行)之前,ruby hello.rb 会输出 uninitialized constant 错误。这是为什么?需要外部文件时的最佳做法是什么?在这个简短的示例中,require_relative 是正确的方法(与 requirerequire "./some_file" 相比)?

【问题讨论】:

  • 你必须向我们展示你拥有的文件系统..
  • @ArupRakshit 谢谢,但在这种特殊情况下,这是无关紧要的。

标签: ruby require ruby-2.0


【解决方案1】:

标准做法是将所有或大部分 require 语句放在文件顶部。文件的设计应尽可能减少对其他文件的依赖。

您遇到的问题是您将文件display.rb 设计为依赖于类Hello

当你这样说时:

class Hello::Display
end

同理:

class Hello
  class Display
  end
end

但不同的是,在第一种情况下,需要先定义Hello,然后才能说Hello::Display。由于 Hello 在你将 require 放在文件顶部时尚未定义,你会得到错误。

你可以这样修复它:

class Hello
   class Display
     # ..your Display code here..
   end
end

或者像这样:

# Predefine Hello as a class name
class Hello
end

class Hello::Display
  # ..your Display code here..
end

【讨论】:

  • 感谢您的详细解释。现在说得通了。标记为已接受的答案。如果目标是在后期将代码打包为 gem,您能否确认应该使用 require_relative 而不是 require
  • @NicoS。是的 require_relative 非常适合 gem 代码。但是请注意,这不是严格要求的,因为您的 lib 目录将被 ruby​​gems 添加到加载路径中。但是我认为它可能仍然是一个更好的选择,因为它减少了冲突的机会。你可以在这里阅读更多关于使用 ruby​​gems 加载代码的信息:guides.rubygems.org/patterns/#loading_code,在这里你可以阅读更多关于require_relative的信息:*.com/questions/3672586/…
  • 再次感谢您。实际上,我希望我的代码在之前工作,我将它打包为一个 gem(所以,还没有在加载路径中)并且在打包它时不必更改它(这似乎是一个糟糕的模式! )。所以,require_relative 符合要求:)
  • 当然。在大多数情况下(在引入 require_relative 之前)测试 gem 代码时,开发人员必须手动修改加载路径以模拟 ruby​​gems。但是就像你说的那样,在任何地方使用 relative 会容易得多。这使得代码自动更便携。
【解决方案2】:

如果在 hello.rb 的开头包含文件 display.rb,当 ruby​​ 解释器遇到 class Hello::Display 时,它期望 Hello 在之前的某个地方定义。但是此时,Hello 类还没有定义,所以你看到了错误。

【讨论】:

    【解决方案3】:

    此错误的原因是您试图在Hello 类中定义一个类,此时尚未定义该类。只需将名称分成两个类:

    class Hello
      class Display
        def initialize(name = "World")
          @name = name
        end
    
        def say_hi  
          puts "Hello #{@name}"  
        end
      end
    end
    

    这样你可以同时定义两个类(你可以稍后打开 Hello 类)

    【讨论】: