开发者

How to use Dir.mktmpdir with a block in a hook with rspec?

开发者 https://www.devze.com 2023-03-25 07:07 出处:网络
I want to create a tmpdir in a before-each hook and use its path in an rspec example. I want to use the block form of Dir.mktmpdir so the dir is removed at the end of the example.

I want to create a tmpdir in a before-each hook and use its path in an rspec example. I want to use the block form of Dir.mktmpdir so the dir is removed at the end of the example.

Problems:

  • I can't let the block exit in the before hook, or the dir is removed before my example can run.
  • I can't wrap a block around my example. I tried using an around hook, but that doesn't share instance variables with examples (the doc confirms this behavior).

Currently I'm using continuations (Fibers would be better if I were on 1.9) to jump out of the block, then jump back in so mktmpdir can clean up.

Is there an easier way to accomplish this, without moving mktmpdir inside each example? It's true that I can remove the dir in the after-hook, but I'm also looking for a general solution to this type of problem - I don't always know what cleanup code is supposed to run when the block exits.

FYI, my continuation code, encapsulated into a class:

class SuspendableBlock
  def initialize
  end

  def run(&block)
    raise LocalJumpError unless block_given?
    callcc {|@run_cc|
      yield
      @resume_cc开发者_高级运维.call if @resume_cc
    }
    nil
  end

  # saves the suspend point & causes run to return immediately
  def suspend
    raise "run must be called first" unless @run_cc
    callcc {|@suspend_cc|
      @run_cc.call(@suspend_cc)
    }
    nil
  end

  # jumps back to after the suspend point to finish the block.
  # after the block exits, return immediately from resume.
  def resume
    raise "suspend must be called first" unless @suspend_cc
    callcc {|@resume_cc|
      @suspend_cc.call(@resume_cc)
    }
    nil
  end
end

Usage:

before :each do
  @sb = SuspendableBlock.new
  @sb.run do
    Dir.mktmpdir do |dir|
      @tmpdir_path = Pathname.new(dir)
      @sb.suspend
    end
  end
end

after :each do
  @sb.resume
end

it "should use a tmp dir" do
  p @tmpdir_path
end


From what I read (never tested it) continuations are really inefficient.

While I cannot help you on continuations you could use Thread to mimic Fibers: https://github.com/tmm1/fiber18.

One library which already does that is em-spec (https://github.com/tmm1/em-spec), with it each test is ran in a fiber you may be able to modify it to match your needs.

0

精彩评论

暂无评论...
验证码 换一张
取 消