如何从Ruby中的符号中获取keyname参数的值?

时间:2014-10-29 12:59:41

标签: ruby

作为Ruby元编程的一个实验,我可以说我有一个类Pet,它带有几个关键字参数。

然后我想动态地将关键字参数分配给属性:

class Pet
  def initialize(name:, age: 0)
    args = method(__method__).parameters.map { |arg| arg[1] }
    args.each do |name| 
      instance_variable_set("@#{key.to_s}", eval(name.to_s)) # Is it possible to do this without eval?
    end
  end
end

但我想避免使用eval。 是否可以使用Javascript中的arguments对象来获取调用函数的参数?

修改

为何选择关键字参数?这里的想法是在initializer声明中指定allowed和default参数。虽然可能不是世界上最好的想法,但是因为你可以在不使用docblock的IDE检查中获得签名,所以它会很酷。

请注意:我非常清楚这可以通过使用splathash作为参数来实现。这不是问题。

2 个答案:

答案 0 :(得分:1)

您可以使用eval名义上避免使用binding.local_variable_get,这听起来就像听起来一样。

class Pet
  def initialize(name:, age: 0)
    args = method(__method__).parameters.map { |arg| arg[1] }
    args.each do |name| 
      instance_variable_set(:"@#{name}", binding.local_variable_get(name))
    end
  end
end

当然,如果你只是哈希,这会变得更加清晰。界面相同;来电者仍然可以Pet.new(name: 'Rover', age: 5)

答案 1 :(得分:1)

关键字参数作为局部变量添加,因此,您可以使用当前binding获取值:

class Pet
  def initialize(name:, age: 0)
    args = method(__method__).parameters.map { |arg| arg[1] }

    args.each do |key| 
      value = binding.local_variable_get(key)
      instance_variable_set("@#{key}", value)
    end
  end
end

但有些警告适用。使用binding,您可以访问有关特定变量范围的详细信息。虽然这是强大的,但它在Ruby中通常相当慢,事实上,支持binding根本就是所有Ruby实现中最伟大的性能杀手之一。

此外,以这种方式访问​​本地变量可能会导致严重的安全问题,因为它可用于访问不相关的系统状态。要非常小心,你用这种方式暴露哪些变量。

最后,绑定总是在调用它的确切位置生成。这意味着,如果您将新值分配给例如调用name之前的binding变量,它将返回该新值,而不是原始方法参数。因此,我将您的块参数名称更改为key