将Constant传递给方法,导致语法错误。使用Splat操作员

时间:2017-06-27 07:30:33

标签: ruby-on-rails ruby

我有一个代码片段,它生成一个模型属性名称和setter等价物的扁平数组,然后使用splat运算符将此数组作为变量传递给Module.delegate(),将所有User.attributes委托给BaseUser类。这很好。

请参阅https://apidock.com/rails/Module/delegate

class BaseUser
  include ActiveModel::Model
  attr_accessor :user

  # The code snippet described above
  delegate(*::User.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :user)

  def initialize(user_attributes)
    @user = ::User.new(user_attributes)
  end
end

现在,我希望将此片段重新编写为可以将[ModelName] < ActiveRecord::Base类常量作为参数的方法。但是,我的尝试(下面)导致了几个语法错误。我哪里错了?

def delegate_getters_and_setters(model)
   delegate(*::model.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: model.downcase.to_sym)
end

感谢您的帮助!

修改

以下是Sublime Text 3突出显示的语法错误。

-:6: syntax error, unexpected tIDENTIFIER, expecting tCONSTANT
      delegate(*::model.attribute_names.map {|attr| ...
                       ^
-:6: syntax error, unexpected tLABEL, expecting '='
...ttr, "#{attr}="] }.flatten, to: model.downcase.to_sym)
...                               ^
-:6: syntax error, unexpected ')', expecting keyword_end

3 个答案:

答案 0 :(得分:4)

::model毫无意义。 model是一个局部变量。只需删除它前面的双冒号:

delegate(*model.attrib......

答案 1 :(得分:3)

  

现在,我希望将此代码段重新编写为可以将[ModelName] < ActiveRecord::Base类常量作为参数的方法。

您不能将常量作为参数。您只能将对象作为参数。常量不是对象。

  

但是,我的尝试(下面)导致了几个语法错误。我哪里错了?

您假设您将常数作为参数。但你没有。有人打电话时

delegate_setters_and_getters(Foo)

你没有得到常量Foo作为参数。你不能,因为常量Foo不是一个对象。相反,常量Foo在调用站点被取消引用,并且您可以在调用站点将任何对象Foo解析为(可能是一个类)作为参数。

它与任何其他表达式完全相同。如果你打电话

delegate_setters_and_getters(foo)

传递局部变量foo作为参数,你传递foo引用的对象作为参数。 (事实上​​,你无法传递局部变量作为参数,即使你想要,因为变量不是对象。)

如果你打电话

delegate_setters_and_getters(bar.baz)

传递方法调用bar.baz作为参数,你在通过解除引用局部变量baz获得的对象上调用方法bar然后将该方法调用的返回值作为参数传递。 (同样,方法调用不是对象,所以即使你想要也不能传递它们。)

答案 2 :(得分:2)

除了@mudasobwa说的话:

::是常量完全限定名称(FQN)语法的一部分。前导::有助于消除名称解析的歧义。

在您的情况下,delegate_getters_and_setters常量名称已经解析,model是对常量 * 的引用,无论它是什么。

*其中“引用常量”我的意思是“引用常量指向的同一个对象”,当然。