1
0
Fork 0
mirror of https://github.com/rails/execjs synced 2023-03-27 23:21:20 -04:00
This commit is contained in:
Joshua Peek 2011-02-11 11:39:06 -06:00
parent 763513d9b1
commit 82773bfbde
6 changed files with 189 additions and 104 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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})()")