如何使用 Dir.mktmpdir 与带有 rspec 的钩子中的块?
我想在 before
-each 挂钩中创建一个 tmpdir 并在 rspec 示例中使用其路径。我想使用 Dir.mktmpdir
的块形式,以便在示例末尾删除该目录。
问题:
- 我无法让块在
before
挂钩中退出,或者在我的示例运行之前删除目录。 - 我无法将我的示例包裹起来。我尝试使用
around
钩子,但它不与示例共享实例变量( doc 确认了此行为)。
目前,我正在使用延续(如果我在 1.9 上,纤维会更好)跳出块,然后跳回,以便 mktmpdir 可以清理。
有没有更简单的方法来完成此任务,而无需在每个示例中移动 mktmpdir
?确实,我可以删除 after
-hook 中的目录,但我也在寻找此类问题的通用解决方案 - 我并不总是知道应该运行什么清理代码当块退出时。
仅供参考,我的延续代码,封装到一个类中:
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
用法:
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
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从我读到的(从未测试过)来看,延续的效率确实很低。
虽然我无法帮助您继续,但您可以使用 Thread 来模仿 Fiber: https://github.com/tmm1/ Fiber18< /a>.
em-spec (https://github.com/tmm1/em-spec) 已经做到了这一点,它的每个测试都在光纤中运行,您可以对其进行修改以满足您的需求。
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.