Project

General

Profile

Feature #12093

Eval InstructionSequence with binding

Added by pavel.evstigneev (Pavel Evstigneev) over 3 years ago. Updated over 2 years ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:73901]

Description

Implementing this feature can boost template engine performance

Currently Kernel#eval can accept binding argument, so code running with eval will have access to local variables and current instance. This feature used by template languages

ERB: https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L887
Erubis: Can't find code on github, but it uses instance_eval or Kernel#eval
Haml: https://github.com/haml/haml/blob/master/lib/haml/engine.rb#L115

My proposal is to make RubyVM::InstructionSequence#eval to recieve binding argument. So it can be used for caching templates. As I see from ERB and Haml, cached template is stored as ruby code string, every time when we render template that string (ruby code) is evaluated, internally ruby will parse it into RubyVM::InstructionSequence and then evaluate.

Before I try to implement it myself in ruby, but could not. Lack of experience with C https://github.com/Paxa/ruby/commit/f5b602b6d9eada9675a4c002c9a5a79129df73a6 (not working)

History

Updated by nobu (Nobuyoshi Nakada) over 3 years ago

  • Project changed from CommonRuby to Ruby trunk

Updated by nobu (Nobuyoshi Nakada) over 3 years ago

Depending on the context, an identifier may be a local variable or a method call.
I think that RubyVM::InstructionSequence#compile would need the binding, instead of #eval.

Updated by shyouhei (Shyouhei Urabe) over 3 years ago

"ISeq#compile's need of binding" means a template engine cannot cache compiled ISeqs for later invocation, right? I doubt the benfit of compile's taking bindings.

Updated by nobu (Nobuyoshi Nakada) over 3 years ago

Do you mean same template with different contexts, a name is a variable one time, but a method call next time?
I doubt that it is a common use case.

Updated by nobu (Nobuyoshi Nakada) over 2 years ago

I discovered an old patch for this issue.
This enables the following code, but doesn't seem useful to me.

obj = Struct.new(:a, :b).new(1, 2)
bind = obj.instance_eval {binding}
RubyVM::InstructionSequence.compile("a + b").eval_with(bind) #=> 3

Also available in: Atom PDF