2007/10/29, Brian Adkins <lojicdotcom / gmail.com>:
> Very imaginative - thanks for the post :) It has a problem that will
> exclude it (below), but I always like to see different ways of
> thinking in Ruby. I don't see a possible solution without
> initialization outside the loop.
>
> 2.times do
>   2.times do |i|
>     SkipN.skip_first { puts "i is #{i}" }
>   end
>   puts '-'*10
> end
>
> Output:
>
> i is 1
> ----------
> i is 0
> i is 1
> ----------

Ah, but you didn't show us this use case yet, didn't you?

Not that I would use or recommend the following code, but
nethertheless here's a more powerful (albeit slower) version:

  module SkipN

    @skips = Hash.new(0)
    @min_levels = Hash.new(0)
    @level = 0

    @trace = lambda do |event, file, line, id, binding, classname|
      case event
      when "call", "c-call"
        @level += 1
      when "return", "c-return"
        @level -= 1
        @min_levels.each do |key, min|
          @min_levels[key] = @level if @level < min
        end
      end
    end

    def self.skip(n = 1, reset_levels = 1, key = caller.first)
      set_trace_func(nil)
      @level -= 1
      min = @min_levels[key]
      @skips[key] = 0 if min > 0 and @level - min > reset_levels
      yield if (@skips[key] += 1) > n
      @min_levels[key] = @level
      set_trace_func(@trace)
    end

    def self.skip_first(reset_levels = 1)
      skip(1, reset_levels + 1, caller.first) { yield }
    end

    set_trace_func(@trace)

  end

Usage:

  3.times do |i1|
    3.times do |i2|
      3.times do |i3|
        SkipN.skip_first(3) { puts "level 3, indexes #{i1}#{i2}#{i3}" }
        SkipN.skip_first(2) { puts "level 2, indexes #{i1}#{i2}#{i3}" }
        SkipN.skip_first(1) { puts "level 1, indexes #{i1}#{i2}#{i3}" }
      end
    end
  end

The level 3 code only skips the first iteration with indexes 000.
The level 2 code skips iterations with indexes *00.
The level 1 code skips iterations with indexes **0.

But specifying the "reset level" in the inner loop looks as too much
magic to me. It's much more readable if you explicitly reset the
counter at the appropriate places.

Regards,
Pit