【问题标题】:Clean way to require all files in non-Rails Ruby app?要求非Rails Ruby应用程序中所有文件的干净方式?
【发布时间】:2012-01-17 18:23:57
【问题描述】:

我正在尝试用 Ruby(而不是 Rails)编写游戏,以便更好地自学。 (意思是,我想把这件事做对,但如果我试图硬塞一些在 Ruby 中无法使用的东西,我会切换语言。)我遇到了 require order 的问题,我'想知道是否有一种干净的方法来执行以下操作。

到目前为止,这是我的结构:

game
  Gemfile
  src
    models
      character.rb
      game_object.rb
  init.rb

init.rb 需要这样的文件,而不是单独列出每个文件:

  Dir['./src/**/*.rb'].each do |app|
    require app
  end

到目前为止,game_object.rb 非常简单,但 character.rb 看起来像这样:

module Game
  class Character < Game::GameObject
    attr_accessor :name

    def initialize(name)
      @name = name
      end
  end
end

不幸的是,如果我这样做,我会得到“未初始化的常量 Game::GameObject (NameError)”,除非我在其他文件之前明确要求 game_object。

在我看来,我有几个选择:

  1. 先在 init.rb 中加载 game_object(和其他超类)。
  2. 在 character.rb 中需要 game_object,这似乎有问题,因为根据我使用的路径,我的理解是它可能会多次加载文件。
  3. 单独加载每个文件并完全手动管理订单,因此我可以完全控制。

这些似乎都比应有的复杂。有没有更清洁的方法?

【问题讨论】:

    标签: ruby require


    【解决方案1】:

    只是把它放在那里:更多的代码并不意味着“肮脏”,就像更少的代码并不意味着“干净”一样。

    从长远来看,手动请求您的文件将减少您的麻烦 - 它解决了加载顺序问题并防止您需要您实际上不需要的文件。此外,以后查看您的代码的任何人都可以清楚地看到您的应用中正在加载的内容。

    我的建议:

    1. 删除 src 文件夹,它是多余的 - 您的 Ruby 应用程序是所有源代码。
    2. 将命名空间映射到文件夹
    3. 使用显式要求(使用 #2 会更容易:

    例子:

    game/
      bin/
        gamerunner
      Gemfile
      lib/
        game.rb
        game/
          game_object.rb
      models/
        character.rb
      spec/
        spec_helper.rb
        models/
          character_spec.rb
    

    您正在编写规范/测试,不是吗?

    然后,在lib/game.rb

    require 'game/game_object.rb'
    # require the rest of your library as you build it
    
    module Game
    end
    

    在你的初始化中:

    require 'game'
    require 'models/character.rb'
    

    更干净,以后更容易提取,应该可以解决您的问题。

    【讨论】:

    • 拥有一个 src 目录并不比拥有一个 lib 目录更多余——而且当您不编写库时更有意义。
    • 在这里达成共识,到目前为止它对我有用。谢谢!
    【解决方案2】:

    我之前没做过,但你可以将自己的自动加载逻辑添加到Module#const_missing

    class Module
      def const_missing_with_autoload(c)
        components = []
        (self.to_s.split("::") + c.to_s.split("::")).reverse.each do |comp|
          components.unshift(comp.gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase)
          begin
            require File.join(*components)
            return const_get(c)
          rescue LoadError
          end
        end
        const_missing_without_autoload(c)
      end
    
      alias_method :const_missing_without_autoload, :const_missing
      alias_method :const_missing, :const_missing_with_autoload
    end
    

    我认为这在没有方法混乱的情况下可以工作,但我无法让它工作。我希望有人发布一个干净的解决方案来实现我想要做的事情。 FWIW,只是将 ActiveSupport 添加到您的项目中可能还是有用的。

    【讨论】:

      猜你喜欢
      • 2011-01-30
      • 2014-04-19
      • 2016-09-29
      • 2012-02-01
      • 2012-11-12
      • 2017-04-26
      • 1970-01-01
      • 2010-10-18
      相关资源
      最近更新 更多