How do I add 'each' method to Ruby object (or should I extend Array)?

前端 未结 7 1552
抹茶落季
抹茶落季 2021-01-30 04:00

I have an object Results that contains an array of result objects along with some cached statistics about the objects in the array. I\'d like the Results object to

7条回答
  •  星月不相逢
    2021-01-30 04:52

    Your << method is perfectly fine and very Ruby like.

    To make a class act like an array, without actually inheriting directly from Array, you can mix-in the Enumerable module and add a few methods.

    Here's an example (including Chuck's excellent suggestion to use Forwardable):

    # You have to require forwardable to use it
    require "forwardable"
    
    class MyArray
      include Enumerable
      extend Forwardable
    
      def initialize
        @values = []
      end
    
      # Map some of the common array methods to our internal array
      def_delegators :@values, :<<, :[], :[]=, :last
    
      # I want a custom method "add" available for adding values to our internal array
      def_delegator :@values, :<<, :add
    
      # You don't need to specify the block variable, yield knows to use a block if passed one
      def each
        # "each" is the base method called by all the iterators so you only have to define it
        @values.each  do |value| 
          # change or manipulate the values in your value array inside this block
          yield value
        end
      end
    
    end
    
    m = MyArray.new
    
    m << "fudge"
    m << "icecream"
    m.add("cake")
    
    # Notice I didn't create an each_with_index method but since 
    # I included Enumerable it knows how and uses the proper data.
    m.each_with_index{|value, index| puts "m[#{index}] = #{value}"}
    
    puts "What about some nice cabbage?"
    m[0] = "cabbage"
    puts "m[0] = #{m[0]}"
    
    puts "No! I meant in addition to fudge"
    m[0] = "fudge"
    m << "cabbage"
    puts "m.first = #{m.first}"
    puts "m.last = #{m.last}"
    

    Which outputs:

    m[0] = fudge
    m[1] = icecream
    m[2] = cake
    What about some nice cabbage?
    m[0] = cabbage
    No! I meant in addition to fudge
    m.first = fudge
    m.last = cabbage
    

提交回复
热议问题