Skip to content

Commit 3204fc5

Browse files
author
Devin Torres
committed
Prepare for release
1 parent 232c748 commit 3204fc5

12 files changed

+158
-42
lines changed

.editorconfig

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
# Unix-style newlines with a newline ending every file
7+
[*]
8+
end_of_line = lf
9+
insert_final_newline = true
10+
11+
# 2 space indentation
12+
[*.{ex,exs,eex}]
13+
indent_style = space
14+
indent_size = 2

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
Copyright © 2013 Devin Torres <[email protected]>
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the “Software”), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.

lib/execjs.ex

+28-9
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,40 @@
11
defmodule Execjs do
22
import Execjs.Escape, only: [escape: 1]
33

4+
defexception Error, message: nil
45
defexception RuntimeError, message: nil
6+
defexception RuntimeUnavailable, message: "Could not find JavaScript runtime"
57

6-
defexception RuntimeUnavailable,
7-
message: "Could not find a JavaScript runtime"
8+
@spec eval(String.t) :: any
9+
def eval(source) when is_binary(source) do
10+
exec %s[eval("#{escape(source)}")]
11+
end
812

9-
def compile(source) do
13+
@spec compile(String.t) :: (String.t -> String.t)
14+
def compile(source) when is_binary(source) do
1015
{ pre, post } = { "(function(){\n#{source};\n", ";\n})()" }
1116
fn (source) ->
1217
pre <> source <> post
1318
end
1419
end
1520

16-
def call(context, thing, args) do
17-
source = "return #{thing}.apply(this, #{JSON.encode!(args)})"
18-
eval(context.(source))
21+
@spec call((String.t -> String.t), String.t, list(any)) :: any
22+
def call(context, identifier, args) when is_binary(identifier) and is_list(args) do
23+
source = "return #{identifier}.apply(this, #{JSON.encode!(args)})"
24+
exec context.(source)
1925
end
2026

21-
def eval(source) do
27+
defp exec(source) do
2228
runtime = Execjs.Runtimes.best_available
23-
program = runtime.template(escape(source))
29+
program = runtime.template(source)
2430
command = runtime.command |> System.find_executable
2531
tmpfile = compile_to_tempfile(program)
2632

2733
try do
2834
port = Port.open({ :spawn_executable, command },
2935
[:binary, :eof, :hide, { :args, [tmpfile] }])
3036

31-
loop(port)
37+
extract_result(loop(port))
3238
after
3339
File.rm! tmpfile
3440
end
@@ -55,4 +61,17 @@ defmodule Execjs do
5561
File.write! path, program
5662
path
5763
end
64+
65+
defp extract_result(output) do
66+
case JSON.decode!(output) do
67+
[ "ok", value ] ->
68+
value
69+
[ "ok" ] ->
70+
:undefined
71+
[ "err", message ] ->
72+
raise Execjs.RuntimeError, message: message
73+
[ "err" ] ->
74+
raise Execjs.Error
75+
end
76+
end
5877
end

lib/execjs/escape.ex

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
defmodule Execjs.Escape do
22
@compile :native
33

4-
def escape(""), do: ""
5-
6-
def escape(string) do
7-
iolist_to_binary(escape(string, ""))
8-
end
4+
def escape(""), do: ""
5+
def escape(string), do: escape(string, "")
96

107
escape_map = [
118
{ ?\\, "\\\\" },
@@ -19,12 +16,12 @@ defmodule Execjs.Escape do
1916

2017
lc { char, escaped } inlist escape_map do
2118
defp escape(<< unquote(char), rest :: binary >>, acc) do
22-
escape(rest, [acc, unquote(escaped)])
19+
escape(rest, << acc :: binary, unquote(escaped) >>)
2320
end
2421
end
2522

2623
defp escape(<< char :: utf8, rest :: binary >>, acc) do
27-
escape(rest, [acc, char])
24+
escape(rest, << acc :: binary, char :: utf8 >>)
2825
end
2926

3027
defp escape(<<>>, acc) do

lib/execjs/runtimes.ex

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
defmodule Execjs.Runtimes do
22
import Execjs.Runtime
33

4+
alias Execjs.RuntimeUnavailable
5+
46
Module.register_attribute __MODULE__, :runtimes, accumulate: true
57

68
defruntime Node,
79
command: "node",
810
runner: "node_runner.js.eex"
911

12+
defruntime SpiderMonkey,
13+
command: "js",
14+
runner: "spidermonkey_runner.js.eex"
15+
1016
defruntime JavaScriptCore,
1117
command: "/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc",
1218
runner: "jsc_runner.js.eex"
1319

20+
defruntime Rhino,
21+
command: "rhino",
22+
runner: "rhino_runner.js.eex"
23+
1424
def runtimes do
1525
unquote(Enum.reverse(@runtimes))
1626
end
@@ -20,7 +30,17 @@ defmodule Execjs.Runtimes do
2030
{ :ok, runtime } ->
2131
runtime
2232
:undefined ->
23-
runtime = Enum.find(runtimes, &(&1.available?)) || raise RuntimeUnavailable
33+
runtime = case System.get_env("EXECJS_RUNTIME") do
34+
nil ->
35+
Enum.find(runtimes, &(&1.available?)) || raise RuntimeUnavailable
36+
name ->
37+
runtime = Module.concat(__MODULE__, name)
38+
Code.ensure_loaded?(runtime)
39+
&& function_exported?(runtime, :available?, 0)
40+
&& runtime.available?
41+
|| raise RuntimeUnavailable
42+
runtime
43+
end
2444
:application.set_env(:execjs, :runtime, runtime)
2545
runtime
2646
end

mix.exs

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defmodule Execjs.Mixfile do
55
[ app: :execjs,
66
version: "0.0.1",
77
elixir: "~> 0.10.3",
8-
deps: deps ]
8+
deps: deps(Mix.env) ]
99
end
1010

1111
# Configuration for the OTP application
@@ -15,7 +15,11 @@ defmodule Execjs.Mixfile do
1515

1616
# Returns the list of dependencies in the format:
1717
# { :foobar, "~> 0.1", git: "https://github.com/elixir-lang/foobar.git" }
18-
defp deps do
18+
defp deps(:dev) do
19+
deps(:prod) ++ [{ :benchmark, github: "meh/elixir-benchmark" }]
20+
end
21+
22+
defp deps(_) do
1923
[ { :jazz, github: "meh/jazz", tag: "v0.0.1" } ]
2024
end
2125
end

mix.lock

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
[ "jazz": {:git, "git://github.com/meh/jazz.git", "5b3fd0e3efd2c8445289bdbda2f93bb0d96ad169", [{:tag, "v0.0.1"}]} ]
1+
[ "benchmark": {:git, "git://github.com/meh/elixir-benchmark.git", "d5e15aabff417f1ffc9ecf8e5966f5c338b10c1e", []},
2+
"jazz": {:git, "git://github.com/meh/jazz.git", "5b3fd0e3efd2c8445289bdbda2f93bb0d96ad169", [{:tag, "v0.0.1"}]} ]

priv/jsc_runner.js.eex

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
(function(program, execJS) { execJS(program); })(function() {
2-
return eval("<%= source %>");
1+
(function(program, runner) { runner(program); })(function() {
2+
return <%= source %>;
33
}, function(program) {
44
var result;
55
try {
66
result = program();
7-
if (reult === undefined) {
8-
print('["ok"]');
9-
} else {
10-
try {
7+
try {
8+
if (result === undefined) {
9+
print('["ok"]');
10+
} else {
1111
print(JSON.stringify(['ok', result]));
12-
} catch (err) {
13-
print('["err"]');
1412
}
13+
} catch (err) {
14+
print('["err"]');
1515
}
1616
} catch (err) {
1717
print(JSON.stringify(['err', '' + err]));

priv/node_runner.js.eex

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
(function(program, execJS) { execJS(program); })(function() {
2-
return eval("<%= source %>");
1+
(function(program, runner) { runner(program); })(function() {
2+
return <%= source %>;
33
}, function(program) {
44
var result;
55
try {
66
result = program();
7-
if (result === undefined) {
8-
process.stdout.write('["ok"]');
9-
} else {
10-
try {
7+
try {
8+
if (result === undefined) {
9+
process.stdout.write('["ok"]');
10+
} else {
1111
process.stdout.write(JSON.stringify(['ok', result]));
12-
} catch (err) {
13-
process.stdout.write('["err"]');
1412
}
13+
} catch (err) {
14+
process.stdout.write('["err"]');
1515
}
1616
} catch (err) {
1717
process.stdout.write(JSON.stringify(['err', '' + err]));

priv/rhino_runner.js.eex

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
(function(program, runner) { runner(program); })(function() {
2+
return <%= source %>;
3+
}, function(program) {
4+
var result;
5+
try {
6+
result = program();
7+
try {
8+
if (result === undefined) {
9+
process.stdout.write('["ok"]');
10+
} else {
11+
java.lang.System.out.println(JSON.stringify(['ok', result]));
12+
}
13+
} catch (err) {
14+
java.lang.System.out.println('["err"]');
15+
}
16+
} catch (err) {
17+
java.lang.System.out.println(JSON.stringify(['err', '' + err]));
18+
}
19+
});

priv/spidermonkey_runner.js.eex

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
(function(program, runner) { runner(program); })(function() {
2+
return <%= source %>;
3+
}, function(program) {
4+
var result;
5+
try {
6+
result = program();
7+
try {
8+
if (result === undefined) {
9+
print('["ok"]');
10+
} else {
11+
print(JSON.stringify(['ok', result]));
12+
}
13+
} catch (err) {
14+
print('["err"]');
15+
}
16+
} catch (err) {
17+
print(JSON.stringify(['err', '' + err]));
18+
}
19+
});

test/execjs_test.exs

+9-6
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ defmodule ExecjsTest do
22
use ExUnit.Case
33

44
test "eval" do
5-
# assert Execjs.eval("(function() { return 1 + 1; })();") == ["ok", 2]
5+
assert Execjs.eval("1 + 1") == 2
6+
assert Execjs.eval(%s{var a = "a"; a + "b"}) == "ab"
7+
end
68

9+
test "call" do
710
context = Execjs.compile(%S""")
8-
function addOne(n) {
9-
return n + 1;
10-
}
11-
"""
11+
function addOne(n) {
12+
return n + 1;
13+
}
14+
"""
1215

13-
IO.inspect Execjs.call(context, "addOne", [3])
16+
assert Execjs.call(context, "addOne", [3]) == 4
1417
end
1518
end

0 commit comments

Comments
 (0)