class IterableContainer
CONT = ['a','b','c','d'],[1,2,3,4],['x','y','z']
# or CONT = ['a','b','c','d']
@i = 0
def self.get_next
result = CONT[@i]
@i += 1
if @i > CONT.length
@i = 1
return CONT[0]
end
return result
end
def self.has_next?
return @i != CONT.length
end
end
Refactorings
No refactoring yet !
lordzoner.myopenid.com
August 6, 2009, August 06, 2009 17:59, permalink
Iteration in Ruby is much different than in Java or C.
class IterableContainer
def initialize
@contents = ['a','b','c','d']
end
def each
for i in 0..@contents.length
yield @contents[i]
end
end
end
# Then you could call:
ic = IterableContainer.new
ic.each {|o| puts o }
# Which would print:
# 1
# 2
# 3
# 4
lordzoner.myopenid.com
August 6, 2009, August 06, 2009 18:01, permalink
I meant "a b c d", but you get it.
Muke Tever
August 7, 2009, August 07, 2009 05:52, permalink
It seems kind of like reinventing the wheel, anyway.
P.S. I love the 'edit' button a bit too much.
# It looks like you're trying to set up for something like this: while (yourcontainer.has_next?) do item = yourcontainer.get_next # do stuff with item here end
# If that's the case, you don't need an IterableContainer class. # The functionality is built-in with arrays, and looks like this: yourarray.each do |item| # do stuff with item here end # If having access to the index is necessary, you can do that too: yourarray.each_with_index do |item, index| # do stuff with item and index here end
bruno antunes
August 7, 2009, August 07, 2009 08:39, permalink
The thing is: in my rudimentary plug-in system, I want the plug-ins to be able to access data structures from the "main" program, and do it in a generic way. By "hiding" it in a different class, I can iterate them. But yes - "each" seems like the best way to do it. Thanks, lordzoner!
Craig Ludington
August 8, 2009, August 08, 2009 18:39, permalink
I like the each version but it seems that the idea of a circular buffer got left behind.
This might be less idiomatic, but it maintains the circular buffer semantics of the original.
# Implement a constant circular buffer.
class CircularBuffer
BUFFER = [:north, :east, :south, :west] unless defined? BUFFER
STOP = BUFFER.length - 1 unless defined? STOP
@@i = -1 # current offset is always incremented before use
# Return true if the current value is at the end
# of the buffer, false otherwise.
def self.at_end?
@@i == STOP
end
# Return the value of the buffer at the current offset,
# cycling around to the beginning if the end of the buffer
# is reached.
def self.current
return BUFFER[ @@i ] if (at_end? and @@i = 0) or (@@i = @@i + 1)
end
end
raise "at_end? was true the first time it was called" if CircularBuffer.at_end?
raise "current wasn't :north the first time it was called" unless CircularBuffer.current == :north
raise "current wasn't :east the second time it was called" unless CircularBuffer.current == :east
raise "current wasn't :south the third time it was called" unless CircularBuffer.current == :south
raise "current wasn't :west the fourth time it was called" unless CircularBuffer.current == :west
raise "at_end? was false when curent was :west" unless CircularBuffer.at_end?
raise "current wasn't :north the fifth time it was called" unless CircularBuffer.current == :north
ReinH
September 9, 2009, September 09, 2009 18:11, permalink
I'm not sure that this can be significantly refactored. Ruby doesn't have a circular linked list class. #each is not equivalent in behavior. Here's the only thing I can see to refator:
def self.get_next @i += 1 @i = 0 if @i >= CONT.length # fix bug where @i == CONT.length CONT[@i] end
I'm afraid I'm still thinking in "C" terms... :|