mirror of
https://github.com/rails/execjs
synced 2023-03-27 23:21:20 -04:00
Context
This commit is contained in:
parent
763513d9b1
commit
82773bfbde
6 changed files with 189 additions and 104 deletions
|
@ -18,6 +18,10 @@ module ExecJS
|
||||||
runtime.eval(source)
|
runtime.eval(source)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.compile(source)
|
||||||
|
runtime.compile(source)
|
||||||
|
end
|
||||||
|
|
||||||
def self.runtimes
|
def self.runtimes
|
||||||
Runtimes.runtimes
|
Runtimes.runtimes
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,56 @@ require "tempfile"
|
||||||
|
|
||||||
module ExecJS
|
module ExecJS
|
||||||
class ExternalRuntime
|
class ExternalRuntime
|
||||||
|
class Context
|
||||||
|
def initialize(runtime)
|
||||||
|
@runtime = runtime
|
||||||
|
@script = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def eval(source)
|
||||||
|
if /\S/ =~ source
|
||||||
|
exec("return eval(#{"(#{source})".to_json})")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exec(source)
|
||||||
|
@script << source
|
||||||
|
@script << "\n"
|
||||||
|
|
||||||
|
compile_to_tempfile(@script) do |file|
|
||||||
|
extract_result(@runtime.exec_runtime(file.path))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
def compile_to_tempfile(source)
|
||||||
|
tempfile = Tempfile.open("execjs")
|
||||||
|
tempfile.write compile(source)
|
||||||
|
tempfile.close
|
||||||
|
yield tempfile
|
||||||
|
ensure
|
||||||
|
tempfile.close!
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile(source)
|
||||||
|
@runtime.runner_source.dup.tap do |output|
|
||||||
|
output.sub!('#{source}', source)
|
||||||
|
output.sub!('#{json2_source}') do
|
||||||
|
IO.read(ExecJS.root + "/support/json2.js")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_result(output)
|
||||||
|
status, value = output.empty? ? [] : JSON.parse(output)
|
||||||
|
if status == "ok"
|
||||||
|
value
|
||||||
|
else
|
||||||
|
raise ProgramError, value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
attr_reader :name
|
attr_reader :name
|
||||||
|
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
|
@ -15,22 +65,39 @@ module ExecJS
|
||||||
@binary = locate_binary
|
@binary = locate_binary
|
||||||
end
|
end
|
||||||
|
|
||||||
def eval(source)
|
def exec(source)
|
||||||
if /\S/ =~ source
|
context = Context.new(self)
|
||||||
exec("return eval(#{"(#{source})".to_json})")
|
context.exec(source)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def exec(source)
|
def eval(source)
|
||||||
compile_to_tempfile(source) do |file|
|
context = Context.new(self)
|
||||||
extract_result(exec_runtime(file.path))
|
context.eval(source)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def compile(source)
|
||||||
|
context = Context.new(self)
|
||||||
|
context.exec(source)
|
||||||
|
context
|
||||||
end
|
end
|
||||||
|
|
||||||
def available?
|
def available?
|
||||||
@binary ? true : false
|
@binary ? true : false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def runner_source
|
||||||
|
@runner_source ||= IO.read(@runner_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exec_runtime(filename)
|
||||||
|
output = sh("#{@binary} #{filename} 2>&1")
|
||||||
|
if $?.success?
|
||||||
|
output
|
||||||
|
else
|
||||||
|
raise RuntimeError, output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
def locate_binary
|
def locate_binary
|
||||||
if binary = which(@command)
|
if binary = which(@command)
|
||||||
|
@ -55,37 +122,6 @@ module ExecJS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile(source)
|
|
||||||
runner_source.dup.tap do |output|
|
|
||||||
output.sub!('#{source}', source)
|
|
||||||
output.sub!('#{json2_source}') do
|
|
||||||
IO.read(ExecJS.root + "/support/json2.js")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def runner_source
|
|
||||||
@runner_source ||= IO.read(@runner_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def compile_to_tempfile(source)
|
|
||||||
tempfile = Tempfile.open("execjs")
|
|
||||||
tempfile.write compile(source)
|
|
||||||
tempfile.close
|
|
||||||
yield tempfile
|
|
||||||
ensure
|
|
||||||
tempfile.close!
|
|
||||||
end
|
|
||||||
|
|
||||||
def exec_runtime(filename)
|
|
||||||
output = sh("#{@binary} #{filename} 2>&1")
|
|
||||||
if $?.success?
|
|
||||||
output
|
|
||||||
else
|
|
||||||
raise RuntimeError, output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if "".respond_to?(:force_encoding)
|
if "".respond_to?(:force_encoding)
|
||||||
def sh(command)
|
def sh(command)
|
||||||
output, options = nil, {}
|
output, options = nil, {}
|
||||||
|
@ -108,14 +144,5 @@ module ExecJS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract_result(output)
|
|
||||||
status, value = output.empty? ? [] : JSON.parse(output)
|
|
||||||
if status == "ok"
|
|
||||||
value
|
|
||||||
else
|
|
||||||
raise ProgramError, value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,26 +1,63 @@
|
||||||
module ExecJS
|
module ExecJS
|
||||||
class RubyRacerRuntime
|
class RubyRacerRuntime
|
||||||
|
class Context
|
||||||
|
def initialize
|
||||||
|
@v8_context = ::V8::Context.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def exec(source)
|
||||||
|
if /\S/ =~ source
|
||||||
|
eval "(function(){#{source}})()"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def eval(source)
|
||||||
|
if /\S/ =~ source
|
||||||
|
unbox @v8_context.eval("(#{source})")
|
||||||
|
end
|
||||||
|
rescue ::V8::JSError => e
|
||||||
|
if e.value["name"] == "SyntaxError"
|
||||||
|
raise RuntimeError, e
|
||||||
|
else
|
||||||
|
raise ProgramError, e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def unbox(value)
|
||||||
|
case value
|
||||||
|
when ::V8::Function
|
||||||
|
nil
|
||||||
|
when ::V8::Array
|
||||||
|
value.map { |v| unbox(v) }
|
||||||
|
when ::V8::Object
|
||||||
|
value.inject({}) do |vs, (k, v)|
|
||||||
|
vs[k] = unbox(v) unless v.is_a?(::V8::Function)
|
||||||
|
vs
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def name
|
def name
|
||||||
"therubyracer (V8)"
|
"therubyracer (V8)"
|
||||||
end
|
end
|
||||||
|
|
||||||
def exec(source)
|
def exec(source)
|
||||||
if /\S/ =~ source
|
context = Context.new
|
||||||
eval "(function(){#{source}})()"
|
context.exec(source)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def eval(source)
|
def eval(source)
|
||||||
if /\S/ =~ source
|
context = Context.new
|
||||||
context = ::V8::Context.new
|
context.eval(source)
|
||||||
unbox context.eval("(#{source})")
|
end
|
||||||
end
|
|
||||||
rescue ::V8::JSError => e
|
def compile(source)
|
||||||
if e.value["name"] == "SyntaxError"
|
context = Context.new
|
||||||
raise RuntimeError, e
|
context.exec(source)
|
||||||
else
|
context
|
||||||
raise ProgramError, e
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def available?
|
def available?
|
||||||
|
@ -29,21 +66,5 @@ module ExecJS
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def unbox(value)
|
|
||||||
case value
|
|
||||||
when ::V8::Function
|
|
||||||
nil
|
|
||||||
when ::V8::Array
|
|
||||||
value.map { |v| unbox(v) }
|
|
||||||
when ::V8::Object
|
|
||||||
value.inject({}) do |vs, (k, v)|
|
|
||||||
vs[k] = unbox(v) unless v.is_a?(::V8::Function)
|
|
||||||
vs
|
|
||||||
end
|
|
||||||
else
|
|
||||||
value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,26 +1,61 @@
|
||||||
module ExecJS
|
module ExecJS
|
||||||
class RubyRhinoRuntime
|
class RubyRhinoRuntime
|
||||||
|
class Context
|
||||||
|
def initialize
|
||||||
|
@rhino_context = ::Rhino::Context.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def exec(source)
|
||||||
|
if /\S/ =~ source
|
||||||
|
eval "(function(){#{source}})()"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def eval(source)
|
||||||
|
if /\S/ =~ source
|
||||||
|
unbox @rhino_context.eval("(#{source})")
|
||||||
|
end
|
||||||
|
rescue ::Rhino::JavascriptError => e
|
||||||
|
if e.message == "syntax error"
|
||||||
|
raise RuntimeError, e
|
||||||
|
else
|
||||||
|
raise ProgramError, e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def unbox(value)
|
||||||
|
case value
|
||||||
|
when ::Rhino::NativeFunction
|
||||||
|
nil
|
||||||
|
when ::Rhino::NativeObject
|
||||||
|
value.inject({}) do |vs, (k, v)|
|
||||||
|
vs[k] = unbox(v) unless v.is_a?(::Rhino::NativeFunction)
|
||||||
|
vs
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def name
|
def name
|
||||||
"therubyrhino (Rhino)"
|
"therubyrhino (Rhino)"
|
||||||
end
|
end
|
||||||
|
|
||||||
def exec(source)
|
def exec(source)
|
||||||
if /\S/ =~ source
|
context = Context.new
|
||||||
eval "(function(){#{source}})()"
|
context.exec(source)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def eval(source)
|
def eval(source)
|
||||||
if /\S/ =~ source
|
context = Context.new
|
||||||
context = ::Rhino::Context.new
|
context.eval(source)
|
||||||
unbox context.eval("(#{source})")
|
end
|
||||||
end
|
|
||||||
rescue ::Rhino::JavascriptError => e
|
def compile(source)
|
||||||
if e.message == "syntax error"
|
context = Context.new
|
||||||
raise RuntimeError, e
|
context.exec(source)
|
||||||
else
|
context
|
||||||
raise ProgramError, e
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def available?
|
def available?
|
||||||
|
@ -29,19 +64,5 @@ module ExecJS
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def unbox(value)
|
|
||||||
case value
|
|
||||||
when ::Rhino::NativeFunction
|
|
||||||
nil
|
|
||||||
when ::Rhino::NativeObject
|
|
||||||
value.inject({}) do |vs, (k, v)|
|
|
||||||
vs[k] = unbox(v) unless v.is_a?(::Rhino::NativeFunction)
|
|
||||||
vs
|
|
||||||
end
|
|
||||||
else
|
|
||||||
value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,4 +17,10 @@ class TestExecJS < Test::Unit::TestCase
|
||||||
runtime = ExecJS::ExternalRuntime.new(:command => "ruby")
|
runtime = ExecJS::ExternalRuntime.new(:command => "ruby")
|
||||||
assert runtime.available?
|
assert runtime.available?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_compile
|
||||||
|
context = ExecJS.compile("foo = function() { return \"bar\"; }")
|
||||||
|
assert_equal "bar", context.exec("return foo()")
|
||||||
|
assert_equal "bar", context.eval("foo()")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,6 +29,12 @@ module TestRuntime
|
||||||
assert_equal "café", @runtime.eval("'café'")
|
assert_equal "café", @runtime.eval("'café'")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_compile
|
||||||
|
context = @runtime.compile("foo = function() { return \"bar\"; }")
|
||||||
|
assert_equal "bar", context.exec("return foo()")
|
||||||
|
assert_equal "bar", context.eval("foo()")
|
||||||
|
end
|
||||||
|
|
||||||
def test_this_is_global_scope
|
def test_this_is_global_scope
|
||||||
assert_equal true, @runtime.eval("this === (function() {return this})()")
|
assert_equal true, @runtime.eval("this === (function() {return this})()")
|
||||||
assert_equal true, @runtime.exec("return this === (function() {return this})()")
|
assert_equal true, @runtime.exec("return this === (function() {return this})()")
|
||||||
|
|
Loading…
Reference in a new issue