3

为我们的 Rails 3.2.22.2 应用程序测试升级到 Ruby 2.3.3,并得到一个奇怪的情况,我们将数组作为第一个参数传递给Tempfile.new,但它最终以哈希的形式出现。

我已经修补tempfile.rb以输出basename传入的参数。

irb会话(非 Rails)中,一切都很好:

> require 'tempfile'
true
> Tempfile.new(['test', '.csv'])
["home", ".csv"] # output of basename argument for Tempfile.new
 => #<Tempfile:/var/blah/test###.csv> 

在一个rails console会话中:

> Tempfile.new(['test', '.csv'])
{"test"=>nil, ".csv"=>nil}
ArgumentError: unexpected prefix: {"test"=>nil, ".csv"=>nil}
from /path/to/ruby-2.3.3/lib/ruby/2.3.0/tmpdir.rb:113:in `make_tmpname'

必须是宝石或其他东西,但我一生都无法弄清楚为什么会发生这种情况,或者在哪里或在什么地方改变了行为。

关于如何调试的任何想法或建议?

4

3 回答 3

3

在您的情况下,我认为您的代码中某处Array#to_hash定义了该方法。

我遇到了同样的问题,由于某种原因,当一个方法有一个默认参数(在这种情况下basename="")和一个双 splatted 参数时,Rubyto_hash在第一个参数上调用该函数。

请参见以下示例:

class Dummy
  def initialize(val = "", **options)
    puts "val = #{val}"
    # puts "Options: #{options}"
  end
end

class Array
  def to_hash
    puts "to_hash called on #{self}"
  end
end

Dummy.new(["Joe", "Bloe"])

这将输出

to_hash called on ["Joe", "Bloe"]
val = ["Joe", "Bloe"]

但是当参数没有默认值时val,你会得到:

val = ["Joe", "Bloe"]

请注意,TempFile#initialize函数签名已从 Ruby 2.1 更改为 Ruby 2.2。

这是差异:

-  def initialize(basename, *rest)
+  def initialize(basename="", tmpdir=nil, mode: 0, **options)

请注意,basename它不再具有默认值。

于 2017-07-20T03:54:49.343 回答
0

这就是我修复它的方法。

class Tempfile 
  def initialize(basename="", tmpdir=nil, mode: 0, **options)
    warn "Tempfile.new doesn't call the given block." if block_given?

    basename = basename.keys if basename.kind_of?(Hash)

    @unlinked = false
    @mode = mode|File::RDWR|File::CREAT|File::EXCL
    ::Dir::Tmpname.create(basename, tmpdir, options) do |tmpname, n, opts|
      opts[:perm] = 0600
      @tmpfile = File.open(tmpname, @mode, opts)
      @opts = opts.freeze
    end
    ObjectSpace.define_finalizer(self, Remover.new(@tmpfile))

    super(@tmpfile)
  end
end  
于 2017-01-30T14:29:20.963 回答
0

刚刚在我的控制台中尝试过,没有错误。尝试几件事,

  1. 确保您在铁路应用程序中使用 ruby​​ 2.3 或更高版本,因为我相信该方法make_tmpname之前的处理方式有所不同。
  2. 确保周围的引号.csv是引号而不是波浪号 `。
  3. 如果我这样做,我会在 ruby​​ 2.3.1 上遇到同样的错误Tempfile.new(['test', /re/])

我希望这会有所帮助,归根结底,导致你的错误的是这个方法try_convert,它返回nil你传递给的第二个参数Tempfile.new

于 2017-01-11T19:41:17.063 回答