Ruby-代码有人解释以下代码

时间:2019-04-01 12:19:08

标签: ruby-on-rails ruby ruby-on-rails-3 rubygems

我在a library中有以下代码,有人可以解释一下以下代码中的代码(“#{k} =“)是什么意思吗?

if respond_to?("#{k}=")
  public_send("#{k}=", v)
else
  raise UnknownAttributeError.new(self, k)
end

我了解到response_to是Ruby中的默认函数,但该语法没有定义/解释,请帮助我们。

已编辑:

我收到上述代码的异常(unknown attribute 'token' for PersonalAccessToken. (ActiveModel::UnknownAttributeError)

/opt/gitlab/embedded/lib/ruby/gems/2.5.0/gems/activemodel-5.0.7.1/lib/active_model/attribute_assignment.rb:40:in `block in _assign_attributes'
/opt/gitlab/embedded/lib/ruby/gems/2.5.0/gems/activemodel-5.0.7.1/lib/active_model/attribute_assignment.rb:48:in `_assign_attribute': unknown attribute 'token' for PersonalAccessToken. (ActiveModel::UnknownAttributeError)

因此,将k视为“令牌”,在哪种情况下我会得到异常(在哪种情况下会进入else状态?)

3 个答案:

答案 0 :(得分:1)

此代码public_send("#{k}=", v)动态调用setter来存储k变量中的内容。考虑以下示例:

class FooBarBaz
  attr_accessor :foo, :bar, :baz

  def set_it what, value
    public_send("#{what}=", value)
  end
end

大致相当于:

  def set_it what, value
    case what
    when "foo" then public_send("foo=", value)
    when "bar" then public_send("bar=", value)
    when "baz" then public_send("baz=", value)
    end
  end

大致相当于:

  def set_it what, value
    case what
    when "foo" then self.foo=(value)
    ...
    end
  end

大致相当于:

  def set_it what, value
    case what
    when "foo" then self.foo = value
    ...
    end
  end

预先调用

respond_to?来检查此实例上是否确实为此k定义了setter,以防止出现以下情况:

FooBarBaz.new.set_it :inexisting, 42
#⇒ NoMethodError: undefined method `inexisting=' for #<FooBarBaz:0x0056247695a538>

此答案中该类的修改后的正确版本:

class FooBarBaz
  attr_accessor :foo, :bar, :baz

  def set_it what, value
    public_send("#{what}=", value) if respond_to?("#{what}=")
  end
end

它不会引发异常。

FooBarBaz.new.set_it :inexisting, 42
#⇒ nil

答案 1 :(得分:0)

“#{}”是红​​宝石中的字符串插值。例如:

PS C:\nodejs\prod\monetrum-node-client> npm unpublish monetrum-node- 
client --force
npm WARN using --force I sure hope you know what you are doing.
npm ERR! code E400
npm ERR! You can no longer unpublish this version. Please deprecate it 
instead
npm ERR! npm deprecate -f 'monetrum-node-client@*' "this package has 
been deprecated" : 12-7be182ce2a14ca2bb34c07a7707a75c0

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\HP\AppData\Roaming\npm-cache\_logs\2019-04- 
01T12_24_19_378Z-debug.log
PS C:\nodejs\prod\monetrum-node-client>

因此在您的示例中,它看起来像是在创建一个值为k和=

的字符串

例如

k = 'world'
puts "hello #{k}"
# hello world

如果您想知道k是什么,可以在上面的行中添加k = 'something' "#{k}=" # something= ,然后运行代码并检查控制台。

如果您使用的是类似RubyMine的更好,则只需使用调试器并在该行上插入断点即可。

答案 2 :(得分:-1)

我认为您在this docs中看到了_assign_attribute方法

k是'key'的缩写含义,v是'value'的同义含义

"#{k}="是通过字符串文字转换为动态方法的某种方法名称。

可能是“更新”或“创建”,“拆分”等任何内容。

等号(“ =”)的含义是它们是分配诸如此类user.attributes = { :username => 'Phusion', :is_admin => true }

的方法

在上述情况下,“ k”为.attributes,“ k =“为attributes=,“ v”为{ :username => 'Phusion', :is_admin => true }

public_send是在公共范围内发送方法的方法。

因此,public_send("#{k}=", v)的含义是在公共方法中调用名称为“ k”的方法,并且该方法将被分配给值“ v”。

我希望这对您有所帮助。


添加一些评论示例

k是程序员的输入,因此它与“类”或“模块”中的方法名称不匹配。

实际上,有常见的错误情况。

class User
  # this attribute can be called from a instance of User
  attr_accessor :name
end

# this causes a error when call assign_attribute
User.new.wrong_name

# this is fine
User.new.name

assignment method reference