With Statement (Redux)

My previous implementation of the with_statement in ruby had one major flaw: It allowed only a single context manager per with block. While effective, it leads to cluttered code, like the following:

with(open("hello.txt")){|f|
    with(open("bonjour.txt")){|g|
        puts f.read()
        puts g.read()
    }
}

Effective, but it isn't as clear as it could be and introduces more nesting than is really necessary. This coupled with my desire to explore varargs methods and blocks in ruby has lead me to a more robust implementation that can take an arbitrary number of managers as a parameter.

def with(*managers, &block)
    def with_(managers, resources, block)
        if managers.nitems > 0
            begin
                resource = managers.delete_at(0)
                resources << resource.enter()
                with_(managers, resources, block)
            ensure
                resource.exit()
            end
        else
            block.call(*resources)
        end
    end

    with_(managers, [], block)
end

The preceding implementation is more complex than the original. In addition to introducing "star magic"1, it relies on recursive creation of begin-ensure blocks which complicates exception handling; however, this implementation allows for such beautiful usage as:

with(open("hello.txt"), open("bonjour.txt")) {|f, g|
    puts f.read()
    puts g.read()
}

Should a manager's exit method raise an exception, that exception will supersede any exception raised within the block, though it will not interfere with exiting other managers.

An implementation and unittests are available in a Mercurial repository. The implementation can be retrieved as follows:

hg clone http://hg.crimzon.ath.cx/with_statement

Both the implementation and unittests are licensed under the MIT license.

[1]As it is called by pylint.