为我们的Rails 3.2.22.2应用程序测试升级到Ruby 2.3.3,并得到一个奇怪的情况,我们将一个数组作为Tempfile.new
的第一个参数传递,但它最终成为一个哈希。 / p>
我已修补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'
要成为一个宝石或其他东西,但无法弄清楚为什么会发生这种情况或者改变行为的地方或内容。
有关如何调试的任何想法或建议?
答案 0 :(得分:2)
在您的情况下,我认为您的代码中某处定义了Array#to_hash
方法。
我遇到了同样的问题,并且由于某种原因,当一个方法有一个默认参数(在本例中为basename=""
)和一个双splatted参数时,Ruby会在第一个参数上调用to_hash
函数。 / p>
请参阅以下示例:
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
不再具有默认值。
答案 1 :(得分:0)
在我的控制台中试过这个,没有错误。尝试一些事情,
make_tmpname
之前的处理方式不同。 .csv
周围的引号是引号,而不是代字号。Tempfile.new(['test', /re/])
我希望这会有所帮助,在一天结束时,导致错误的是这个方法try_convert,它会为您传递给nil
的第二个参数返回Tempfile.new
答案 2 :(得分: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