【问题标题】:Ruby 2.3.3: Weird Tempfile.new([name, prefix]) basename converted to hashRuby 2.3.3:奇怪的 Tempfile.new([name, prefix]) basename 转换为哈希
【发布时间】:2017-01-11 18:48:50
【问题描述】:

为我们的 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'

一定是宝石之类的,但我终其一生都无法弄清楚为什么会发生这种情况,或者在哪里或是什么改变了这种行为。

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

【问题讨论】:

  • 在你修补的 tempfile.rb 中puts caller 的输出是什么?

标签: ruby-on-rails ruby ruby-on-rails-3.2 ruby-2.3


【解决方案1】:

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

我遇到了同样的问题,由于某种原因,当方法具有默认参数(在本例中为 basename="")和双 splatted 参数时,Ruby 在第一个参数上调用 to_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 不再有默认值。

【讨论】:

  • 非常感谢您的回答!!!!这是一个非常好的发现!已经为此苦苦挣扎了一段时间。
  • 很好的发现,谢谢。但是有/没有默认名称,这两种情况我在运行“ruby 2.3.1p112”时仍然遇到错误
  • 我的问题与默认参数无关。我在 basename 中获得了一个数组,并且在转换为字符串以验证前缀时遇到了问题。将该值从数组更新为文件名字符串,解决了我的问题。
【解决方案2】:

刚刚在我的控制台中尝试过,没有出现错误。尝试一些东西,

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

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

【讨论】:

  • ` 是一个反引号(或grave accent)。 ~tilde
  • 我知道有人会纠正我,但不记得名字了,谢谢老兄。
  • 感谢您的反馈。上面的代码是应用程序中的代码,编号为 ~`,我使用 2.3.3 来产生错误。当您说使用正则表达式遇到相同的错误时,您的意思是您看到 [] 参数被转换为哈希?
【解决方案3】:

这就是我修复它的方法。

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  

【讨论】:

  • 这对我不起作用,并且在运行“ruby 2.3.1p112”时仍然出现相同的错误
  • 这并没有解决我的错误,但帮助我找到了我的错误。就我而言,basename 是一个数组,这在 ruby​​-2.1.8 中不是问题,但 ruby​​-2.3.1 开始为此出错。数组试图转换为字符串,以获取前缀,它变成 nil 并给出运行时错误“意外前缀”。将发送到 Tempfile 的 basename 参数更新为文件名字符串解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-06
相关资源
最近更新 更多