【问题标题】:Ruby metaprogramming to achieve dynamic methods?Ruby 元编程实现动态方法?
【发布时间】:2020-03-01 21:31:10
【问题描述】:

想用元编程实现下面的代码。

@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

【问题讨论】:

    标签: ruby-on-rails ruby metaprogramming instance-variables


    【解决方案1】:

    这一点似乎是多余的:

    @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
    

    【讨论】:

      【解决方案2】:

      你能告诉我我的代码有什么问题吗?

      它的作用相当于:

      def resource(comment)
        @resource = comment.id
      end
      

      instance_variable_get 会是更好的选择。

      【讨论】:

      • 如何使用这个访问哈希?
      • NameError (`@resource[13739]' is not allowed as an instance variable name) 使用 instance_variable_get 后出现此错误
      • @vikas95prasad:当然,方括号和数字不是实例变量名的一部分,所以不要放在那里。
      • @mrzasa 这就是我使用它的方式,它的工作原理 instance_variable_get("@#{attribute}")[comment.id]
      【解决方案3】:

      这就是我使用它的方式,它的工作原理

      ['resource', 'voters', 'is_upvoted'].each do |attribute|
        define_method("#{attribute}") do |comment|
          instance_variable_get("@#{attribute}")[comment.id]
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-08
        • 2013-05-25
        • 1970-01-01
        • 2012-03-18
        • 2015-06-03
        • 1970-01-01
        相关资源
        最近更新 更多