gem binding_of_caller
有一个如何在父范围中设置变量的示例:
(这只是从他们的自述文件粘贴)
def a
var = 10
b
puts var
end
def b
c
end
def c
binding.of_caller(2).eval('var = :hello')
end
a()
# OUTPUT
# => hello
这很有用,但它受到在字符串中进行所有变量初始化的需要的限制。
我稍微考了一下,意识到我可以使用YAML来序列化/反序列化对象。
例如,举例如下:
def c
value = YAML.dump [ { a: "b" } ]
binding.of_caller(2).eval("var = YAML.load('#{value}')")
end
a()
# => {a: "b"}
这很酷,但如果我完全避免序列化并且只是编写一个正确的do; end;
块,它会更好:
# doesnt work
def c
binding.of_caller(2).eval do
# ideally this would set the variable named "var" in the scope of method "a"
var = [ { a: "b" } ]
end
end
如何完成上一个示例的功能?如果有其他方式,我不需要使用binding_of_caller
。
答案 0 :(得分:4)
这是我能做的最好的,我怀疑(尽管我真的很想被证明是错的),最好的是你找不到自己的C扩展和la binding_of_caller:
eval("ObjectSpace._id2ref(%d).call(binding)" % block.object_id)
当然,魔法在这里:
Binding#eval
我们获取Proc的对象ID,然后在我们的binding
中使用ObjectSpace#_id2ref
从内存中的任何位置检索它并调用它,传入本地def a
var = 10
b
puts var
end
def b
c
end
def c
binding.of_caller(2).eval_block do |bnd|
bnd.local_variable_set(:var, [ { a: "b" } ])
end
end
a # => {:a=>"b"}
这是在行动:
var = [ { a: "b" } ]
正如您所看到的,我们必须执行bnd.local_variable_set(:var, [ { a: "b" } ])
而不是bnd
。没有办法在Ruby中更改块的绑定,因此我们必须传入绑定(class Program
{
static int SumaDivisors(int nombre)
{
int suma;
suma = 0;
for (int contador = 1; contador < nombre; contador++)
{
if (nombre % contador == 0)
{
suma = suma + contador;
}
}
return suma;
}
static void Main(string[] args)
{
Console.WriteLine("Busca els nombres amics entre 0 i 10000");
int numero, suma1, suma2;
for (numero = 1; numero < 10000; numero++)
{
suma1 = SumaDivisors(numero);
suma2 = SumaDivisors(suma1);
if (suma1 != numero && suma2 == numero)
{
Console.WriteLine("Els nombre {0} i {1} són nombres amics", suma1, suma2);
}
}
Console.ReadKey();
}
}
)并调用Binding#local_variable_set
。