如何使用自定义对象包装Ruby数组,但是支持与数组相同的方法?

时间:2015-08-06 16:42:08

标签: ruby

我正在创建一个像数组一样的对象,但在将项添加到数组之前需要进行一些数据初始化。

class People
  def initialize(data_array)
    @people_array = data_array.map {|data| Person.new(data) }
  end

  def <<(data)
    @people_array << Person.new(data)
  end

  # def map(&block) ...
  # def each(&block) ...
  # etc...
end

我想支持数组支持的所有相同方法并委托给那些方法,这样我就不必重写所有这些方法。实现这一目标的最简单/最简洁的方法是什么?

3 个答案:

答案 0 :(得分:2)

也许继承Array类是一个很好的解决方案:

class People < Array
  def initialize(data_array)
    super(data_array.map {|data| Person.new(data) })
  end

  def <<(item)
    super(Person.new(item))
  end
end

然而,它有一些缺点,如评论和axel的答案所述。

另一种解决方案是组合和混合:

class People
  include Enumerable

  def initialize(data_array)
    @collection = data_array.map {|data| Person.new(data) }
  end

  def each(&block)
    @collection.each(&block)
  end

  def <<(data)
    @collection << Person.new(data)
  end
end

但是,此解决方案仅为您提供Enumerable模块以及<<运算符提供的方法。

要查看Array本身定义的方法,请轻松执行:

(Array.instance_methods - (Enumerable.instance_methods + Object.instance_methods)).sort
 => [:&, :*, :+, :-, :<<, :[], :[]=, :assoc, :at, :bsearch, :clear, :collect!,
 :combination, :compact, :compact!, :concat, :delete, :delete_at, :delete_if, :each,
 :each_index, :empty?, :fetch, :fill, :flatten, :flatten!, :index, :insert, :join,
 :keep_if, :last, :length, :map!, :pack, :permutation, :pop, :product, :push, :rassoc,
 :reject!, :repeated_combination, :repeated_permutation, :replace, :reverse, :reverse!,
 :rindex, :rotate, :rotate!, :sample, :select!, :shift, :shuffle, :shuffle!, :size, :slice,
 :slice!, :sort!, :sort_by!, :to_ary, :transpose, :uniq, :uniq!, :unshift, :values_at, :|]

但是,我认为这是一个肮脏的解决方案,并鼓励使用alex's answer

答案 1 :(得分:1)

您可以使用Delegator作为

class SimpleDelegator < Delegator
  def initialize(obj)
    super                  # pass obj to Delegator constructor, required
    @delegate_sd_obj = obj # store obj for future use
  end
end

我会劝阻extending Array

答案 2 :(得分:1)

当然,你总是可以篡改它

 class People
      def model
        @arr ||= []
      end

      def method_missing(method_sym, *arguments, &block)
        define_method method_sym do |*arguments|
          model.send method_sym, *arguments
        end
        send(method_sym, *arguments, &block)      
      end

      #probably should implement respond_to? here
end

我更喜欢这种方法,因为你不会混淆对阵Array和扩展Array的实现。您可以构建自定义匹配器,以仅实现特定的数组方法,例如可用于People类的方法。