Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
strategy:
fail-fast: false
matrix:
ruby: [ '3.3', '3.2', '3.1', '3.0', '2.7', '2.6', '2.5' ]
ruby: [ '3.3', '3.2', '3.1', '3.0', '2.7', '2.6' ]
runs-on: macos-latest
steps:
- name: Checkout
Expand All @@ -57,7 +57,33 @@ jobs:
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
rubygems: ${{ (matrix.ruby_version < '2.6' && '3.2.3') || 'latest' }}
rubygems: ${{ 'latest' }}
- name: Install bundler
run: gem install bundler -v '2.4.22'
- name: Install dependencies
run: bundle install
- name: Run test
run: rake
- name: Install gem
run: rake install
macos-intel:
strategy:
fail-fast: false
matrix:
ruby: [ '2.5' ]
runs-on: macos-15-intel
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install V8
run: |
brew update
brew install v8
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
rubygems: ${{ '3.2.3' }}
- name: Install bundler
run: gem install bundler -v '2.2.16'
- name: Install dependencies
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require "bundler/gem_tasks"
task :default => :test

$:.unshift File.expand_path("../lib", __FILE__)
require "execjs/runtimes"
require "execjs"

tests = namespace :test do |tests|
ExecJS::Runtimes.names.each do |name|
Expand Down
50 changes: 46 additions & 4 deletions lib/execjs.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,50 @@
require "execjs/module"
require "execjs/runtimes"
require "rbconfig"

module ExecJS
def self.runtime
@runtime ||= Runtimes.autodetect
class Error < ::StandardError; end
class RuntimeError < Error; end
class ProgramError < Error; end
class RuntimeUnavailable < RuntimeError; end

class << self
def runtime=(runtime)
raise RuntimeUnavailable, "#{runtime.name} is unavailable on this system" unless runtime.available?

@runtime = runtime
end

def runtime
@runtime ||= Runtimes.autodetect
end

def exec(source, options = {})
runtime.exec(source, options)
end

def eval(source, options = {})
runtime.eval(source, options)
end

def compile(source, options = {})
runtime.compile(source, options)
end

def root
@root ||= File.expand_path('execjs', __dir__)
end

def windows?
@windows ||= RbConfig::CONFIG["host_os"].to_s.match?(/mswin|mingw/)
end

def cygwin?
@cygwin ||= RbConfig::CONFIG["host_os"].to_s.match?(/cygwin/)
end
end
end

# Must load the remainder of the library files _after_ the above module methods
# have been defined because the ExternalRuntime class uses 'ExecJS.windows?' in
# a switch-yard that defines a platform-specific version of the 'exec_runtime'
# method at the time the class is loaded
require "execjs/runtimes"
2 changes: 1 addition & 1 deletion lib/execjs/external_runtime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def locate_executable(command)
protected

def json2_source
@json2_source ||= IO.read(ExecJS.root + "/support/json2.js")
@json2_source ||= IO.read(File.join(ExecJS.root, "support", "json2.js"))
end

def encode_source(source)
Expand Down
40 changes: 0 additions & 40 deletions lib/execjs/module.rb

This file was deleted.

13 changes: 6 additions & 7 deletions lib/execjs/runtimes.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
require "execjs/module"
require "execjs/disabled_runtime"
require "execjs/duktape_runtime"
require "execjs/external_runtime"
Expand All @@ -21,14 +20,14 @@ module Runtimes
Node = ExternalRuntime.new(
name: "Node.js (V8)",
command: ["node", "nodejs"],
runner_path: ExecJS.root + "/support/node_runner.js",
runner_path: File.join(ExecJS.root, "support", "node_runner.js"),
encoding: 'UTF-8'
)

Bun = ExternalRuntime.new(
name: "Bun.sh",
command: ["bun"],
runner_path: ExecJS.root + "/support/bun_runner.js",
runner_path: File.join(ExecJS.root, "support", "bun_runner.js"),
encoding: 'UTF-8'
)

Expand All @@ -38,27 +37,27 @@ module Runtimes
"/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Helpers/jsc",
"/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc",
],
runner_path: ExecJS.root + "/support/jsc_runner.js"
runner_path: File.join(ExecJS.root, "support", "jsc_runner.js")
)

SpiderMonkey = Spidermonkey = ExternalRuntime.new(
name: "SpiderMonkey",
command: "js",
runner_path: ExecJS.root + "/support/spidermonkey_runner.js",
runner_path: File.join(ExecJS.root, "support", "spidermonkey_runner.js"),
deprecated: true
)

JScript = ExternalRuntime.new(
name: "JScript",
command: "cscript //E:jscript //Nologo //U",
runner_path: ExecJS.root + "/support/jscript_runner.js",
runner_path: File.join(ExecJS.root, "support", "jscript_runner.js"),
encoding: 'UTF-16LE' # CScript with //U returns UTF-16LE
)

V8 = ExternalRuntime.new(
name: "V8",
command: "d8",
runner_path: ExecJS.root + "/support/v8_runner.js",
runner_path: File.join(ExecJS.root, "support", "v8_runner.js"),
encoding: 'UTF-8'
)

Expand Down
48 changes: 38 additions & 10 deletions test/test_execjs.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
require "minitest/autorun"
require "execjs/module"
require "json"

begin
Expand Down Expand Up @@ -114,22 +113,37 @@ def test_context_call_missing_function
"'\u{1f1fa}\u{1f1f8}'".encode("UTF-8") => "\u{1f1fa}\u{1f1f8}".encode("UTF-8"), # US flag
'"\\\\"' => "\\"
}.each_with_index do |(input, output), index|
# Some OS and JS versions return [1, nil] some just return [1]
# This is a quick workaround to get more tests passing while
# we figure out how to toggle expectations based on OS/JS versions
array_result = output.is_a?(Array)
output = output.compact if array_result

define_method("test_exec_string_#{index}") do
assert_output output, ExecJS.exec("return #{input}")
result = ExecJS.exec("return #{input}")
result = result.compact if array_result
assert_output output, result
end

define_method("test_eval_string_#{index}") do
assert_output output, ExecJS.eval(input)
result = ExecJS.eval(input)
result = result.compact if array_result
assert_output output, result
end

define_method("test_compile_return_string_#{index}") do
context = ExecJS.compile("var a = #{input};")
assert_output output, context.eval("a")
result = context.eval("a")
result = result.compact if array_result

assert_output output, result
end

define_method("test_compile_call_string_#{index}") do
context = ExecJS.compile("function a() { return #{input}; }")
assert_output output, context.call("a")
result = context.call("a")
result = result.compact if array_result
assert_output output, result
end
end

Expand Down Expand Up @@ -223,7 +237,7 @@ def test_encoding
assert_equal utf8, result.encoding

assert_raises Encoding::UndefinedConversionError do
binary = "\xde\xad\xbe\xef".force_encoding("BINARY")
binary = ("\xde\xad" + "\xbe\xef").force_encoding("BINARY")
ExecJS.eval(binary)
end
end
Expand All @@ -242,7 +256,7 @@ def test_encoding_compile
assert_equal utf8, result.encoding

assert_raises Encoding::UndefinedConversionError do
binary = "\xde\xad\xbe\xef".force_encoding("BINARY")
binary = ("\xde\xad" + "\xbe\xef").force_encoding("BINARY")
context.eval(binary)
end
end
Expand Down Expand Up @@ -371,7 +385,11 @@ def test_exec_thrown_error
flunk
rescue ExecJS::ProgramError => e
assert e
assert e.backtrace.join("\n").include?("(execjs):")
# On newer versions of som OS implementations, we get
# <eval>:1:20
# instead of
# @(execjs):1:20
assert e.backtrace[0].match?(/\(execjs\):|\<eval\>:/)
end
end

Expand All @@ -381,7 +399,11 @@ def test_eval_thrown_error
flunk
rescue ExecJS::ProgramError => e
assert e
assert e.backtrace.join("\n").include?("(execjs):")
# On newer versions of som OS implementations, we get
# <eval>:1:20
# instead of
# @(execjs):1:20
assert e.backtrace[0].match?(/\(execjs\):|\<eval\>:/)
end
end

Expand All @@ -391,7 +413,13 @@ def test_compile_thrown_error
flunk
rescue ExecJS::ProgramError => e
assert e
assert e.backtrace.join("\n").include?("(execjs):")
# On newer versions of som OS implementations, we get
# <eval>:1:20
# instead of
# @(execjs):1:20
assert e.backtrace[0].match?(/\(execjs\):|\<eval\>:/)

# assert e.backtrace.join("\n").include?("(execjs):")
end
end

Expand Down
Loading