我在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为'token',在哪种情况下我会得到异常(在哪种情况下它会进入else状态?)
此代码public_send("#{k}=", v)
动态调用存储在k
变量中的setter。请考虑以下示例:
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
“#{}”是ruby中的字符串插值。例如:
k = 'world'
puts "hello #{k}"
# hello world
因此,在您的示例中,它看起来像是在创建一个值为k和=的字符串
EG
k = 'something'
"#{k}="
# something=
如果你想知道k是什么,你可以在上面的行中添加puts k.to_s
然后运行代码并检查你的控制台。
更好的是,如果你使用像RubyMine这样的东西,只需使用调试器并在该行上粘贴一个断点。
我想你在_assign_attribute
看到了this docs方法
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或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