public
Last active

Ruby Enumerable each_with_position (provides #first? #last? #prev #next ...)

  • Download Gist
each_with_position.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
##################################
### SCROLL DOWN FOR AN EXAMPLE ###
##################################
 
module Enumerable
# your each_with_position method
def each_pos &block
EachWithPosition.each(self, &block)
end
end
 
class EachWithPosition
attr_reader :index
 
class << self
def each *a, &b
handler = self.new(*a, :each, &b)
end
end
 
def initialize collection, method, &block
@index = 0
@item, @prev, @next = nil
@collection = collection
@callback = block
self.send(method)
end
 
def count
@collection.count
end
alias_method :length, :count
alias_method :size, :count
 
def rest
count - position
end
 
def first?
@index == 0
end
 
def last?
@index == (count - 1)
end
 
def wrapped?
!first? && !last?
end
alias_method :inner?, :wrapped?
 
def position
@index + 1
end
 
def prev
@prev
end
 
def next
@next
end
 
def current
@item
end
alias_method :item, :current
alias_method :value, :current
 
def call
if @callback.arity == 1
@callback.call(self)
else
@callback.call(@item, self)
end
end
 
def each
@collection.each_cons(2) do |e, n|
@prev = @item
@item = e
@next = n
 
self.call
@index += 1
 
# fix cons slice behaviour
if last?
@prev, @item, @next = @item, @next, nil
self.call
@index += 1
end
end
end
end
 
 
 
 
 
 
("a".."m").to_a.each_pos do |e|
puts "Char\tfirst?\tlast?\tprev\tnext\twrapped?\tindex\tposition" if e.first?
print "#{e.item}\t"
print "#{e.first?}\t"
print "#{e.last?}\t"
print "#{e.prev}\t"
print "#{e.next}\t"
print "#{e.wrapped?}\t\t"
print "#{e.index}\t"
puts "#{e.position}\t"
end
 
# Char first? last? prev next wrapped? index position
# a true false b false 0 1
# b false false a c true 1 2
# c false false b d true 2 3
# d false false c e true 3 4
# e false false d f true 4 5
# f false false e g true 5 6
# g false false f h true 6 7
# h false false g i true 7 8
# i false false h j true 8 9
# j false false i k true 9 10
# k false false j l true 10 11
# l false false k m true 11 12
# m false true l false 12 13
 
 
 
{}.tap {|h| ("a".."m").each_with_index {|c, i| h[c] = i}}.each_pos do |(k, v), e|
puts "KV\tChar\t\tfirst?\tlast?\tprev\t\tnext\t\twrapped?\tindex\tposition" if e.first?
print "#{k} => #{v}\t"
print "#{e.item}\t"
print "#{e.first?}\t"
print "#{e.last?}\t"
print "#{e.prev || "\t"}\t"
print "#{e.next || "\t"}\t"
print "#{e.wrapped?}\t\t"
print "#{e.index}\t"
puts "#{e.position}\t"
end
 
# KV Char first? last? prev next wrapped? index position
# a => 0 [:a, "0"] true false [:b, "1"] false 0 1
# b => 1 [:b, "1"] false false [:a, "0"] [:c, "2"] true 1 2
# c => 2 [:c, "2"] false false [:b, "1"] [:d, "3"] true 2 3
# d => 3 [:d, "3"] false false [:c, "2"] [:e, "4"] true 3 4
# e => 4 [:e, "4"] false false [:d, "3"] [:f, "5"] true 4 5
# f => 5 [:f, "5"] false false [:e, "4"] [:g, "6"] true 5 6
# g => 6 [:g, "6"] false false [:f, "5"] [:h, "7"] true 6 7
# h => 7 [:h, "7"] false false [:g, "6"] [:i, "8"] true 7 8
# i => 8 [:i, "8"] false false [:h, "7"] [:j, "9"] true 8 9
# j => 9 [:j, "9"] false false [:i, "8"] [:k, "10"] true 9 10
# k => 10 [:k, "10"] false false [:j, "9"] [:l, "11"] true 10 11
# l => 11 [:l, "11"] false false [:k, "10"] [:m, "12"] true 11 12
# m => 12 [:m, "12"] false true [:l, "11"] false 12 13

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.