假设以下 Rails 设置:
- 导轨 3.2.9
- 卡皮斯特拉诺 2.13.5
- 使用多级扩展(即 capistrano/ext/multistage)
- 定义的生产阶段,例如在
Rails.root/config/deploy/production.rb
.
在 production.rb 中,您似乎无法使用 require_relative — 您最终会收到“无法推断基本路径”错误。但是,如果您只是 plain ruby production.rb
,则 require_relative 可以正常工作。
为什么会这样?Capistrano 似乎以一种使 require_relative 无法按预期工作的方式加载/执行代码。
我怀疑这类似于:Passenger Rack app 'cannot infer basepath',这(粗略地说)表明 require_relative 可能会失败,具体取决于代码的最终加载/运行方式。
下面给出了分支 ruby_1_9_3 中 require_relative 的源代码,它显示了 require_relative 如何依赖于调用堆栈。然而,端到端的画面并不完整——Capistrano 如何查找和执行代码,以及它如何影响调用堆栈。
我不认为这里有什么是无法解决的,但是代替我自己深入研究这个问题的时间,任何关于正在发生的事情的专家见解都将不胜感激,不仅是为了具体问题,而且是为了洞察 Cap 和 Ruby工作。
// load.c
VALUE
rb_f_require_relative(VALUE obj, VALUE fname)
{
VALUE base = rb_current_realfilepath();
if (NIL_P(base)) {
rb_raise(rb_eLoadError, "cannot infer basepath");
}
base = rb_file_dirname(base);
return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
}
// vm_eval.c
VALUE
rb_current_realfilepath(void)
{
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *cfp = th->cfp;
cfp = vm_get_ruby_level_caller_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
if (cfp != 0) return cfp->iseq->filepath;
return Qnil;
}