execjs 2.5.1 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6bd129488d607b71ba6aec4c087036583727f4114d632107be2297b96a6a20f2
4
+ data.tar.gz: fea27c5987305700a3c5adbbe8f2e282dc5d49e6c579d2c91369886739342c26
5
+ SHA512:
6
+ metadata.gz: 99fe4da9a1203aa378e4f73879db38d7f9737dedc92141c820e099229eac5d00e311ab56379d5a92ef41fa1323cedf2614ee2e971e0e5602096f30732aed1808
7
+ data.tar.gz: df6fb1647179df49bef56c5570fbc7148bfa1e290945e398482e369572764b60c1293c2220c6e3101d6bd9880d47d4084f2b1325c5f39d321a186ef4ec2ac639
@@ -1,5 +1,5 @@
1
- Copyright (c) 2015 Sam Stephenson
2
- Copyright (c) 2015 Josh Peek
1
+ Copyright (c) 2015-2016 Sam Stephenson
2
+ Copyright (c) 2015-2016 Josh Peek
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
5
5
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -7,14 +7,15 @@ returns the result to you as a Ruby object.
7
7
 
8
8
  ExecJS supports these runtimes:
9
9
 
10
- * [therubyracer](https://github.com/cowboyd/therubyracer) - Google V8
11
- embedded within Ruby
12
10
  * [therubyrhino](https://github.com/cowboyd/therubyrhino) - Mozilla
13
11
  Rhino embedded within JRuby
14
12
  * [Duktape.rb](https://github.com/judofyr/duktape.rb) - Duktape JavaScript interpreter
15
13
  * [Node.js](http://nodejs.org/)
16
14
  * Apple JavaScriptCore - Included with Mac OS X
17
15
  * [Microsoft Windows Script Host](http://msdn.microsoft.com/en-us/library/9bbdkx3k.aspx) (JScript)
16
+ * [Google V8](http://code.google.com/p/v8/)
17
+ * [mini_racer](https://github.com/discourse/mini_racer) - Google V8
18
+ embedded within Ruby
18
19
 
19
20
  A short example:
20
21
 
@@ -42,7 +43,6 @@ context.call("CoffeeScript.compile", "square = (x) -> x * x", bare: true)
42
43
  $ gem install execjs
43
44
  ```
44
45
 
45
-
46
46
  # FAQ
47
47
 
48
48
  **Why can't I use CommonJS `require()` inside ExecJS?**
@@ -72,9 +72,12 @@ are automatically detected, each runtime has different sandboxing properties.
72
72
  You shouldn't use `ExecJS.eval` on any inputs you wouldn't feel comfortable Ruby
73
73
  `eval()`ing.
74
74
 
75
+ ## Contributing to ExecJS
75
76
 
76
- # License
77
+ ExecJS is work of dozens of contributors. You're encouraged to submit pull requests, propose
78
+ features and discuss issues.
77
79
 
78
- Copyright (c) 2015 Sam Stephenson and Josh Peek.
80
+ See [CONTRIBUTING](CONTRIBUTING.md).
79
81
 
80
- Released under the MIT license. See `LICENSE` for details.
82
+ ## License
83
+ ExecJS is released under the [MIT License](MIT-LICENSE).
@@ -6,15 +6,15 @@ module ExecJS
6
6
  "Disabled"
7
7
  end
8
8
 
9
- def exec(source)
9
+ def exec(source, options = {})
10
10
  raise Error, "ExecJS disabled"
11
11
  end
12
12
 
13
- def eval(source)
13
+ def eval(source, options = {})
14
14
  raise Error, "ExecJS disabled"
15
15
  end
16
16
 
17
- def compile(source)
17
+ def compile(source, options = {})
18
18
  raise Error, "ExecJS disabled"
19
19
  end
20
20
 
@@ -4,7 +4,7 @@ require "json"
4
4
  module ExecJS
5
5
  class DuktapeRuntime < Runtime
6
6
  class Context < Runtime::Context
7
- def initialize(runtime, source = "")
7
+ def initialize(runtime, source = "", options = {})
8
8
  @ctx = Duktape::Context.new(complex_object: nil)
9
9
  @ctx.exec_string(encode(source), '(execjs)')
10
10
  rescue Exception => e
@@ -26,7 +26,8 @@ module ExecJS
26
26
  end
27
27
 
28
28
  def call(identifier, *args)
29
- @ctx.call_prop(identifier.split("."), *args)
29
+ @ctx.exec_string("__execjs_duktape_call = #{identifier}", '(execjs)')
30
+ @ctx.call_prop("__execjs_duktape_call", *args)
30
31
  rescue Exception => e
31
32
  raise wrap_error(e)
32
33
  end
@@ -4,7 +4,7 @@ require "execjs/runtime"
4
4
  module ExecJS
5
5
  class ExternalRuntime < Runtime
6
6
  class Context < Runtime::Context
7
- def initialize(runtime, source = "")
7
+ def initialize(runtime, source = "", options = {})
8
8
  source = encode(source)
9
9
 
10
10
  @runtime = runtime
@@ -120,20 +120,25 @@ module ExecJS
120
120
  @binary ||= which(@command)
121
121
  end
122
122
 
123
- def locate_executable(cmd)
124
- if ExecJS.windows? && File.extname(cmd) == ""
125
- cmd << ".exe"
126
- end
127
-
128
- if File.executable? cmd
129
- cmd
130
- else
131
- path = ENV['PATH'].split(File::PATH_SEPARATOR).find { |p|
132
- full_path = File.join(p, cmd)
133
- File.executable?(full_path) && File.file?(full_path)
123
+ def locate_executable(command)
124
+ commands = Array(command)
125
+ if ExecJS.windows? && File.extname(command) == ""
126
+ ENV['PATHEXT'].split(File::PATH_SEPARATOR).each { |p|
127
+ commands << (command + p)
134
128
  }
135
- path && File.expand_path(cmd, path)
136
129
  end
130
+
131
+ commands.find { |cmd|
132
+ if File.executable? cmd
133
+ cmd
134
+ else
135
+ path = ENV['PATH'].split(File::PATH_SEPARATOR).find { |p|
136
+ full_path = File.join(p, cmd)
137
+ File.executable?(full_path) && File.file?(full_path)
138
+ }
139
+ path && File.expand_path(cmd, path)
140
+ end
141
+ }
137
142
  end
138
143
 
139
144
  protected
@@ -168,7 +173,7 @@ module ExecJS
168
173
  begin
169
174
  command = binary.split(" ") << filename
170
175
  `#{shell_escape(*command)} 2>&1 > #{path}`
171
- output = File.open(path, 'rb', @popen_options) { |f| f.read }
176
+ output = File.open(path, 'rb', **@popen_options) { |f| f.read }
172
177
  ensure
173
178
  File.unlink(path) if path
174
179
  end
@@ -192,7 +197,7 @@ module ExecJS
192
197
 
193
198
  def exec_runtime(filename)
194
199
  command = "#{Shellwords.join(binary.split(' ') << filename)} 2>&1"
195
- io = IO.popen(command, @popen_options)
200
+ io = IO.popen(command, **@popen_options)
196
201
  output = io.read
197
202
  io.close
198
203
 
@@ -204,7 +209,7 @@ module ExecJS
204
209
  end
205
210
  else
206
211
  def exec_runtime(filename)
207
- io = IO.popen(binary.split(' ') << filename, @popen_options.merge({err: [:child, :out]}))
212
+ io = IO.popen(binary.split(' ') << filename, **(@popen_options.merge({err: [:child, :out]})))
208
213
  output = io.read
209
214
  io.close
210
215
 
@@ -0,0 +1,103 @@
1
+ require "execjs/runtime"
2
+
3
+ module ExecJS
4
+ class MiniRacerRuntime < Runtime
5
+ class Context < Runtime::Context
6
+ def initialize(runtime, source = "", options={})
7
+ source = encode(source)
8
+ @context = ::MiniRacer::Context.new
9
+ @context.eval("delete this.console");
10
+ translate do
11
+ @context.eval(source)
12
+ end
13
+ end
14
+
15
+ def exec(source, options = {})
16
+ source = encode(source)
17
+
18
+ if /\S/ =~ source
19
+ eval "(function(){#{source}})()"
20
+ end
21
+ end
22
+
23
+ def eval(source, options = {})
24
+ source = encode(source)
25
+
26
+ if /\S/ =~ source
27
+ translate do
28
+ @context.eval("(#{source})")
29
+ end
30
+ end
31
+ end
32
+
33
+ def call(identifier, *args)
34
+ # TODO optimise generate
35
+ eval "#{identifier}.apply(this, #{::JSON.generate(args)})"
36
+ end
37
+
38
+ private
39
+
40
+ def strip_functions!(value)
41
+ if Array === value
42
+ value.map! do |v|
43
+ if MiniRacer::JavaScriptFunction === value
44
+ nil
45
+ else
46
+ strip_functions!(v)
47
+ end
48
+ end
49
+ elsif Hash === value
50
+ value.each do |k,v|
51
+ if MiniRacer::JavaScriptFunction === v
52
+ value.delete k
53
+ else
54
+ value[k] = strip_functions!(v)
55
+ end
56
+ end
57
+ value
58
+ elsif MiniRacer::JavaScriptFunction === value
59
+ nil
60
+ else
61
+ value
62
+ end
63
+ end
64
+
65
+ def translate
66
+ begin
67
+ strip_functions! yield
68
+ rescue MiniRacer::RuntimeError => e
69
+ ex = ProgramError.new e.message
70
+ if backtrace = e.backtrace
71
+ backtrace = backtrace.map { |line|
72
+ if line =~ /JavaScript at/
73
+ line.sub("JavaScript at ", "")
74
+ .sub("<anonymous>", "(execjs)")
75
+ .strip
76
+ else
77
+ line
78
+ end
79
+ }
80
+ ex.set_backtrace backtrace
81
+ end
82
+ raise ex
83
+ rescue MiniRacer::ParseError => e
84
+ ex = RuntimeError.new e.message
85
+ ex.set_backtrace(["(execjs):1"] + e.backtrace)
86
+ raise ex
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ def name
93
+ "mini_racer (V8)"
94
+ end
95
+
96
+ def available?
97
+ require "mini_racer"
98
+ true
99
+ rescue LoadError
100
+ false
101
+ end
102
+ end
103
+ end
data/lib/execjs/module.rb CHANGED
@@ -15,16 +15,16 @@ module ExecJS
15
15
  @runtime = runtime
16
16
  end
17
17
 
18
- def exec(source)
19
- runtime.exec(source)
18
+ def exec(source, options = {})
19
+ runtime.exec(source, options)
20
20
  end
21
21
 
22
- def eval(source)
23
- runtime.eval(source)
22
+ def eval(source, options = {})
23
+ runtime.eval(source, options)
24
24
  end
25
25
 
26
- def compile(source)
27
- runtime.compile(source)
26
+ def compile(source, options = {})
27
+ runtime.compile(source, options)
28
28
  end
29
29
 
30
30
  def root
@@ -3,7 +3,7 @@ require "execjs/runtime"
3
3
  module ExecJS
4
4
  class RubyRhinoRuntime < Runtime
5
5
  class Context < Runtime::Context
6
- def initialize(runtime, source = "")
6
+ def initialize(runtime, source = "", options = {})
7
7
  source = encode(source)
8
8
 
9
9
  @rhino_context = ::Rhino::Context.new
@@ -6,18 +6,33 @@ module ExecJS
6
6
  class Context
7
7
  include Encoding
8
8
 
9
- def initialize(runtime, source = "")
9
+ def initialize(runtime, source = "", options = {})
10
10
  end
11
11
 
12
+ # Evaluates the +source+ in the context of a function body and returns the
13
+ # returned value.
14
+ #
15
+ # context.exec("return 1") # => 1
16
+ # context.exec("1") # => nil (nothing was returned)
12
17
  def exec(source, options = {})
13
18
  raise NotImplementedError
14
19
  end
15
20
 
21
+ # Evaluates the +source+ as an expression and returns the result.
22
+ #
23
+ # context.eval("1") # => 1
24
+ # context.eval("return 1") # => Raises SyntaxError
16
25
  def eval(source, options = {})
17
26
  raise NotImplementedError
18
27
  end
19
28
 
20
- def call(properties, *args)
29
+ # Evaluates +source+ as an expression (which should be of type
30
+ # +function+), and calls the function with the given arguments.
31
+ # The function will be evaluated with the global object as +this+.
32
+ #
33
+ # context.call("function(a, b) { return a + b }", 1, 1) # => 2
34
+ # context.call("CoffeeScript.compile", "1 + 1")
35
+ def call(source, *args)
21
36
  raise NotImplementedError
22
37
  end
23
38
  end
@@ -30,18 +45,32 @@ module ExecJS
30
45
  self.class::Context
31
46
  end
32
47
 
33
- def exec(source)
34
- context = context_class.new(self)
35
- context.exec(source)
48
+ def exec(source, options = {})
49
+ context = compile("", options)
50
+
51
+ if context.method(:exec).arity == 1
52
+ context.exec(source)
53
+ else
54
+ context.exec(source, options)
55
+ end
36
56
  end
37
57
 
38
- def eval(source)
39
- context = context_class.new(self)
40
- context.eval(source)
58
+ def eval(source, options = {})
59
+ context = compile("", options)
60
+
61
+ if context.method(:eval).arity == 1
62
+ context.eval(source)
63
+ else
64
+ context.eval(source, options)
65
+ end
41
66
  end
42
67
 
43
- def compile(source)
44
- context_class.new(self, source)
68
+ def compile(source, options = {})
69
+ if context_class.instance_method(:initialize).arity == 2
70
+ context_class.new(self, source)
71
+ else
72
+ context_class.new(self, source, options)
73
+ end
45
74
  end
46
75
 
47
76
  def deprecated?
@@ -2,8 +2,8 @@ require "execjs/module"
2
2
  require "execjs/disabled_runtime"
3
3
  require "execjs/duktape_runtime"
4
4
  require "execjs/external_runtime"
5
- require "execjs/ruby_racer_runtime"
6
5
  require "execjs/ruby_rhino_runtime"
6
+ require "execjs/mini_racer_runtime"
7
7
 
8
8
  module ExecJS
9
9
  module Runtimes
@@ -11,20 +11,23 @@ module ExecJS
11
11
 
12
12
  Duktape = DuktapeRuntime.new
13
13
 
14
- RubyRacer = RubyRacerRuntime.new
15
-
16
14
  RubyRhino = RubyRhinoRuntime.new
17
15
 
16
+ MiniRacer = MiniRacerRuntime.new
17
+
18
18
  Node = ExternalRuntime.new(
19
19
  name: "Node.js (V8)",
20
- command: ["nodejs", "node"],
20
+ command: ["node", "nodejs"],
21
21
  runner_path: ExecJS.root + "/support/node_runner.js",
22
22
  encoding: 'UTF-8'
23
23
  )
24
24
 
25
25
  JavaScriptCore = ExternalRuntime.new(
26
26
  name: "JavaScriptCore",
27
- command: "/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc",
27
+ command: [
28
+ "/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Helpers/jsc",
29
+ "/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc",
30
+ ],
28
31
  runner_path: ExecJS.root + "/support/jsc_runner.js"
29
32
  )
30
33
 
@@ -42,6 +45,13 @@ module ExecJS
42
45
  encoding: 'UTF-16LE' # CScript with //U returns UTF-16LE
43
46
  )
44
47
 
48
+ V8 = ExternalRuntime.new(
49
+ name: "V8",
50
+ command: "d8",
51
+ runner_path: ExecJS.root + "/support/v8_runner.js",
52
+ encoding: 'UTF-8'
53
+ )
54
+
45
55
 
46
56
  def self.autodetect
47
57
  from_environment || best_available ||
@@ -54,16 +64,14 @@ module ExecJS
54
64
  end
55
65
 
56
66
  def self.from_environment
57
- if name = ENV["EXECJS_RUNTIME"]
58
- if runtime = const_get(name)
59
- if runtime.available?
60
- runtime if runtime.available?
61
- else
62
- raise RuntimeUnavailable, "#{runtime.name} runtime is not available on this system"
63
- end
64
- elsif !name.empty?
65
- raise RuntimeUnavailable, "#{name} runtime is not defined"
66
- end
67
+ env = ENV["EXECJS_RUNTIME"]
68
+ if env && !env.empty?
69
+ name = env
70
+ raise RuntimeUnavailable, "#{name} runtime is not defined" unless const_defined?(name)
71
+ runtime = const_get(name)
72
+
73
+ raise RuntimeUnavailable, "#{runtime.name} runtime is not available on this system" unless runtime.available?
74
+ runtime
67
75
  end
68
76
  end
69
77
 
@@ -73,13 +81,14 @@ module ExecJS
73
81
 
74
82
  def self.runtimes
75
83
  @runtimes ||= [
76
- RubyRacer,
77
84
  RubyRhino,
78
85
  Duktape,
79
- JavaScriptCore,
86
+ MiniRacer,
80
87
  Node,
88
+ JavaScriptCore,
81
89
  SpiderMonkey,
82
- JScript
90
+ JScript,
91
+ V8
83
92
  ]
84
93
  end
85
94
  end
@@ -2,6 +2,7 @@
2
2
  }, function(program) {
3
3
  var output;
4
4
  try {
5
+ delete this.console;
5
6
  result = program();
6
7
  if (typeof result == 'undefined' && result !== null) {
7
8
  print('["ok"]');
@@ -1,20 +1,34 @@
1
- (function(program, execJS) { execJS(program) })(function(global, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source}
1
+ (function(program, execJS) { execJS(program) })(function(global, process, module, exports, require, console, setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate) { #{source}
2
2
  }, function(program) {
3
- var output, print = function(string) {
4
- process.stdout.write('' + string);
3
+ var __process__ = process;
4
+
5
+ var printFinal = function(string) {
6
+ process.stdout.write('' + string, function() {
7
+ __process__.exit(0);
8
+ });
5
9
  };
6
10
  try {
11
+ delete this.process;
12
+ delete this.console;
13
+ delete this.setTimeout;
14
+ delete this.setInterval;
15
+ delete this.clearTimeout;
16
+ delete this.clearInterval;
17
+ delete this.setImmediate;
18
+ delete this.clearImmediate;
7
19
  result = program();
20
+ this.process = __process__;
8
21
  if (typeof result == 'undefined' && result !== null) {
9
- print('["ok"]');
22
+ printFinal('["ok"]');
10
23
  } else {
11
24
  try {
12
- print(JSON.stringify(['ok', result]));
25
+ printFinal(JSON.stringify(['ok', result]));
13
26
  } catch (err) {
14
- print(JSON.stringify(['err', '' + err, err.stack]));
27
+ printFinal(JSON.stringify(['err', '' + err, err.stack]));
15
28
  }
16
29
  }
17
30
  } catch (err) {
18
- print(JSON.stringify(['err', '' + err, err.stack]));
31
+ this.process = __process__;
32
+ printFinal(JSON.stringify(['err', '' + err, err.stack]));
19
33
  }
20
34
  });
@@ -0,0 +1,18 @@
1
+ (function(program, execJS) { execJS(program) })(function() { #{source}
2
+ }, function(program) {
3
+ var output;
4
+ try {
5
+ result = program();
6
+ if (typeof result == 'undefined' && result !== null) {
7
+ print('["ok"]');
8
+ } else {
9
+ try {
10
+ print(JSON.stringify(['ok', result]));
11
+ } catch (err) {
12
+ print(JSON.stringify(['err', '' + err, err.stack]));
13
+ }
14
+ }
15
+ } catch (err) {
16
+ print(JSON.stringify(['err', '' + err, err.stack]));
17
+ }
18
+ });
@@ -1,3 +1,3 @@
1
1
  module ExecJS
2
- VERSION = "2.5.1"
2
+ VERSION = "2.8.1"
3
3
  end
metadata CHANGED
@@ -1,31 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: execjs
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.1
5
- prerelease:
4
+ version: 2.8.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Sam Stephenson
9
8
  - Josh Peek
10
- autorequire:
9
+ autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2015-04-08 00:00:00.000000000 Z
12
+ date: 2021-05-14 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: rake
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
- - - ! '>='
18
+ - - ">="
21
19
  - !ruby/object:Gem::Version
22
20
  version: '0'
23
21
  type: :development
24
22
  prerelease: false
25
23
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
24
  requirements:
28
- - - ! '>='
25
+ - - ">="
29
26
  - !ruby/object:Gem::Version
30
27
  version: '0'
31
28
  description: ExecJS lets you run JavaScript code from Ruby.
@@ -36,14 +33,15 @@ executables: []
36
33
  extensions: []
37
34
  extra_rdoc_files: []
38
35
  files:
36
+ - MIT-LICENSE
39
37
  - README.md
40
- - LICENSE
38
+ - lib/execjs.rb
41
39
  - lib/execjs/disabled_runtime.rb
42
40
  - lib/execjs/duktape_runtime.rb
43
41
  - lib/execjs/encoding.rb
44
42
  - lib/execjs/external_runtime.rb
43
+ - lib/execjs/mini_racer_runtime.rb
45
44
  - lib/execjs/module.rb
46
- - lib/execjs/ruby_racer_runtime.rb
47
45
  - lib/execjs/ruby_rhino_runtime.rb
48
46
  - lib/execjs/runtime.rb
49
47
  - lib/execjs/runtimes.rb
@@ -52,31 +50,29 @@ files:
52
50
  - lib/execjs/support/json2.js
53
51
  - lib/execjs/support/node_runner.js
54
52
  - lib/execjs/support/spidermonkey_runner.js
53
+ - lib/execjs/support/v8_runner.js
55
54
  - lib/execjs/version.rb
56
- - lib/execjs.rb
57
55
  homepage: https://github.com/rails/execjs
58
56
  licenses:
59
57
  - MIT
60
- post_install_message:
58
+ metadata: {}
59
+ post_install_message:
61
60
  rdoc_options: []
62
61
  require_paths:
63
62
  - lib
64
63
  required_ruby_version: !ruby/object:Gem::Requirement
65
- none: false
66
64
  requirements:
67
- - - ! '>='
65
+ - - ">="
68
66
  - !ruby/object:Gem::Version
69
- version: 2.0.0
67
+ version: 1.9.3
70
68
  required_rubygems_version: !ruby/object:Gem::Requirement
71
- none: false
72
69
  requirements:
73
- - - ! '>='
70
+ - - ">="
74
71
  - !ruby/object:Gem::Version
75
72
  version: '0'
76
73
  requirements: []
77
- rubyforge_project:
78
- rubygems_version: 1.8.23.2
79
- signing_key:
80
- specification_version: 3
74
+ rubygems_version: 3.2.15
75
+ signing_key:
76
+ specification_version: 4
81
77
  summary: Run JavaScript code from Ruby
82
78
  test_files: []
@@ -1,114 +0,0 @@
1
- require "execjs/runtime"
2
-
3
- module ExecJS
4
- class RubyRacerRuntime < Runtime
5
- class Context < Runtime::Context
6
- def initialize(runtime, source = "")
7
- source = encode(source)
8
-
9
- lock do
10
- @v8_context = ::V8::Context.new
11
-
12
- begin
13
- @v8_context.eval(source)
14
- rescue ::V8::JSError => e
15
- raise wrap_error(e)
16
- end
17
- end
18
- end
19
-
20
- def exec(source, options = {})
21
- source = encode(source)
22
-
23
- if /\S/ =~ source
24
- eval "(function(){#{source}})()", options
25
- end
26
- end
27
-
28
- def eval(source, options = {})
29
- source = encode(source)
30
-
31
- if /\S/ =~ source
32
- lock do
33
- begin
34
- unbox @v8_context.eval("(#{source})")
35
- rescue ::V8::JSError => e
36
- raise wrap_error(e)
37
- end
38
- end
39
- end
40
- end
41
-
42
- def call(properties, *args)
43
- lock do
44
- begin
45
- unbox @v8_context.eval(properties).call(*args)
46
- rescue ::V8::JSError => e
47
- raise wrap_error(e)
48
- end
49
- end
50
- end
51
-
52
- def unbox(value)
53
- case value
54
- when ::V8::Function
55
- nil
56
- when ::V8::Array
57
- value.map { |v| unbox(v) }
58
- when ::V8::Object
59
- value.inject({}) do |vs, (k, v)|
60
- vs[k] = unbox(v) unless v.is_a?(::V8::Function)
61
- vs
62
- end
63
- when String
64
- value.force_encoding('UTF-8')
65
- else
66
- value
67
- end
68
- end
69
-
70
- private
71
- def lock
72
- result, exception = nil, nil
73
- V8::C::Locker() do
74
- begin
75
- result = yield
76
- rescue Exception => e
77
- exception = e
78
- end
79
- end
80
-
81
- if exception
82
- raise exception
83
- else
84
- result
85
- end
86
- end
87
-
88
- def wrap_error(e)
89
- error_class = e.value["name"] == "SyntaxError" ? RuntimeError : ProgramError
90
-
91
- stack = e.value["stack"] || ""
92
- stack = stack.split("\n")
93
- stack.shift
94
- stack = [e.message[/<eval>:\d+:\d+/, 0]].compact if stack.empty?
95
- stack = stack.map { |line| line.sub(" at ", "").sub("<eval>", "(execjs)").strip }
96
-
97
- error = error_class.new(e.value.to_s)
98
- error.set_backtrace(stack + caller)
99
- error
100
- end
101
- end
102
-
103
- def name
104
- "therubyracer (V8)"
105
- end
106
-
107
- def available?
108
- require "v8"
109
- true
110
- rescue LoadError
111
- false
112
- end
113
- end
114
- end