From d8c5ac27511063fce394f3f77d788233a5422590 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 6 Dec 2014 12:25:40 -0800 Subject: [PATCH 01/23] Initial support for duktape --- Gemfile | 1 + lib/execjs/duktape_runtime.rb | 67 +++++++++++++++++++++++++++++++++++ lib/execjs/runtimes.rb | 4 +++ test/test_execjs.rb | 3 ++ 4 files changed, 75 insertions(+) create mode 100644 lib/execjs/duktape_runtime.rb diff --git a/Gemfile b/Gemfile index 0d13b86..7d8d4e5 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,7 @@ source 'https://rubygems.org' gemspec group :test do + gem 'duktape' gem 'therubyracer', platform: :mri gem 'therubyrhino', ">=1.73.3", platform: :jruby end diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb new file mode 100644 index 0000000..085f647 --- /dev/null +++ b/lib/execjs/duktape_runtime.rb @@ -0,0 +1,67 @@ +require "execjs/runtime" +require "json" + +module ExecJS + class DuktapeRuntime < Runtime + class Context < Runtime::Context + def initialize(runtime, source = "") + @ctx = Duktape::Context.new + + # Disable CJS + exec("module = exports = require = undefined") + exec(source) + end + + def exec(source, options = {}) + source = encode(source) + + js = <<-JS + (function(program, execJS) { return execJS(program); })(function() { #{source} + }, function(program) { + try { + return JSON.stringify(['ok', program()]); + } catch (err) { + return JSON.stringify(['err', '' + err]); + } + }); + JS + + if json = @ctx.eval_string(js, '(execjs)') + status, value = ::JSON.parse(json, create_additions: false) + if status == "ok" + value + elsif value =~ /SyntaxError:/ + raise RuntimeError, value + else + raise ProgramError, value + end + end + rescue Duktape::ContextError => e + raise RuntimeError, e.message + end + + def eval(source, options = {}) + source = encode(source) + + if /\S/ =~ source + exec("return eval(#{::JSON.generate("(#{source})", quirks_mode: true)})") + end + end + + def call(identifier, *args) + eval "#{identifier}.apply(this, #{::JSON.generate(args)})" + end + end + + def name + "Duktape" + end + + def available? + require "duktape" + true + rescue LoadError + false + end + end +end diff --git a/lib/execjs/runtimes.rb b/lib/execjs/runtimes.rb index 969e7a6..8730f5d 100644 --- a/lib/execjs/runtimes.rb +++ b/lib/execjs/runtimes.rb @@ -1,5 +1,6 @@ require "execjs/module" require "execjs/disabled_runtime" +require "execjs/duktape_runtime" require "execjs/external_runtime" require "execjs/johnson_runtime" require "execjs/mustang_runtime" @@ -10,6 +11,8 @@ module ExecJS module Runtimes Disabled = DisabledRuntime.new + Duktape = DuktapeRuntime.new + RubyRacer = RubyRacerRuntime.new RubyRhino = RubyRhinoRuntime.new @@ -78,6 +81,7 @@ module ExecJS @runtimes ||= [ RubyRacer, RubyRhino, + Duktape, Johnson, Mustang, Node, diff --git a/test/test_execjs.rb b/test/test_execjs.rb index 591caff..54eb085 100644 --- a/test/test_execjs.rb +++ b/test/test_execjs.rb @@ -171,6 +171,9 @@ class TestExecJS < Test end def test_coffeescript + # Skip coffeescript on Duktape for now + skip if ExecJS.runtime.is_a?(ExecJS::DuktapeRuntime) + assert source = File.read(File.expand_path("../fixtures/coffee-script.js", __FILE__)) context = ExecJS.compile(source) assert_equal 64, context.call("CoffeeScript.eval", "((x) -> x * x)(8)") From 1b96bbe8600a3ac9a2a60917cea85e2e3d2b0906 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 9 Dec 2014 14:44:17 -0800 Subject: [PATCH 02/23] Rescue SyntaxError --- lib/execjs/duktape_runtime.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index 085f647..ed2ad2b 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -36,7 +36,7 @@ module ExecJS raise ProgramError, value end end - rescue Duktape::ContextError => e + rescue Duktape::SyntaxError => e raise RuntimeError, e.message end From 6ed8f7724d5654e69284003f6cc3f9545444ab06 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 9 Dec 2014 14:44:56 -0800 Subject: [PATCH 03/23] CJS disabled by default --- lib/execjs/duktape_runtime.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index ed2ad2b..880e4a1 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -6,9 +6,6 @@ module ExecJS class Context < Runtime::Context def initialize(runtime, source = "") @ctx = Duktape::Context.new - - # Disable CJS - exec("module = exports = require = undefined") exec(source) end From cc1f21309424e5e7c61f91c38eb49df60799ce66 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 9 Dec 2014 14:48:47 -0800 Subject: [PATCH 04/23] Use native error handling --- lib/execjs/duktape_runtime.rb | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index 880e4a1..b7f9c45 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -13,28 +13,16 @@ module ExecJS source = encode(source) js = <<-JS - (function(program, execJS) { return execJS(program); })(function() { #{source} - }, function(program) { - try { - return JSON.stringify(['ok', program()]); - } catch (err) { - return JSON.stringify(['err', '' + err]); - } - }); + (function(program) { return JSON.stringify([program()]); })(function() { #{source} }); JS if json = @ctx.eval_string(js, '(execjs)') - status, value = ::JSON.parse(json, create_additions: false) - if status == "ok" - value - elsif value =~ /SyntaxError:/ - raise RuntimeError, value - else - raise ProgramError, value - end + ::JSON.parse(json, create_additions: false)[0] end rescue Duktape::SyntaxError => e raise RuntimeError, e.message + rescue Duktape::Error => e + raise ProgramError, e.message end def eval(source, options = {}) From a8a2d802690d104b5a5d2f27664ecbe98d3bdbf2 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 9 Dec 2014 14:52:07 -0800 Subject: [PATCH 05/23] Unwrap complex objects --- lib/execjs/duktape_runtime.rb | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index b7f9c45..4417cdb 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -11,20 +11,32 @@ module ExecJS def exec(source, options = {}) source = encode(source) - - js = <<-JS - (function(program) { return JSON.stringify([program()]); })(function() { #{source} }); - JS - - if json = @ctx.eval_string(js, '(execjs)') - ::JSON.parse(json, create_additions: false)[0] - end + unwrap(@ctx.eval_string("(function() { #{source} })();", '(execjs)')) rescue Duktape::SyntaxError => e raise RuntimeError, e.message rescue Duktape::Error => e raise ProgramError, e.message end + def unwrap(obj) + case obj + when ::Duktape::ComplexObject + nil + when Array + obj.map { |v| unwrap(v) } + when Hash + obj.inject({}) do |vs, (k, v)| + v = unwrap(v) + vs[k] = v if v + vs + end + when String + obj.force_encoding('UTF-8') + else + obj + end + end + def eval(source, options = {}) source = encode(source) From a3b32250ccdf3a8d8c5f59c0e468a3ad62f810e8 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 9 Dec 2014 14:56:43 -0800 Subject: [PATCH 06/23] Express exec in terms of eval --- lib/execjs/duktape_runtime.rb | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index 4417cdb..bae656c 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -10,14 +10,25 @@ module ExecJS end def exec(source, options = {}) + eval "(function(){#{source}})()" + end + + def eval(source, options = {}) source = encode(source) - unwrap(@ctx.eval_string("(function() { #{source} })();", '(execjs)')) + + if /\S/ =~ source + unwrap(@ctx.eval_string("(#{source})", '(execjs)')) + end rescue Duktape::SyntaxError => e raise RuntimeError, e.message rescue Duktape::Error => e raise ProgramError, e.message end + def call(identifier, *args) + eval "#{identifier}.apply(this, #{::JSON.generate(args)})" + end + def unwrap(obj) case obj when ::Duktape::ComplexObject @@ -36,18 +47,6 @@ module ExecJS obj end end - - def eval(source, options = {}) - source = encode(source) - - if /\S/ =~ source - exec("return eval(#{::JSON.generate("(#{source})", quirks_mode: true)})") - end - end - - def call(identifier, *args) - eval "#{identifier}.apply(this, #{::JSON.generate(args)})" - end end def name From df33657dfd2b7e76f38a80681f4d880fc407d747 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 9 Dec 2014 14:57:08 -0800 Subject: [PATCH 07/23] Prefer Duktape --- lib/execjs/runtimes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/runtimes.rb b/lib/execjs/runtimes.rb index 8730f5d..67a5d10 100644 --- a/lib/execjs/runtimes.rb +++ b/lib/execjs/runtimes.rb @@ -79,9 +79,9 @@ module ExecJS def self.runtimes @runtimes ||= [ + Duktape, RubyRacer, RubyRhino, - Duktape, Johnson, Mustang, Node, From bf982dd33365ea34622b1189e7d4bd2461b8c975 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 9 Dec 2014 15:01:17 -0800 Subject: [PATCH 08/23] Rescue internal errors --- lib/execjs/duktape_runtime.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index bae656c..c313f33 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -23,6 +23,8 @@ module ExecJS raise RuntimeError, e.message rescue Duktape::Error => e raise ProgramError, e.message + rescue Duktape::InternalError => e + raise RuntimeError, e.message end def call(identifier, *args) From 945772a69f96e93b2fab3000351ed93701c04346 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 11 Dec 2014 10:13:59 -0800 Subject: [PATCH 09/23] Encode first --- lib/execjs/duktape_runtime.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index c313f33..a0f1d2b 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -10,7 +10,7 @@ module ExecJS end def exec(source, options = {}) - eval "(function(){#{source}})()" + eval "(function(){#{encode(source)}})()" end def eval(source, options = {}) From c5c547e224e19e58178770594362fa9f8cb30d1d Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 11 Dec 2014 10:14:48 -0800 Subject: [PATCH 10/23] Return strings are now utf-8 --- lib/execjs/duktape_runtime.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index a0f1d2b..67125d5 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -43,8 +43,6 @@ module ExecJS vs[k] = v if v vs end - when String - obj.force_encoding('UTF-8') else obj end From a7e8a964bc484315b46cfbb6af709afd5a4af9ee Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 11 Dec 2014 10:38:20 -0800 Subject: [PATCH 11/23] Exec context --- lib/execjs/duktape_runtime.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index 67125d5..60e19eb 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -6,7 +6,9 @@ module ExecJS class Context < Runtime::Context def initialize(runtime, source = "") @ctx = Duktape::Context.new - exec(source) + + source = encode(source) + @ctx.exec_string(source, '(execjs)') end def exec(source, options = {}) From afe2cd0c402a2caeab30635eb4bd2adf0a1de072 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 11 Dec 2014 11:31:20 -0800 Subject: [PATCH 12/23] Use prop call --- lib/execjs/duktape_runtime.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index 60e19eb..4c63a28 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -30,7 +30,13 @@ module ExecJS end def call(identifier, *args) - eval "#{identifier}.apply(this, #{::JSON.generate(args)})" + unwrap(@ctx.call_prop(identifier.split("."), *args)) + rescue Duktape::SyntaxError => e + raise RuntimeError, e.message + rescue Duktape::Error => e + raise ProgramError, e.message + rescue Duktape::InternalError => e + raise RuntimeError, e.message end def unwrap(obj) From a3cca2f71d07a52706c4ecd676c20513bd7b611a Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 11 Dec 2014 11:32:49 -0800 Subject: [PATCH 13/23] Unwrap all hash values --- lib/execjs/duktape_runtime.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index 4c63a28..ddb1cc9 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -47,8 +47,7 @@ module ExecJS obj.map { |v| unwrap(v) } when Hash obj.inject({}) do |vs, (k, v)| - v = unwrap(v) - vs[k] = v if v + vs[k] = unwrap(v) vs end else From a523857ef4f74167914b42998b0039cae998f6e3 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 11 Dec 2014 14:56:05 -0800 Subject: [PATCH 14/23] Rescue context compile errors --- lib/execjs/duktape_runtime.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index ddb1cc9..246c2f2 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -9,6 +9,12 @@ module ExecJS source = encode(source) @ctx.exec_string(source, '(execjs)') + rescue Duktape::SyntaxError => e + raise RuntimeError, e.message + rescue Duktape::Error => e + raise ProgramError, e.message + rescue Duktape::InternalError => e + raise RuntimeError, e.message end def exec(source, options = {}) From 16bf2175adf3d8fd3671ee4e582087d182c3e064 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 13 Dec 2014 01:06:13 -0800 Subject: [PATCH 15/23] Wrap up normalized exception catching --- lib/execjs/duktape_runtime.rb | 80 +++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index 246c2f2..b52a6b3 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -7,59 +7,59 @@ module ExecJS def initialize(runtime, source = "") @ctx = Duktape::Context.new - source = encode(source) - @ctx.exec_string(source, '(execjs)') - rescue Duktape::SyntaxError => e - raise RuntimeError, e.message - rescue Duktape::Error => e - raise ProgramError, e.message - rescue Duktape::InternalError => e - raise RuntimeError, e.message + normalize do + @ctx.exec_string(encode(source), '(execjs)') + end end def exec(source, options = {}) - eval "(function(){#{encode(source)}})()" + return unless /\S/ =~ source + + normalize do + @ctx.eval_string("(function(){#{encode(source)}})()", '(execjs)') + end end def eval(source, options = {}) - source = encode(source) + return unless /\S/ =~ source - if /\S/ =~ source - unwrap(@ctx.eval_string("(#{source})", '(execjs)')) + normalize do + @ctx.eval_string("(#{encode(source)})", '(execjs)') end - rescue Duktape::SyntaxError => e - raise RuntimeError, e.message - rescue Duktape::Error => e - raise ProgramError, e.message - rescue Duktape::InternalError => e - raise RuntimeError, e.message end def call(identifier, *args) - unwrap(@ctx.call_prop(identifier.split("."), *args)) - rescue Duktape::SyntaxError => e - raise RuntimeError, e.message - rescue Duktape::Error => e - raise ProgramError, e.message - rescue Duktape::InternalError => e - raise RuntimeError, e.message - end - - def unwrap(obj) - case obj - when ::Duktape::ComplexObject - nil - when Array - obj.map { |v| unwrap(v) } - when Hash - obj.inject({}) do |vs, (k, v)| - vs[k] = unwrap(v) - vs - end - else - obj + normalize do + @ctx.call_prop(identifier.split("."), *args) end end + + private + def normalize + unwrap yield + rescue Duktape::SyntaxError => e + raise RuntimeError, e.message + rescue Duktape::Error => e + raise ProgramError, e.message + rescue Duktape::InternalError => e + raise RuntimeError, e.message + end + + def unwrap(obj) + case obj + when ::Duktape::ComplexObject + nil + when Array + obj.map { |v| unwrap(v) } + when Hash + obj.inject({}) do |vs, (k, v)| + vs[k] = unwrap(v) + vs + end + else + obj + end + end end def name From 9bee9ccaff3d92157d2771ad30e3f522cc380155 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 15 Dec 2014 17:29:01 -0800 Subject: [PATCH 16/23] Set complex_object to nil --- lib/execjs/duktape_runtime.rb | 60 +++++++++++++---------------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index b52a6b3..cc8477e 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -5,59 +5,43 @@ module ExecJS class DuktapeRuntime < Runtime class Context < Runtime::Context def initialize(runtime, source = "") - @ctx = Duktape::Context.new - - normalize do - @ctx.exec_string(encode(source), '(execjs)') - end + @ctx = Duktape::Context.new(complex_object: nil) + @ctx.exec_string(encode(source), '(execjs)') + rescue Exception => e + reraise_error(e) end def exec(source, options = {}) return unless /\S/ =~ source - - normalize do - @ctx.eval_string("(function(){#{encode(source)}})()", '(execjs)') - end + @ctx.eval_string("(function(){#{encode(source)}})()", '(execjs)') + rescue Exception => e + reraise_error(e) end def eval(source, options = {}) return unless /\S/ =~ source - - normalize do - @ctx.eval_string("(#{encode(source)})", '(execjs)') - end + @ctx.eval_string("(#{encode(source)})", '(execjs)') + rescue Exception => e + reraise_error(e) end def call(identifier, *args) - normalize do - @ctx.call_prop(identifier.split("."), *args) - end + @ctx.call_prop(identifier.split("."), *args) + rescue Exception => e + reraise_error(e) end private - def normalize - unwrap yield - rescue Duktape::SyntaxError => e - raise RuntimeError, e.message - rescue Duktape::Error => e - raise ProgramError, e.message - rescue Duktape::InternalError => e - raise RuntimeError, e.message - end - - def unwrap(obj) - case obj - when ::Duktape::ComplexObject - nil - when Array - obj.map { |v| unwrap(v) } - when Hash - obj.inject({}) do |vs, (k, v)| - vs[k] = unwrap(v) - vs - end + def reraise_error(e) + case e + when Duktape::SyntaxError + raise RuntimeError, e.message + when Duktape::Error + raise ProgramError, e.message + when Duktape::InternalError + raise RuntimeError, e.message else - obj + raise e end end end From cdcebcb05824b4374c1cb6ca45cd228764be2725 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 25 Feb 2015 14:26:58 -0600 Subject: [PATCH 17/23] Link to edge duktape for now --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 69d040d..1f0e4b2 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' gemspec group :test do - gem 'duktape' + gem 'duktape', github: 'judofyr/duktape.rb' gem 'therubyracer', platform: :mri gem 'therubyrhino', ">=1.73.3", platform: :jruby gem 'minitest', require: false From cebf4a64a5dcba390ac755ed8f72ab6efb09a001 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 25 Feb 2015 14:28:12 -0600 Subject: [PATCH 18/23] Revert "Link to edge duktape for now" This reverts commit cdcebcb05824b4374c1cb6ca45cd228764be2725. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1f0e4b2..69d040d 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' gemspec group :test do - gem 'duktape', github: 'judofyr/duktape.rb' + gem 'duktape' gem 'therubyracer', platform: :mri gem 'therubyrhino', ">=1.73.3", platform: :jruby gem 'minitest', require: false From 3b15a50eeb93cfe0f4214410364b251ff461cbad Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 9 Mar 2015 16:37:07 -0700 Subject: [PATCH 19/23] Works on coffee now --- test/test_execjs.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/test_execjs.rb b/test/test_execjs.rb index 91ef6cb..fb44350 100644 --- a/test/test_execjs.rb +++ b/test/test_execjs.rb @@ -346,9 +346,6 @@ class TestExecJS < Test end def test_coffeescript - # Skip coffeescript on Duktape for now - skip if ExecJS.runtime.is_a?(ExecJS::DuktapeRuntime) - assert source = File.read(File.expand_path("../fixtures/coffee-script.js", __FILE__)) context = ExecJS.compile(source) assert_equal 64, context.call("CoffeeScript.eval", "((x) -> x * x)(8)") From cb4c3ceb4b16bea9aa2d6dbb7e6f99734410b7c5 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 9 Mar 2015 16:43:17 -0700 Subject: [PATCH 20/23] Wrap error with lineno --- lib/execjs/duktape_runtime.rb | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/execjs/duktape_runtime.rb b/lib/execjs/duktape_runtime.rb index cc8477e..cfbc7f9 100644 --- a/lib/execjs/duktape_runtime.rb +++ b/lib/execjs/duktape_runtime.rb @@ -8,40 +8,48 @@ module ExecJS @ctx = Duktape::Context.new(complex_object: nil) @ctx.exec_string(encode(source), '(execjs)') rescue Exception => e - reraise_error(e) + raise wrap_error(e) end def exec(source, options = {}) return unless /\S/ =~ source @ctx.eval_string("(function(){#{encode(source)}})()", '(execjs)') rescue Exception => e - reraise_error(e) + raise wrap_error(e) end def eval(source, options = {}) return unless /\S/ =~ source @ctx.eval_string("(#{encode(source)})", '(execjs)') rescue Exception => e - reraise_error(e) + raise wrap_error(e) end def call(identifier, *args) @ctx.call_prop(identifier.split("."), *args) rescue Exception => e - reraise_error(e) + raise wrap_error(e) end private - def reraise_error(e) - case e + def wrap_error(e) + klass = case e when Duktape::SyntaxError - raise RuntimeError, e.message + RuntimeError when Duktape::Error - raise ProgramError, e.message + ProgramError when Duktape::InternalError - raise RuntimeError, e.message + RuntimeError + end + + if klass + re = / \(line (\d+)\)$/ + lineno = e.message[re, 1] || 1 + error = klass.new(e.message.sub(re, "")) + error.set_backtrace(["(execjs):#{lineno}"] + e.backtrace) + error else - raise e + e end end end From 5ff315a9599fad23daa9547fe7001d2002185552 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 22 Mar 2015 09:59:36 -0700 Subject: [PATCH 21/23] Test from duktape.rb master --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 69d040d..1f0e4b2 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' gemspec group :test do - gem 'duktape' + gem 'duktape', github: 'judofyr/duktape.rb' gem 'therubyracer', platform: :mri gem 'therubyrhino', ">=1.73.3", platform: :jruby gem 'minitest', require: false From 264b53de9ebc1d2d7c46704c9d88c7d39c97e592 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 22 Mar 2015 10:03:24 -0700 Subject: [PATCH 22/23] Skip on jruby --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1f0e4b2..18351bb 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' gemspec group :test do - gem 'duktape', github: 'judofyr/duktape.rb' + gem 'duktape', platform: :mri, github: 'judofyr/duktape.rb' gem 'therubyracer', platform: :mri gem 'therubyrhino', ">=1.73.3", platform: :jruby gem 'minitest', require: false From 0d0ae14fb88eb28f60c02de26af0660444fa1054 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 6 Apr 2015 10:00:23 -0700 Subject: [PATCH 23/23] Use stable duktape --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 18351bb..2d5fb79 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' gemspec group :test do - gem 'duktape', platform: :mri, github: 'judofyr/duktape.rb' + gem 'duktape', platform: :mri gem 'therubyracer', platform: :mri gem 'therubyrhino', ">=1.73.3", platform: :jruby gem 'minitest', require: false