【问题标题】:Tracing dependency loading in Rails在 Rails 中跟踪依赖项加载
【发布时间】:2011-10-31 18:18:06
【问题描述】:

我们的团队正在开发一个新应用程序,我们从 Rails 3.1 和 Ruby 1.9.2 开始 - 昨晚我把它带到了 Ruby 1.9.3。

我们在依赖链 (css_parser) 中使用的其中一个 gem 最终在其中包含一个 require 'iconv',在 1.9.3 中触发 a deprecation warning,如下所示:

.../gems/activesupport-3.1.1/lib/active_support/dependencies.rb:240:in `block in require': iconv will be deprecated in the future, use String#encode instead.

起初我天真地把它归咎于 rails 没有更好的踪迹,直到我在任何地方都没有找到 require 'iconv'。

我追踪到这一点的唯一方法是我开始在我的 Gemfile 中注释掉一些东西,然后我终于想到了加载 irb 并开始依次请求每个库的好主意。我也可以在 gems 目录中完成一个文件系统 grep,但我不确定“require 'iconv'”是什么触发了错误。

什么皮塔饼。必须有更好的方法 - 只需在加载轨道没有削减它的 rake 任务中执行 --trace 。是否有某种方式/任何方式可以触发对此的跟踪,以向我显示相对较长的库依赖项列表中的哪一行触发了弃用?

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    所以,这可能有点没有实际意义,因为我不太可能再次遇到这个问题(并且 css_parser gem 是我当前 Rails 3.1/Ruby 1.9.3 项目中唯一需要 iconv 的 gem)。

    但它一个难题,所以我想找到解决它的方法。

    在这种情况下,问题是非常特定于 iconv 的。还有其他 ruby​​ 弃用,但在大多数情况下,它们似乎通过 Kernel#warn(如果是 ruby​​)或 rb_warn()(如果是 C) - 但 warning in iconv.c is a little different 比其他人 - 无论如何它是对 rb_stderr 的投入。

    所以也许我可以做以下事情

    1. 覆盖内核#require 以捕获标准错误
    2. 调用原始内核后检查 iconv 消息#require
    3. 如果找到消息,则引发异常,从而获得跟踪
    4. 如果可能,请在打包程序运行之前执行此操作。

    事实证明我做不到 #4 - 因为 Bundler 直接调用 Kernel.require - 但我可以使用 Bundler 解析 Gemfile 来给我自己需要的东西列表。

    这就是我得到的——感谢this stack overflow post 提供关于捕获标准错误的指针——以及aliasing the original Kernel#require 上的想法的rubygems 来源

    # override Kernel#require to intercept stderr messages on require
    # and raise a custom error if we find one mentioning 'iconv'
    require "stringio"
    
    class RequireError < StandardError
    end
    
    module Kernel
    
      alias :the_original_require require
      private :the_original_require
    
      def capture_stderr
        # The output stream must be an IO-like object. In this case we capture it in
        # an in-memory IO object so we can return the string value. You can assign any
        # IO object here.
        previous_stderr, $stderr = $stderr, StringIO.new
        yield
        $stderr.string
      ensure
        # Restore the previous value of stderr (typically equal to STDERR).
        $stderr = previous_stderr
      end
    
      def require(name)
        captured_output = capture_stderr do
          the_original_require(name)
        end
    
        if(captured_output =~ %r{iconv})
          raise RequireError, 'iconv requirement found'
        end
      end
    end
    
    require 'bundler'
    
    # load the list of Bundler requirements from the Gemfile
    required_libraries = Bundler.definition.dependencies.map(&:name)
    
    # loop through and require each, ignoring all errors other than
    # our custom error
    
    required_libraries.each do |requirement|
      begin
        require(requirement)
      rescue Exception => e
        if(e.class == RequireError)
          raise e
        end
      end
    end
    

    瞧!有助于追踪 iconv 需求所在位置的跟踪消息。

    最后,最好只搜索“require 'iconv'”(一旦清楚这是导致错误的原因)。

    但是,就像在生活中一样。 Some Yaks Must Be Shaved.

    【讨论】:

    • 您可能对stackoverflow.com/questions/660737/… 感兴趣,它询问如何在提供警告时引发异常。
    • 是的,我从重写 Kernel#warn 的想法开始,当我开始在 ruby​​ 代码中搜索 iconv 错误时,很快就放弃了这个想法。我真希望有更好的方法。
    【解决方案2】:

    您可以查看Gemfile.lock 文件,该文件将所有依赖项保存在分层树中,并指示每个 gem 所需的版本。这可能有助于识别需要它的 gem。

    【讨论】:

    • 当我在 Gemfile 中注释掉(或要求)每个命名库时,结果证明这有助于将其缩小到子依赖项 - 但获得一个跟踪触发弃用的特定源代码行。
    • 是的。我个人不知道有什么方法可以做到这一点。同样在等待答案。 ;)
    猜你喜欢
    • 1970-01-01
    • 2010-10-12
    • 2010-09-22
    • 2012-12-28
    • 1970-01-01
    • 2013-01-09
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多