Ruby中使用hash参数和Hash#merge的语法错误

时间:2012-07-04 02:39:46

标签: ruby

我正在尝试做一个开源贡献,下面带有options.merge()的star_rating方法中的代码行(这是我尝试提交的更改)被踢回以下消息“这是无效的Ruby语法(1.8.7和1.9.3)......“我的问题是为什么?我检查了ruby交互式shell上的Hash#merge方法,它似乎有效。

def star_rating(options = {})
   ##original line of code
   has_many :rates_without_dimension, :as => :rateable, :class_name => 'RateMe', :dependent => :destroy, :conditions => {:dimension => nil}  

  ##line of code I tried to submit
  has_many :rates_without_dimension, :as => :rateable, options.merge(:class_name => 'RateMe'), :dependent => :destroy, :conditions => {:dimension => nil}  
end

3 个答案:

答案 0 :(得分:2)

根据第一版“红宝石编程语言”的第6.4.4章

  

如果Ruby是方法的最后一个参数(或者如果后面的唯一参数是一个块参数,前缀为&),则允许您省略散列文字周围的花括号。

您的方法调用的格式为method a => b, c => d, {e => f, g => h}, i => j,因为hash.merge将返回一个哈希值。所以你要分解哈希,而不是放入一个哈希,并且编译器假定a => b, c=>d是一个哈希,这不会是最后一个参数,打破了最后一个参数规则。

另外,根据同一节

  

如果省略括号,那么必须省略花括号。

你的hash.merge返回花括号中的哈希值,这会破坏该规则。

编辑:只要哈希不是唯一的参数,这实际上就可以了。

答案 1 :(得分:1)

通常,将options传递给Ruby方法通常是通过将其作为最后一个参数来完成的。在某些情况下,它实际上需要是最后一个参数。

答案 2 :(得分:1)

这确实是无效的语法。方法调用的最后一个参数可以是Hash,在这种情况下Ruby允许你删除封闭的{}

foo(1, 2, 3, :a => 4, :b => 5)
# equivalent to:
foo(1, 2, 3, {:a => 4, :b => 5})

在您的情况下,您在简单参数(:as => :rateable)之前有options.merge,这是不允许的。

如果你倒掉它们,你仍然无法获得你想要的效果:

has_many :rates_without_dimension, options.merge(:class_name => 'RateMe'), :as => :rateable, :dependent => :destroy, :conditions => {:dimension => nil}
# same as
has_many :rates_without_dimension, options.merge(:class_name => 'RateMe'), {:as => :rateable, :dependent => :destroy, :conditions => {:dimension => nil}}
# => has 3 arguments, not 2.

你可以做的是确保你传递两个参数。一种方法:

has_many :rates_without_dimension, options.merge(:class_name => 'RateMe', :as => :rateable, :dependent => :destroy, :conditions => {:dimension => nil})

请注意,在Ruby 2.0中,可以使用等效的数组(*)的splat运算符来执行您想要的操作will be ** for hashes

h = {:b => 2}
foo(:a => 1, **h, :c => 3)
# same as
foo(:a => 1, :b => 2, :c => 3) 

# so you will be allowed to write:
has_many :rates_without_dimension, :as => :rateable, **options.merge(:class_name => 'RateMe'), :dependent => :destroy, :conditions => {:dimension => nil}