2017-01-11 37 views
2

測試升級到Ruby 2.3.3我們的Rails應用3.2.22.2,並獲得在那裏我們傳遞一個數組一個奇怪的局面:作爲Tempfile.new的第一個參數,但它最終會成爲一個散列。紅寶石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' 

得是一個寶石或東西,但無法弄清楚了我的生活,爲什麼這種情況正在發生或在哪裏或什麼在改變行爲。

如何調試任何意見或建議?

+1

「put caller」的輸出在修補過的tempfile.rb中的輸出是什麼? –

回答

2

在你的情況,我認爲你的代碼中的某個地方有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 PARAM沒有默認值,你會得到:

val = ["Joe", "Bloe"] 

TempFile#initialize函數簽名從Ruby 2.1更改爲Ruby 2.2。

這裏的DIFF:

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

注意basename沒有默認值了。

+0

非常感謝你回答!這是一個非常好的發現!一直在掙扎。 – bschaeffer

0

只是嘗試這樣做在我的控制檯,並沒有得到錯誤。嘗試了一些東西,

  1. 確保您在軌應用使用Ruby 2.3或更高版本,因爲我相信,法make_tmpname是不同的前處理。
  2. 確保引號.csv的報價,而不是一個波浪號`。
  3. 我讓你同樣的錯誤使用Ruby 2.3.1如果我這樣做Tempfile.new(['test', /re/])

我希望這可以幫助,在這一天是什麼導致你錯誤的到底是這種方法try_convert這是第二回nil參數傳遞給Tempfile.new

+0

'\''是反引號(或[重音符號](http://www.fileformat.info/info/unicode/char/0060/index.htm))。 '〜'是[代字號](http://www.fileformat.info/info/unicode/char/007e/index.htm)。 –

+0

我知道有人會糾正我,但不記得名字,感謝兄弟。 –

+0

感謝您的反饋。上面的代碼是應用程序中沒有'〜'或''''的代碼,我使用2.3.3來產生錯誤。當你說你使用正則表達式得到同樣的錯誤,你的意思是你看到'[]'參數被轉換爲散列? – bschaeffer

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