在块内部设置块外的变量?

时间:2017-05-26 22:39:28

标签: ruby

我有以下代码:

def test_callback_interface
  with_temp_stdio do |stdin, stdout|
    stdin.write("hello\n")
    stdin.close
    stdout.flush
    line = nil

    replace_stdio(stdin.path, stdout.path) {
      Readline.handler_install("> ", true) { |l| line = l }
      6.times { Readline.read_char }
      Readline.handler_remove
    }

    assert_equal("hello", line)     <------ FAIL here
    assert_equal(true, line.tainted?)
    stdout.rewind
    assert_equal("> ", stdout.read(2))
    assert_equal(1, Readline::HISTORY.length)
    assert_equal("hello", Readline::HISTORY[0])
  end

  assert_equal(true, false)
end

它在assert_equal("hello", line)行上失败,说linenil。但是,我确信调用了回调(我通过将raise放在那里来验证它)。所以我必须在这里遗漏一些关于范围的基本信息。有人可以告诉我如何将l的值赋予line变量吗?

由于

编辑:

如何在handler_install / read_char中调用回调?

static VALUE readline_callback_ensure(VALUE val) {
    free(readline_callback_line);
    readline_callback_line = NULL;
    return Qnil;
}
static VALUE readline_callback_call(VALUE line) {
    VALUE proc = rb_attr_get(mReadline, read_char_cb_proc);
    rb_funcall(proc, id_call, 1, line);
    return Qnil;
}
static void readline_callback_callback(char * line) {
    if (readline_callback_add_history && line) {
        add_history(line);
    }
    readline_callback_line = line;
    rb_ensure(
        readline_callback_call, line ? rb_str_new_cstr(line) : Qnil,
        readline_callback_ensure, Qnil
    );
}
static VALUE readline_callback_handler_install(int argc, VALUE * argv, VALUE self) {
    VALUE tmp, add_hist, block;
    char * prompt = NULL;

    rb_need_block();

    if (rb_scan_args(argc, argv, "02&", &tmp, &add_hist, &block) > 0) {
        prompt = RSTRING_PTR(tmp);
    }

    if (RTEST(add_hist)) {
        readline_callback_add_history = true;
    } else {
        readline_callback_add_history = false;
    }

    rb_ivar_set(mReadline, read_char_cb_proc, block);

    rl_callback_handler_install(prompt, readline_callback_callback);

    return Qnil;
}

static VALUE readline_callback_read_char(VALUE self) {
    VALUE proc = rb_attr_get(mReadline, read_char_cb_proc);
    if (NIL_P(proc)) {
        rb_raise(rb_eRuntimeError, "No handler installed.");
    }
    rl_callback_read_char();
    return Qnil;
}

所以基本上read_char调用rl_callback_read_char(gnu readline函数),它在检测完整行时调用我安装的处理程序readline_callback_callback,它调用了用户提供的存储块。

1 个答案:

答案 0 :(得分:0)

解决,而不是范围问题。 GNU Readline在EOF上再次使用NULL调用我的代码,完全忘记了这一点。