4

假设以下 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;
}
4

1 回答 1

1

http://pragprog.com/book/ruby3/programming-ruby-1-9说:

需要一个路径相对于包含调用的文件的库。因此,如果目录 /usr/local/mylib/bin 包含文件 myprog.rb 并且该程序包含以下行: require_relative "../lib/mylib" 那么 Ruby 将在 /usr/local/mylib/ 中查找 mylib库。

如果我有这样的目录结构:

a/b/c/d1
a/b/c/d2
a/b/c/d2/e/f1
a/b/c/d2/e/f2

$ pwd
a/b/c/d1
$ ruby -w ../d2/e/f1/test_req_rel

文件a/b/c/d2/e/f1/test_req_rel.rb包含:

require_relative '../f2/req1'

所以它会搜索 in a/b/c/d2/e/f2,因为调用是 ina/b/c/d2/e/f1/test_req_rel.rb并且 '../f2/req1'意味着从f1to e,然后转发 in f2req1.rb必须存在的地方,否则你会得到错误“没有这样的文件要加载 - /a/b/c/c/d/ e (加载错误)"

(用 Ruby 1.9.2 测试)

于 2012-11-28T22:28:11.633 回答