On Sep 25, 2007, at 2:21 PM, Luke Pearce wrote:

> Hi,
>
> Really need a little help understanding how to implement Enumerable -
> maybe I'm thinking about this the wrong way - what I'd like to do is:
>
> sm = ScoreMatrix.new
> sm.keywords << Keyword.new(1)
> sm.keywords << Keyword.new(2)
> sm.keywords.sum #=> returns 3
>
> I currently have:
>
> class ScoreMatrix
>   def initialize
>     @keywords = [] # <= what do I put here?
>   end
>
>   def keywords
>     @keywords
>   end
> end
>
> class Keyword
>   include Enumerable
>
>   attr_accessor :hits
>
>   def initialize(hits)
>     @hits = hits
>     @array = []
>   end
>
>   def sum
>     total = 0
>     @array.each do |item|
>       total += item.hits
>     end
>     total
>   end
>
>   def each
>     @array.each do |item|
>       yield item
>     end
>     self
>   end
>
>   def add(item)
>     @array.push(item)
>     self
>   end
>   alias :<< :add
> end
>
> Am I on the right track or way off? :0)

It looks to me that you are confusing a Class with an array of  
objects of that class. It's hard for me to see what you are trying to  
accomplish, but to the best of my understanding, all you need is  
following:

<code>
class ScoreMatrix
    attr_reader :keywords
    def initialize
       @keywords = []
    end
    def sum
       @keywords.inject(0) { |s, keywd| s += keywd.hits }
    end
end

class Keyword
    attr_reader :hits
   def initialize(hits)
       @hits = hits
    end
end

sm = ScoreMatrix.new
sm.keywords << Keyword.new(1)
sm.keywords << Keyword.new(2)
sm.sum # => 3
</code>

I can't see that you need to include Enumerable in the Keyword class.  
You aren't treating Keyword objects as collections, you are just  
iterating over an array of Keywords. Array already includes Enumerable.

Perhaps what you really want is for ScoreMatrix objects to behave as  
if _they_ were an array of Keyword hits. If that's the case, then you  
want something like:

<code>
class ScoreMatrix
    include Enumerable
    attr_reader :keywords
    def initialize
       @keywords = []
    end
    def each
       @keywords.each { |keywd| yield keywd.hits }
    end
    def sum
       inject(0) { |s, h| s += h }
    end
end

class Keyword
    attr_reader :hits
   def initialize(hits)
       @hits = hits
    end
end

sm = ScoreMatrix.new
sm.keywords << Keyword.new(1)
sm.keywords << Keyword.new(2)
sm.sum # => 3
</code>

Regards, Morton