Ruby元编程实现动态方法?
Ruby metaprogramming to achieve dynamic methods?
想使用元编程实现以下代码。
@resource = {}
@voters = {}
@is_upvoted = {}
def resource(comment)
@resource[comment.id]
end
def voters(comment)
@voters[comment.id]
end
def is_upvoted(comment)
@is_upvoted[comment.id]
end
如何使用 ruby 元编程创建这些方法并访问哈希?
你能告诉我我的代码有什么问题吗?
['resource', 'voters', 'is_upvoted'].each do |attribute|
define_method("#{attribute}") do |comment|
instance_variable_set("@#{attribute}", comment.id)
end
end
Can you tell me what is wrong in my code ?
它的作用相当于:
def resource(comment)
@resource = comment.id
end
instance_variable_get
会是更好的选择。
这个有点多余:
@resource = {}
@voters = {}
@is_upvoted = {}
因为您已经在循环数组来进行元编程。
您可以尝试类似的方法:
class Foo
%w(
resource
voters
is_upvoted
).each do |attr_sym|
define_method attr_sym do |comment|
instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
instance_variable_get("@#{attr_sym}")[comment.id]
end
end
end
我相信这会给你大致如下的方法:
class Foo
def resource(comment)
@resource ||= {}
@resource[comment.id]
end
end
就我个人而言,在您的方法中使用 comment.id
似乎不太好。因为如果有一天您想使用不同的属性(或其他属性)作为 key
?
怎么办?
所以,我想我会这样做:
class Foo
%w(
resource
voters
is_upvoted
).each do |attr_sym|
define_method attr_sym do |key|
instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
instance_variable_get("@#{attr_sym}")[key]
end
end
end
现在,您似乎想要一种在实例变量上设置键值对的简单方法,所以我想我会尝试类似的方法:
class Foo
%w(
resource
voters
is_upvoted
).each do |attr_sym|
define_method attr_sym do |key=nil|
instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
hsh = instance_variable_get("@#{attr_sym}")
return hsh[key] if key
hsh
end
end
end
在这种情况下你应该能够做到(假设你有一个响应 id
的 @comment
变量):
@comment.id
=> 1
foo = Foo.new
=> #<Foo:0x000056536d7504b0>
foo.resource
=> {}
foo.resource[@comment.id] = :bar
=> :bar
foo.resource
=> {1=>:bar}
foo.resource[@comment.id]
=> :bar
我就是这样使用它的,而且效果很好
['resource', 'voters', 'is_upvoted'].each do |attribute|
define_method("#{attribute}") do |comment|
instance_variable_get("@#{attribute}")[comment.id]
end
end
想使用元编程实现以下代码。
@resource = {}
@voters = {}
@is_upvoted = {}
def resource(comment)
@resource[comment.id]
end
def voters(comment)
@voters[comment.id]
end
def is_upvoted(comment)
@is_upvoted[comment.id]
end
如何使用 ruby 元编程创建这些方法并访问哈希?
你能告诉我我的代码有什么问题吗?
['resource', 'voters', 'is_upvoted'].each do |attribute|
define_method("#{attribute}") do |comment|
instance_variable_set("@#{attribute}", comment.id)
end
end
Can you tell me what is wrong in my code ?
它的作用相当于:
def resource(comment)
@resource = comment.id
end
instance_variable_get
会是更好的选择。
这个有点多余:
@resource = {}
@voters = {}
@is_upvoted = {}
因为您已经在循环数组来进行元编程。
您可以尝试类似的方法:
class Foo
%w(
resource
voters
is_upvoted
).each do |attr_sym|
define_method attr_sym do |comment|
instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
instance_variable_get("@#{attr_sym}")[comment.id]
end
end
end
我相信这会给你大致如下的方法:
class Foo
def resource(comment)
@resource ||= {}
@resource[comment.id]
end
end
就我个人而言,在您的方法中使用 comment.id
似乎不太好。因为如果有一天您想使用不同的属性(或其他属性)作为 key
?
所以,我想我会这样做:
class Foo
%w(
resource
voters
is_upvoted
).each do |attr_sym|
define_method attr_sym do |key|
instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
instance_variable_get("@#{attr_sym}")[key]
end
end
end
现在,您似乎想要一种在实例变量上设置键值对的简单方法,所以我想我会尝试类似的方法:
class Foo
%w(
resource
voters
is_upvoted
).each do |attr_sym|
define_method attr_sym do |key=nil|
instance_variable_set("@#{attr_sym}", {}) unless instance_variable_get("@#{attr_sym}")
hsh = instance_variable_get("@#{attr_sym}")
return hsh[key] if key
hsh
end
end
end
在这种情况下你应该能够做到(假设你有一个响应 id
的 @comment
变量):
@comment.id
=> 1
foo = Foo.new
=> #<Foo:0x000056536d7504b0>
foo.resource
=> {}
foo.resource[@comment.id] = :bar
=> :bar
foo.resource
=> {1=>:bar}
foo.resource[@comment.id]
=> :bar
我就是这样使用它的,而且效果很好
['resource', 'voters', 'is_upvoted'].each do |attribute|
define_method("#{attribute}") do |comment|
instance_variable_get("@#{attribute}")[comment.id]
end
end