【问题标题】:Wrapping Ruby global variables within a scope在范围内包装 Ruby 全局变量
【发布时间】:2012-12-21 06:33:44
【问题描述】:

我正在评估 Ruby 中的脚本,我希望每个脚本都有自己的沙箱,其中包含一个名为 $window 的全局变量。 $window 变量应该指向不同的东西,具体取决于脚本在哪个沙箱中运行。线程局部变量可以工作,但我没有使用线程。我正在使用 Ruby C API,因此有点打开了可能性。

现在,我在 Binding 中运行每个脚本,所以它们在那里有些沙盒。绑定可以有封闭的局部变量,但不能有全局变量。想法是这样的:

sandbox1 = window1.get_binding
sandbox2 = window2.get_binding
sandbox3 = window3.get_binding

sandbox1.eval('$window.foo') # calls 'foo' on window 1
sandbox2.eval('$window.foo') # calls 'foo' on window 2
sandbox3.eval('$window.foo') # calls 'foo' on window 3

有没有办法关闭Binding 中的全局变量?我找到了一个可能的解决方案并将其发布在下面。

【问题讨论】:

  • 好像是在担心多个线程的访问同步到一个全局?
  • 它们不在单独的线程中,尽管这样会很容易!它们是网络浏览器中的不同窗口。
  • 您要实现的基本目标是什么?全局变量通常被认为是一种不好的做法。
  • 我澄清了我的问题。我想拥有多个具有相同名称的全局变量的沙箱。
  • 为什么这被标记为javascriptwebkit

标签: ruby scope closures


【解决方案1】:

不同的窗口将绑定到什么?

如果它们绑定到一个线程,那么解决您的问题的最简单方法是拥有一个Thread local variable,如果绑定到其他东西(比如说当前时间),那么您可能想要使用全局哈希.

我个人会选择一个专用的类,这将使以后更容易重构(你可能会重构它,因为全局变量是不良依赖注入的代码味道):

class Windows < Hash
end
WINDOWS = Windows.new
...
window_scope = WINDOWS[Time.now].binding

那么你有一个可变常量,它实际上是一个全局集合。

【讨论】:

  • 遗憾的是,它们没有绑定到线程,但使用某种全局哈希可能会起作用。我将编辑主要帖子并进行一些澄清。
【解决方案2】:

我找到了使用 Ruby C API 的可能解决方案。在绑定中评估的任何内容都将位于该绑定的调用框架下。使用 Ruby 1.8.7,我可以在 C 中做到这一点:

public VALUE getCurrentWindow()
{
    // Get the current call frame from Ruby.
    FRAME* frame = ruby_frame;

    // Traverse up the call frame stack until we find a Window class.
    while (frame) {
        if (RTEST(rb_obj_is_kind_of(frame->self, rb_cWindow))
            return frame->self;

        frame = frame->prev;
    }

    // Couldn't find the window.
    return Qnil;
}

它似乎有效,但我们会看看我是否遇到问题。

【讨论】:

    猜你喜欢
    • 2016-11-13
    • 1970-01-01
    • 2017-03-05
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    • 2020-12-17
    • 2015-03-22
    • 1970-01-01
    相关资源
    最近更新 更多