Capistrano:require_relative不能按预期工作

时间:2012-11-28 19:15:38

标签: ruby capistrano

假设以下Rails设置:

  • Rails 3.2.9
  • Capistrano 2.13.5
  • 使用多级扩展(即capistrano / ext / multistage)
  • 定义的生产阶段,例如在Rails.root/config/deploy/production.rb

在production.rb中,你不能使用require_relative,看起来 - 你最终得到'无法推断的基道'错误。但是,如果您只是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;
}

1 个答案:

答案 0 :(得分:1)

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

  

需要一个库,其路径相对于包含该文件的文件   呼叫。因此,如果目录/ usr / local / mylib / bin包含该文件   myprog.rb和该程序包含以下行:   require_relative“../ lib / mylib”然后Ruby会查找mylib   的/ usr /本地/ MYLIB / lib中。

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

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'

所以它将在a/b/c/d2/e/f2中进行搜索,因为该调用位于a/b/c/d2/e/f1/test_req_rel.rb和。{ '../f2/req1'表示从f1返回e,然后转发f2,其中req1.rb必须存在,否则您会收到错误“无此文件要加载 - / a / b / c / c / d / e(LoadError)“

(使用Ruby 1.9.2测试)