Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 159 lines (135 sloc) 3.926 kb
0be476d @sstephenson Extract ExecJS::Runtime
authored
1 require "tempfile"
2
3 module ExecJS
c5e22c4 @sstephenson Runtime -> ExternalRuntime
authored
4 class ExternalRuntime
82773bf @josh Context
josh authored
5 class Context
c595c07 @josh Remove pure evaluation
josh authored
6 def initialize(runtime, source = "")
82773bf @josh Context
josh authored
7 @runtime = runtime
c595c07 @josh Remove pure evaluation
josh authored
8 @source = source
50791dd @josh Add Context#call
josh authored
9 end
10
4bc602f @josh Pure function hint
josh authored
11 def eval(source, options = {})
0b4977e @josh Try to convert to UTF8 early
josh authored
12 souce = source.encode('UTF-8') if source.respond_to?(:encode)
13
82773bf @josh Context
josh authored
14 if /\S/ =~ source
3097959 @josh Switch to multi_json lib
josh authored
15 exec("return eval(#{MultiJson.encode("(#{source})")})")
82773bf @josh Context
josh authored
16 end
17 end
18
4bc602f @josh Pure function hint
josh authored
19 def exec(source, options = {})
0b4977e @josh Try to convert to UTF8 early
josh authored
20 souce = source.encode('UTF-8') if source.respond_to?(:encode)
21
c595c07 @josh Remove pure evaluation
josh authored
22 compile_to_tempfile([@source, source].join("\n")) do |file|
0dc15c3 @josh Make runner_source and exec_runtime protected
josh authored
23 extract_result(@runtime.send(:exec_runtime, file.path))
82773bf @josh Context
josh authored
24 end
25 end
26
f815272 @sstephenson properties -> identifier
authored
27 def call(identifier, *args)
3097959 @josh Switch to multi_json lib
josh authored
28 eval "#{identifier}.apply(this, #{MultiJson.encode(args)})"
50791dd @josh Add Context#call
josh authored
29 end
30
82773bf @josh Context
josh authored
31 protected
32 def compile_to_tempfile(source)
a1277a6 @josh Style
josh authored
33 tempfile = Tempfile.open(['execjs', '.js'])
82773bf @josh Context
josh authored
34 tempfile.write compile(source)
35 tempfile.close
36 yield tempfile
37 ensure
38 tempfile.close!
39 end
40
41 def compile(source)
0dc15c3 @josh Make runner_source and exec_runtime protected
josh authored
42 @runtime.send(:runner_source).dup.tap do |output|
bd4c71c @josh Fix sub \ escaping
josh authored
43 output.sub!('#{source}') do
44 source
45 end
82773bf @josh Context
josh authored
46 output.sub!('#{json2_source}') do
47 IO.read(ExecJS.root + "/support/json2.js")
48 end
49 end
50 end
51
52 def extract_result(output)
3097959 @josh Switch to multi_json lib
josh authored
53 status, value = output.empty? ? [] : MultiJson.decode(output)
82773bf @josh Context
josh authored
54 if status == "ok"
55 value
56 else
57 raise ProgramError, value
58 end
59 end
60 end
61
d19c760 @sstephenson Less magic
authored
62 attr_reader :name
63
954db08 @sstephenson Instantiate with options instead of subclassing
authored
64 def initialize(options)
d19c760 @sstephenson Less magic
authored
65 @name = options[:name]
954db08 @sstephenson Instantiate with options instead of subclassing
authored
66 @command = options[:command]
67 @runner_path = options[:runner_path]
5d0d51b @sstephenson therubyracer gem installs an incompatible `v8` binary - make sure we …
authored
68 @test_args = options[:test_args]
69 @test_match = options[:test_match]
24a41df @josh Fix JSC encoding
josh authored
70 @conversion = options[:conversion]
c00ee39 @josh Support "nodejs" binary name
josh authored
71 @binary = locate_binary
954db08 @sstephenson Instantiate with options instead of subclassing
authored
72 end
73
82773bf @josh Context
josh authored
74 def exec(source)
75 context = Context.new(self)
c595c07 @josh Remove pure evaluation
josh authored
76 context.exec(source)
82773bf @josh Context
josh authored
77 end
78
0be476d @sstephenson Extract ExecJS::Runtime
authored
79 def eval(source)
82773bf @josh Context
josh authored
80 context = Context.new(self)
c595c07 @josh Remove pure evaluation
josh authored
81 context.eval(source)
0be476d @sstephenson Extract ExecJS::Runtime
authored
82 end
83
82773bf @josh Context
josh authored
84 def compile(source)
c595c07 @josh Remove pure evaluation
josh authored
85 Context.new(self, source)
c5e22c4 @sstephenson Runtime -> ExternalRuntime
authored
86 end
87
b22082f @sstephenson Add Runtime#available?
authored
88 def available?
3097959 @josh Switch to multi_json lib
josh authored
89 require "multi_json"
c00ee39 @josh Support "nodejs" binary name
josh authored
90 @binary ? true : false
b22082f @sstephenson Add Runtime#available?
authored
91 end
92
0dc15c3 @josh Make runner_source and exec_runtime protected
josh authored
93 protected
94 def runner_source
95 @runner_source ||= IO.read(@runner_path)
96 end
82773bf @josh Context
josh authored
97
0dc15c3 @josh Make runner_source and exec_runtime protected
josh authored
98 def exec_runtime(filename)
99 output = sh("#{@binary} #{filename} 2>&1")
100 if $?.success?
101 output
102 else
103 raise RuntimeError, output
104 end
82773bf @josh Context
josh authored
105 end
106
c00ee39 @josh Support "nodejs" binary name
josh authored
107 def locate_binary
3cf772e @sstephenson Add `which` support for Windows
authored
108 if binary = which(@command)
c00ee39 @josh Support "nodejs" binary name
josh authored
109 if @test_args
110 output = `#{binary} #{@test_args} 2>&1`
111 binary if output.match(@test_match)
112 else
113 binary
114 end
115 end
116 end
117
3cf772e @sstephenson Add `which` support for Windows
authored
118 def which(command)
612c95e @josh Fix external runtime which to return the expanded path
josh authored
119 Array(command).each do |name|
88fa6b7 @swaits Preserve command flags passed to which
swaits authored
120 name, args = name.split(/\s+/, 2)
3cf772e @sstephenson Add `which` support for Windows
authored
121 result = if ExecJS.windows?
122 `#{ExecJS.root}/support/which.bat #{name}`
123 else
0aad760 @josh Redirect which stderr to null
josh authored
124 `which #{name} 2>/dev/null`
3cf772e @sstephenson Add `which` support for Windows
authored
125 end
612c95e @josh Fix external runtime which to return the expanded path
josh authored
126
127 if path = result.strip.split("\n").first
88fa6b7 @swaits Preserve command flags passed to which
swaits authored
128 return args ? "#{path} #{args}" : path
612c95e @josh Fix external runtime which to return the expanded path
josh authored
129 end
3cf772e @sstephenson Add `which` support for Windows
authored
130 end
612c95e @josh Fix external runtime which to return the expanded path
josh authored
131 nil
3cf772e @sstephenson Add `which` support for Windows
authored
132 end
133
24a41df @josh Fix JSC encoding
josh authored
134 if "".respond_to?(:force_encoding)
135 def sh(command)
136 output, options = nil, {}
1781666 @josh Force UTF-8 on external encoding
josh authored
137 options[:external_encoding] = 'UTF-8'
24a41df @josh Fix JSC encoding
josh authored
138 options[:internal_encoding] = @conversion[:from] if @conversion
139 IO.popen(command, options) { |f| output = f.read }
140 output.force_encoding(@conversion[:to]) if @conversion
141 output
142 end
143 else
144 require "iconv"
145
146 def sh(command)
147 output = nil
148 IO.popen(command) { |f| output = f.read }
149
150 if @conversion
151 Iconv.iconv(@conversion[:from], @conversion[:to], output).first
152 else
153 output
154 end
155 end
156 end
0be476d @sstephenson Extract ExecJS::Runtime
authored
157 end
158 end
Something went wrong with that request. Please try again.