【问题标题】:Ruby - Code someone explain the following codeRuby - 代码有人解释以下代码
【发布时间】:2019-04-01 12:19:07
【问题描述】:

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

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

我知道 respond_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 状态?)

【问题讨论】:

  • 请添加到库的名称,如果可以,请添加有关该代码段的链接。
  • 这是一个带有插值的随意string literal:如果k"foo"(或:foo),那么"#{k}=" 的计算结果为"foo="
  • 这是一个纯 Ruby 问题,所以它不应该有 Rails 标记。
  • 如果k = "foo",第一行将显示,“如果默认接收者self响应'foo='方法”。 respond_to 的参数可以是字符串或符号 (:foo=)。见Object#respond_to?
  • @CarySwoveland 请检查已编辑的问题

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


【解决方案1】:

此代码public_send("#{k}=", v) 动态调用存储在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

【讨论】:

  • 如果我的参数 k=token,在其他情况下我实际上得到了异常。在上述情况下,我会在哪种情况下得到异常?
  • 当类没有 token 的设置器时,例如既没有声明attr_writer :token,也没有声明attr_accessor :token,也没有声明def token=(value)。尝试阅读我的答案并更好地理解
【解决方案2】:

"#{}" 是 ruby​​ 中的字符串插值。比如:

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

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

的字符串

例如

k = 'something'
"#{k}="
# something=

如果您想知道 k 是什么,可以在上面的行中添加 puts k.to_s 然后运行代码并检查您的控制台。

如果您使用的是 RubyMine 之类的东西,那就更好了,只需使用调试器并在该行设置断点即可。

【讨论】:

  • 感谢您的回复但我仍然不明白为什么字符串操作会出现在 IF 检查中
  • 这绝不是回答原始问题。如果我可以多次否决使用 RubyMine 的荒谬建议,我会这样做。
  • @AlekseiMatiushkin 这个问题非常具体地提出:“有人能解释一下代码 ("#{k}=") 的含义吗?”。我已经解释了 #{} 的含义并给出了示例。我使用调试工具的建议是让 OP 在运行时确定变量的含义。因此,与您的评论相反,我回答了所提出的问题。如果您觉得可以添加更多或更好地回答问题,请随时贡献。如果您认为提出的问题不是正确的问题,或者措辞有误导性,请向 OP 提出问题。把你的消极情绪留给自己
  • 请冷静,红宝石朋友。我们是来解决问题的,不是互相争斗,对吧?
【解决方案3】:

我想你在this docs中看到了_assign_attribute方法

k是'key'的缩写,v是'value'的意思

"#{k}=" 是通过字符串字面量动态方法的某种方法名称。

可能是“更新”或“创建”、“拆分”或其他任何内容。

等号(“=”)的意思是它们是分配类似user.attributes = { :username =&gt; 'Phusion', :is_admin =&gt; true }的方法

在上述情况下,“k”是.attributes,“k=”是attributes=,“v”是{ :username =&gt; 'Phusion', :is_admin =&gt; true }

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

所以public_send("#{k}=", v)的意思是在公共方法中调用一个名为“k”的方法,这个方法会被赋值给“v”作为值。

我希望这个解释对你有所帮助。


添加一些评论示例

k 是程序员的输入,因此它与 Class 或 Module 中的方法名称不匹配。

在现实中,有常见的错误案例。

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

【讨论】:

  • 为什么这个 IF 条件失败是我的问题 "If respond_to?("#{k}=")" ?为什么会进入 else 状态?
  • 我的意思是,如果key k = token,输入有什么问题,为什么会进入ELSE条件?
  • Class User 不是有效的 ruby​​ 语法。此外,ruby 中没有 assign_attribute,尽管问题被标记为 rails,但问题与 rails 无关。投反对票。
  • @AlekseiMatiushkin 感谢您对语法的评论。我不确定他指的是assign_attribute。这只是我的猜测。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-21
  • 2012-04-09
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 2022-10-14
  • 2010-10-11
相关资源
最近更新 更多