Skip to content

Commit 232c748

Browse files
author
Devin Torres
committed
Execjs.call
1 parent 32958a2 commit 232c748

File tree

6 files changed

+68
-49
lines changed

6 files changed

+68
-49
lines changed

lib/execjs.ex

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
1-
defexception Execjs.RuntimeError, message: nil
1+
defmodule Execjs do
2+
import Execjs.Escape, only: [escape: 1]
23

3-
defexception Execjs.RuntimeUnavailable,
4-
message: "Could not find a JavaScript runtime"
4+
defexception RuntimeError, message: nil
55

6-
defmodule Execjs do
7-
def eval(string) do
6+
defexception RuntimeUnavailable,
7+
message: "Could not find a JavaScript runtime"
8+
9+
def compile(source) do
10+
{ pre, post } = { "(function(){\n#{source};\n", ";\n})()" }
11+
fn (source) ->
12+
pre <> source <> post
13+
end
14+
end
15+
16+
def call(context, thing, args) do
17+
source = "return #{thing}.apply(this, #{JSON.encode!(args)})"
18+
eval(context.(source))
19+
end
20+
21+
def eval(source) do
822
runtime = Execjs.Runtimes.best_available
9-
program = runtime.template(escape(string))
23+
program = runtime.template(escape(source))
1024
command = runtime.command |> System.find_executable
11-
tmpfile = compile(program)
25+
tmpfile = compile_to_tempfile(program)
1226

1327
try do
1428
port = Port.open({ :spawn_executable, command },
@@ -34,39 +48,11 @@ defmodule Execjs do
3448
end
3549
end
3650

37-
defp compile(program) do
51+
defp compile_to_tempfile(program) do
3852
hash = :erlang.phash2(:crypto.rand_bytes(8))
3953
filename = "execjs-#{hash}.js"
4054
path = Path.join(System.tmp_dir!, filename)
4155
File.write! path, program
4256
path
4357
end
44-
45-
def escape(string) do
46-
iolist_to_binary(escape(string, ""))
47-
end
48-
49-
escape_map = [
50-
{ ?\\, "\\\\" },
51-
{ ?", "\\\"" },
52-
{ ?\n, "\\n" },
53-
{ ?\r, "\\r" },
54-
# http://bclary.com/2004/11/07/#a-7.3
55-
{ "\x{2028}", "\\u2028" },
56-
{ "\x{2029}", "\\u2029" }
57-
]
58-
59-
lc { char, escaped } inlist escape_map do
60-
defp escape(<< unquote(char), rest :: binary >>, acc) do
61-
escape(rest, [acc, unquote(escaped)])
62-
end
63-
end
64-
65-
defp escape(<< char :: utf8, rest :: binary >>, acc) do
66-
escape(rest, [acc, char])
67-
end
68-
69-
defp escape(<<>>, acc) do
70-
acc
71-
end
7258
end

lib/execjs/escape.ex

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
defmodule Execjs.Escape do
2+
@compile :native
3+
4+
def escape(""), do: ""
5+
6+
def escape(string) do
7+
iolist_to_binary(escape(string, ""))
8+
end
9+
10+
escape_map = [
11+
{ ?\\, "\\\\" },
12+
{ ?", "\\\"" },
13+
{ ?\n, "\\n" },
14+
{ ?\r, "\\r" },
15+
# http://bclary.com/2004/11/07/#a-7.3
16+
{ "\x{2028}", "\\u2028" },
17+
{ "\x{2029}", "\\u2029" }
18+
]
19+
20+
lc { char, escaped } inlist escape_map do
21+
defp escape(<< unquote(char), rest :: binary >>, acc) do
22+
escape(rest, [acc, unquote(escaped)])
23+
end
24+
end
25+
26+
defp escape(<< char :: utf8, rest :: binary >>, acc) do
27+
escape(rest, [acc, char])
28+
end
29+
30+
defp escape(<<>>, acc) do
31+
acc
32+
end
33+
end

lib/execjs/runtimes.ex

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,24 @@ defmodule Execjs.Runtimes do
33

44
Module.register_attribute __MODULE__, :runtimes, accumulate: true
55

6-
defruntime JavaScriptCore,
7-
command: "/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc",
8-
runner: "jsc_runner.js.eex"
9-
106
defruntime Node,
117
command: "node",
128
runner: "node_runner.js.eex"
139

14-
def runtimes, do: @runtimes
10+
defruntime JavaScriptCore,
11+
command: "/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc",
12+
runner: "jsc_runner.js.eex"
13+
14+
def runtimes do
15+
unquote(Enum.reverse(@runtimes))
16+
end
1517

1618
def best_available do
1719
case :application.get_env(:execjs, :runtime) do
1820
{ :ok, runtime } ->
1921
runtime
2022
:undefined ->
21-
runtime = Enum.find(@runtimes, &(&1.available?)) || raise RuntimeUnavailable
23+
runtime = Enum.find(runtimes, &(&1.available?)) || raise RuntimeUnavailable
2224
:application.set_env(:execjs, :runtime, runtime)
2325
runtime
2426
end

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ defmodule Execjs.Mixfile do
1616
# Returns the list of dependencies in the format:
1717
# { :foobar, "~> 0.1", git: "https://github.com/elixir-lang/foobar.git" }
1818
defp deps do
19-
[ { :jazz, github: "meh/jazz" } ]
19+
[ { :jazz, github: "meh/jazz", tag: "v0.0.1" } ]
2020
end
2121
end

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[ "jazz": {:git, "git://github.com/meh/jazz.git", "efac8600723bdf338a356e5671007aa54a55f327", []} ]
1+
[ "jazz": {:git, "git://github.com/meh/jazz.git", "5b3fd0e3efd2c8445289bdbda2f93bb0d96ad169", [{:tag, "v0.0.1"}]} ]

test/execjs_test.exs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ defmodule ExecjsTest do
44
test "eval" do
55
# assert Execjs.eval("(function() { return 1 + 1; })();") == ["ok", 2]
66

7-
IO.inspect Execjs.eval(%S""")
8-
(function() {
7+
context = Execjs.compile(%S""")
98
function addOne(n) {
109
return n + 1;
1110
}
12-
13-
return addOne(3);
14-
})();
1511
"""
12+
13+
IO.inspect Execjs.call(context, "addOne", [3])
1614
end
1715
end

0 commit comments

Comments
 (0)