Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Use ExecJS

  • Loading branch information
josh committed Mar 10, 2011
1 parent 779c03b commit 4a4bb56dca40b59bd61705ac47d31b072bec1458
Showing with 9 additions and 150 deletions.
  1. +1 −1 coffee-script.gemspec
  2. +7 −125 lib/coffee_script.rb
  3. +1 −24 test/test_coffee_script.rb
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
]

s.add_dependency 'coffee-script-source'
s.add_development_dependency 'therubyracer'
s.add_dependency 'execjs'

s.authors = ['Jeremy Ashkenas', 'Joshua Peek', 'Sam Stephenson']
s.email = 'josh@joshpeek.com'
@@ -1,20 +1,17 @@
require 'json'
require 'tempfile'

require 'execjs'
require 'coffee_script/source'

module CoffeeScript
class Error < ::StandardError; end
class EngineError < Error; end
class CompilationError < Error; end
EngineError = ExecJS::RuntimeError
CompilationError = ExecJS::ProgramError

module Source
def self.path
@path ||= ENV['COFFEESCRIPT_SOURCE_PATH'] || bundled_path
end

def self.path=(path)
@contents = @version = @bare_option = nil
@contents = @version = @bare_option = @context = nil
@path = path
end

@@ -29,126 +26,17 @@ def self.version
def self.bare_option
@bare_option ||= contents.match(/noWrap/) ? 'noWrap' : 'bare'
end
end

module ExternalEngine
class << self
def compile(command, script, options)
yield f = Tempfile.open("coffee.js")
f.puts compile_js(script, options)
f.close

execute("#{command} #{f.path}")
ensure
f.close! if f
end

def execute(command)
out = `#{command}`.chomp
if $?.success?
status, result = out[0, 1], out[1..-1]
if status == "+"
result
else
raise CompilationError, result[/^(?:Error: )?(.*)/, 1]
end
else
raise EngineError, out
end
end

def compile_js(script, options)
options = options[:bare] ? "{#{Source.bare_option} : true}" : "{}"
<<-JS
try {
print('+' + CoffeeScript.compile(#{script.to_json}, #{options}));
} catch (e) {
print('-' + e);
}
JS
end
end
end

module Engines
module JavaScriptCore
BIN = "/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc"

class << self
def supported?
File.exist?(BIN)
end

def compile(script, options = {})
ExternalEngine.compile(BIN, script, options) do |f|
f.puts "load(#{Source.path.to_json});"
end
end
end
end

module Node
class << self

def binary
@binary ||= `sh -c "which nodejs node"`.split("\n").first
end

def binary=(value)
@binary = value.nil? ? nil : value.to_s
end

def supported?
binary
end

def compile(script, options = {})
ExternalEngine.compile(binary, script, options) do |f|
f.puts Source.contents
f.puts "var CoffeeScript = this.CoffeeScript, print = console.log;"
end
end
end
end

module V8
class << self
def supported?
require 'v8'
true
rescue LoadError
false
end

def compile(script, options = {})
coffee_module['compile'].call(script, Source.bare_option => options[:bare])
rescue ::V8::JSError => e
raise CompilationError, e.message
end

private
def coffee_module
@coffee_module ||= build_coffee_module
end

def build_coffee_module
context = ::V8::Context.new
context.eval(Source.contents)
context['CoffeeScript']
rescue ::V8::JSError => e
raise EngineError, e.message
end
end
def self.context
@context ||= ExecJS.compile(contents)
end
end

class << self
def engine
@engine ||= nil
end

def engine=(engine)
@engine = engine
end

def version
@@ -166,13 +54,7 @@ def compile(script, options = {})
options[:bare] = false
end

engine.compile(script, options)
Source.context.call("CoffeeScript.compile", script, options)
end
end

self.engine ||= [
Engines::V8,
Engines::Node,
Engines::JavaScriptCore
].detect(&:supported?)
end
@@ -2,7 +2,7 @@
require 'test/unit'
require 'stringio'

module CoffeeScriptTests
class TestCoffeeScript < Test::Unit::TestCase
def test_compile
assert_equal "(function() {\n puts('Hello, World!');\n}).call(this);\n",
CoffeeScript.compile("puts 'Hello, World!'\n")
@@ -40,33 +40,10 @@ def test_compilation_error
end
end

def test_error_messages_omit_leading_error_string
assert_exception_does_not_match(/^Error: /) { CoffeeScript.compile("unless") } # parse error
assert_exception_does_not_match(/^Error: /) { CoffeeScript.compile("function") } # syntax error
end

def assert_exception_does_not_match(pattern)
yield
flunk "no exception raised"
rescue Exception => e
assert_no_match pattern, e.message
end
end

CoffeeScript::Engines.constants.each do |const|
engine = CoffeeScript::Engines.const_get(const)
unless engine.supported?
warn "*** skipping #{const} tests"
next
end

instance_eval <<-RUBY, __FILE__, __LINE__ + 1
class Test#{const} < Test::Unit::TestCase
include CoffeeScriptTests
def setup
CoffeeScript.engine = CoffeeScript::Engines::#{const}
end
end
RUBY
end

0 comments on commit 4a4bb56

Please sign in to comment.
You can’t perform that action at this time.