在Rails中跟踪依赖项加载

时间:2011-10-31 18:18:07

标签: ruby-on-rails ruby

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

我们在依赖链中使用的一个宝石(css_parser)最终在其中有一个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.

起初我天真地指责铁轨没有更好的痕迹,直到我没有在任何地方找到需要'iconv'。

我追踪这个问题的唯一方法就是我开始在我的Gemfile中评论事情,然后我终于有了明智的想法来加载irb并开始依次要求每个库。我也可以在gems目录中完成一个文件系统grep,但我不确定“require'iconv'”是触发错误的原因。

什么是PITA。必须有一个更好的方法 - 只是在rake任务中执行--trace,加载rails没有削减它。是否有某种方式/任何方式触发跟踪,这将显示相​​对较长的库依赖项列表中的哪一行触发了弃用?

2 个答案:

答案 0 :(得分:6)

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

是一个谜题,所以我想找到解决问题的方法。

在这种情况下,问题非常特定于iconv。还有其他ruby弃用,但在大多数情况下,它们似乎通过内核#warn(如果是ruby)或rb_warn()(如果是C) - 但warning in iconv.c is a little different而不是其他 - 无论如何它是' sa放到rb_stderr。

所以也许我可以做以下

  1. 覆盖内核#require以捕获stderr
  2. 在调用原始内核#require
  3. 后检查iconv消息
  4. 如果找到消息,则提出异常,从而获得跟踪
  5. 如果可能的话,在捆绑器运行之前执行此操作。
  6. 事实证明我不能做#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要求的位置。

    最后,可能只是搜索&#34;要求&#39; iconv&#39;&#34;仍然是最好的(一旦明确了导致错误的原因)。

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

答案 1 :(得分:0)

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