Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有人能帮我理解下面的Ruby代码段吗?_Ruby_List Comprehension - Fatal编程技术网

有人能帮我理解下面的Ruby代码段吗?

有人能帮我理解下面的Ruby代码段吗?,ruby,list-comprehension,Ruby,List Comprehension,我最近在Tomcat的JRuby上运行Sinatra时遇到了permgen内存泄漏。这个问题与Sinatra用来支持各种模板选项的Tilt库有关。旧代码(此处未包含)正在生成内存泄漏。新代码(如下)没有,事实上我看到permgen GC现在正在工作 Ruby应该是自描述的,但我无法通过阅读理解这段代码。有嵌套的类eval。为什么?为什么要定义一个方法然后取消绑定 为什么编译一堆模板并保留它们以供重用的代码看起来如此复杂 另外:如果有任何GitHub员工在看这个问题,您能否为GitHub添加一些功

我最近在Tomcat的JRuby上运行Sinatra时遇到了permgen内存泄漏。这个问题与Sinatra用来支持各种模板选项的Tilt库有关。旧代码(此处未包含)正在生成内存泄漏。新代码(如下)没有,事实上我看到permgen GC现在正在工作

Ruby应该是自描述的,但我无法通过阅读理解这段代码。有嵌套的类eval。为什么?为什么要定义一个方法然后取消绑定

为什么编译一堆模板并保留它们以供重用的代码看起来如此复杂

另外:如果有任何GitHub员工在看这个问题,您能否为GitHub添加一些功能,允许用户在代码段上插入问题

(此代码已从中删除)

def compile_template_方法(局部变量)
源,偏移量=预编译(本地)
偏移量+=5
方法_name=“uuu tilt_35;{Thread.current.object_id.abs}”

Object.class_eval以下是我在代码中的理解:

Object.class_eval将在当前范围外和全局范围内执行第一个块(eval_文件和行偏移量仅用于在发生错误时打印正确的行和文件名),然后将在虚拟容器中创建一个新方法(我假设这就是TOPOBJECT),一旦编译了该方法,它就被解除绑定并存储在其他地方

之后,该方法将附加到一个包含模板变量的新对象,并在其中运行,我不记得确切的语法,但这里是想法(其中方法是未绑定的方法):

至于代码的复杂性,我已经不得不编写类似的东西(不像上面所说的那样复杂),以使上面的api易于使用,这有时是代价^^

存在嵌套的类eval。为什么?

这种方法不像您合理预期的那样是优雅的自描述代码,它看起来像是来自于饱经风霜的、经过修复和修补的生产代码(因此,也许我们可以原谅他们一点)

那么为什么要进行两次评估呢?在可以计算第二个嵌套的“真实”模板方法代码之前,要计算的代码必须以正确的源代码作为前缀,该源代码可能已在模板文件中定义为“魔术注释”

一旦字符串编码设置正确,就可以尝试真正的类评估。另一种说法可能是“这是写源代码的源代码,写源代码的源代码”

据推测,这是为了解决Ruby 1.9中可能出现的兼容性问题,在Ruby 1.9中,正在编译的模板可能包含与Tilt库源代码本身的编码(US-ASCII编码)不同的字符编码(UTF-8),这将导致对模板字符串的错误计算(因为在调用模板文件的主机代码中已经设置了字符串编码)

为什么要定义一个方法,然后取消绑定?

澄清一下:在Ruby中,unbound与undefined不同

未绑定方法作为类型为UnboundMethod的可调用自由方法对象存在,尽管它们不再与特定对象关联。未绑定方法不再具有接收器

为了创建未绑定的方法,首先必须将其绑定到(针对)对象。这就是为什么编译的模板方法会从顶级对象中快速删除的原因,因为它只是生成未绑定方法所需的临时安排

此技术用于使用编译模板,这些模板的作用域针对给定类的不同实例,而无需以任何可见或永久的方式更改根对象或第三方开发人员的客户机类

通过解除编译模板方法与特定客户机代码对象的关联,编译模板方法可以在以后调用使用该类型对象的模板时反弹到该对象类的新实例

例如,给定以下ERB模板:

<p>Hello <%= @name %></p>
在后台,当调用
template.render(baq)
时,未绑定的编译模板方法将绑定到Person的“baq”实例:

__tilt_2151955260.bind(baq).call
不必每次都调用class_eval会带来可观的性能提升

为什么代码会编译一堆模板,并将它们保留一段时间 重复使用如此复杂的外观?

我的评估是,虽然代码实现乍一看确实显得不必要的复杂,但这些间接层在框架代码中通常是必要的,其目的是使公共API变得非常简单和甜美,以供成千上万的其他开发人员使用,即使这是以牺牲少数已开发人员的利益为代价的为了维持它

由于在许多不同地区使用的API以及来自世界各地的许多编码所产生的实际问题,代码复杂性(双重评估嵌套)也有所增加

脚注
问题中提到的模板类已被重构为一个单独的文件

AFAIK,未绑定的方法存储在
@compiled\u方法
中,该方法在
compiled\u方法
中完成(我没有看到任何其他调用
compile\u template\u method
。你确定链接指向了正确的位置吗?Scott,感谢你提供了这个全面而令人振奋的回答!后续观察:我注意到模板方法名是使用当前线程的对象id定义的。至少这使JRu中的事情具有线程安全性但会增加开销,因为相同的模板+局部变量将针对请求线程池中的线程数量进行计算。糟糕。再次感谢!哦,另一个后续问题:Woops!这里还有一个问题:哦,ano
<p>Hello <%= @name %></p>
scott = Person.new
scott.name = "Scott"
output = template.render(scott)
=> "<p>Hello Scott</p>"
baq = Person.new
baq.name = "Baq"
output = template.render(baq)
__tilt_2151955260.bind(baq).call