【问题标题】:Ruby: attr_accessor generated methods - how to iterate them (in to_s - custom format)?Ruby:attr_accessor 生成的方法 - 如何迭代它们(以 to_s - 自定义格式)?
【发布时间】:2010-01-07 12:24:17
【问题描述】:

我需要一个具有半自动“to_s”方法的类(实际上是生成 XML)。 我想遍历我的“attr_accessor”行中设置的所有自动方法:

class MyClass
    attr_accessor :id,:a,:b,:c
end

c=MyClass.new

到目前为止,我正在做一个基本的:

c.methods - Object.methods

=> ["b", "b=", "c", "c=", "id=", "a", "a="]

我面临一些挑战:

  1. 'id' 可能会引起轻微的头痛 - 因为 Object 似乎已经有了一个 'id'。
  2. 上面的 'c.methods' 调用返回字符串 - 我没有得到任何其他元数据? (在 Java 中,“方法”是一个对象,我可以在其中执行进一步的反射)。
  3. 我必须处理一对多的关系(“c”是其他对象类型的数组类型)。

这就是我想要做的:我想设计一个简单的对象,它有一个'to_s',它将构建一个 XML 片段:例如。

<id> 1 </id>
<a> Title </a>
<b> Stuff </b>
<c>
    <x-from-other-object>
    <x-from-other-object>
    ....
</c>

然后从那个简单的对象继承我的数据类:这样(希望)我得到一个机制来构建一个完整的 XML 文档。

我确定我也在重新发明轮子……所以欢迎使用其他久经考验的方法。

【问题讨论】:

    标签: xml ruby reflection


    【解决方案1】:

    要从字符串中获取方法对象,您可以使用方法methodinstance_method(其中method 将在对象上调用,instance_method 在类上调用)。不过,它提供给您的唯一有趣的信息是 arity(与 java 不同,它还提供返回值和参数的类型,这在 ruby​​ 中当然是不可能的)。

    您的标题表明您只想遍历 attr_accessor 创建的方法,但您的代码将遍历您的类中定义的每个方法,如果您想向您的类。

    要解决这个问题和 id 的问题,您可以使用自己的 attr_accessor 包装器来存储它为哪些变量创建了访问器,如下所示:

    module MyAccessor
      def my_attr_accessor *attrs
        @attrs ||= []
        @attrs << attrs
        attr_accessor *attrs
      end
    
      def attrs
        @attrs
      end
    end
    
    class MyClass
      extend MyAccessor
      my_attr_accessor :id,:a,:b,:c
    
      def to_s
        MyClass.attrs.each do |attr|
          do_something_with(attr, send(attr))
        end
      end
    end
    

    对于问题 3,你可以这样做

    if item.is_a? Array
      do_something
    else
      do_something_else
    end
    

    【讨论】:

    • 有趣的东西 - 需要通过这个才能投票!谢谢!
    • 这肯定有助于 +1 - 但这里的主要问题是,我确实确实想了解 attr_accessor 定义的东西。
    • 已经澄清了一些描述以表明这一点。
    • attr_accessor 不存储有关它在任何地方定义的方法的任何信息。因此,除非您使用存储此类信息的包装器,否则无法找出 attr_accessor 定义的方法或 attr_accessor 是否定义了特定方法。
    • 投票作为接受的答案 - 我的理解并不完全存在,但它看起来几乎可以回答我提出的问题。干杯
    【解决方案2】:

    我使用这种技术将自定义对象转换为 JSON。可能是下面的 sn-p 会有所帮助,因为问题是针对 to_xml 实现的。

    在模块中使用self.included 有一点魔力。这是 2006 年的一篇非常好的文章,关于具有实例和类方法的模块http://blog.jayfields.com/2006/12/ruby-instance-and-class-methods-from.html

    该模块旨在包含在任何类中以提供to_json 功能。它拦截attr_accessor 方法而不是使用自己的方法,以便对现有类进行最少的更改。

    to_json 的实现是基于这个answer

    module JSONable
      module ClassMethods
        attr_accessor :attributes
    
        def attr_accessor *attrs
          self.attributes = Array attrs
          super
        end
      end
    
      def self.included(base)
        base.extend(ClassMethods)
      end
    
      def as_json options = {}
        self.class.attributes.inject({}) do |hash, attribute|
          hash[attribute] = self.send(attribute)
          hash
        end
      end
    
      def to_json *a
        as_json.to_json *a
      end
    end
    
    
    class CustomClass
      include JSONable
      attr_accessor :b, :c 
    
      def initialize b: nil, c: nil
        self.b, self.c = b, c
      end
    end
    
    a = CustomClass.new(b: "q", c: 23)
    puts JSON.pretty_generate a
    
    {
      "b": "q",
      "c": 23
    }
    

    【讨论】:

      猜你喜欢
      • 2020-12-02
      • 1970-01-01
      • 2019-09-27
      • 2015-10-19
      • 1970-01-01
      • 2016-02-25
      • 1970-01-01
      • 1970-01-01
      • 2020-11-16
      相关资源
      最近更新 更多