Skip to content
Newer
Older
100644 159 lines (135 sloc) 3.89 KB
0be476d @sstephenson Extract ExecJS::Runtime
authored Feb 6, 2011
1 require "tempfile"
2
3 module ExecJS
c5e22c4 @sstephenson Runtime -> ExternalRuntime
authored Feb 6, 2011
4 class ExternalRuntime
82773bf @josh Context
josh authored Feb 11, 2011
5 class Context
c595c07 @josh Remove pure evaluation
josh authored Mar 10, 2011
6 def initialize(runtime, source = "")
82773bf @josh Context
josh authored Feb 11, 2011
7 @runtime = runtime
35064ed @lautis Encode initial source to UTF-8 when using external runtime
lautis authored Jun 5, 2011
8 @source = source.respond_to?(:encode) ? source.encode("UTF-8") : source
50791dd @josh Add Context#call
josh authored Feb 12, 2011
9 end
10
4bc602f @josh Pure function hint
josh authored Feb 11, 2011
11 def eval(source, options = {})
ae253df @lautis Fix typo in variable name
lautis authored Jun 5, 2011
12 source = source.encode('UTF-8') if source.respond_to?(:encode)
0b4977e @josh Try to convert to UTF8 early
josh authored May 12, 2011
13
82773bf @josh Context
josh authored Feb 11, 2011
14 if /\S/ =~ source
3097959 @josh Switch to multi_json lib
josh authored Apr 14, 2011
15 exec("return eval(#{MultiJson.encode("(#{source})")})")
82773bf @josh Context
josh authored Feb 11, 2011
16 end
17 end
18
4bc602f @josh Pure function hint
josh authored Feb 11, 2011
19 def exec(source, options = {})
ae253df @lautis Fix typo in variable name
lautis authored Jun 5, 2011
20 source = source.encode('UTF-8') if source.respond_to?(:encode)
0b4977e @josh Try to convert to UTF8 early
josh authored May 12, 2011
21
c595c07 @josh Remove pure evaluation
josh authored Mar 10, 2011
22 compile_to_tempfile([@source, source].join("\n")) do |file|
0dc15c3 @josh Make runner_source and exec_runtime protected
josh authored Mar 10, 2011
23 extract_result(@runtime.send(:exec_runtime, file.path))
82773bf @josh Context
josh authored Feb 11, 2011
24 end
25 end
26
f815272 @sstephenson properties -> identifier
authored Mar 10, 2011
27 def call(identifier, *args)
3097959 @josh Switch to multi_json lib
josh authored Apr 14, 2011
28 eval "#{identifier}.apply(this, #{MultiJson.encode(args)})"
50791dd @josh Add Context#call
josh authored Feb 12, 2011
29 end
30
82773bf @josh Context
josh authored Feb 11, 2011
31 protected
32 def compile_to_tempfile(source)
a1277a6 @josh Style
josh authored May 12, 2011
33 tempfile = Tempfile.open(['execjs', '.js'])
82773bf @josh Context
josh authored Feb 11, 2011
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 Mar 10, 2011
42 @runtime.send(:runner_source).dup.tap do |output|
bd4c71c @josh Fix sub \ escaping
josh authored Mar 10, 2011
43 output.sub!('#{source}') do
44 source
45 end
82773bf @josh Context
josh authored Feb 11, 2011
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 Apr 14, 2011
53 status, value = output.empty? ? [] : MultiJson.decode(output)
82773bf @josh Context
josh authored Feb 11, 2011
54 if status == "ok"
55 value
56 else
57 raise ProgramError, value
58 end
59 end
60 end
61
d19c760 @sstephenson Less magic
authored Feb 9, 2011
62 attr_reader :name
63
954db08 @sstephenson Instantiate with options instead of subclassing
authored Feb 6, 2011
64 def initialize(options)
d19c760 @sstephenson Less magic
authored Feb 10, 2011
65 @name = options[:name]
954db08 @sstephenson Instantiate with options instead of subclassing
authored Feb 7, 2011
66 @command = options[:command]
67 @runner_path = options[:runner_path]
5d0d51b @sstephenson therubyracer gem installs an incompatible `v8` binary - make sure we …
authored Feb 6, 2011
68 @test_args = options[:test_args]
69 @test_match = options[:test_match]
24a41df @josh Fix JSC encoding
josh authored Feb 10, 2011
70 @conversion = options[:conversion]
c00ee39 @josh Support "nodejs" binary name
josh authored Feb 7, 2011
71 @binary = locate_binary
954db08 @sstephenson Instantiate with options instead of subclassing
authored Feb 7, 2011
72 end
73
82773bf @josh Context
josh authored Feb 11, 2011
74 def exec(source)
75 context = Context.new(self)
c595c07 @josh Remove pure evaluation
josh authored Mar 10, 2011
76 context.exec(source)
82773bf @josh Context
josh authored Feb 11, 2011
77 end
78
0be476d @sstephenson Extract ExecJS::Runtime
authored Feb 7, 2011
79 def eval(source)
82773bf @josh Context
josh authored Feb 11, 2011
80 context = Context.new(self)
c595c07 @josh Remove pure evaluation
josh authored Mar 10, 2011
81 context.eval(source)
0be476d @sstephenson Extract ExecJS::Runtime
authored Feb 7, 2011
82 end
83
82773bf @josh Context
josh authored Feb 11, 2011
84 def compile(source)
c595c07 @josh Remove pure evaluation
josh authored Mar 10, 2011
85 Context.new(self, source)
c5e22c4 @sstephenson Runtime -> ExternalRuntime
authored Feb 7, 2011
86 end
87
b22082f @sstephenson Add Runtime#available?
authored Feb 6, 2011
88 def available?
3097959 @josh Switch to multi_json lib
josh authored Apr 14, 2011
89 require "multi_json"
c00ee39 @josh Support "nodejs" binary name
josh authored Feb 7, 2011
90 @binary ? true : false
b22082f @sstephenson Add Runtime#available?
authored Feb 7, 2011
91 end
92
0dc15c3 @josh Make runner_source and exec_runtime protected
josh authored Mar 10, 2011
93 protected
94 def runner_source
95 @runner_source ||= IO.read(@runner_path)
96 end
82773bf @josh Context
josh authored Feb 11, 2011
97
0dc15c3 @josh Make runner_source and exec_runtime protected
josh authored Mar 10, 2011
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 Feb 11, 2011
105 end
106
c00ee39 @josh Support "nodejs" binary name
josh authored Feb 7, 2011
107 def locate_binary
3cf772e @sstephenson Add `which` support for Windows
authored Feb 7, 2011
108 if binary = which(@command)
c00ee39 @josh Support "nodejs" binary name
josh authored Feb 7, 2011
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 Feb 7, 2011
118 def which(command)
612c95e @josh Fix external runtime which to return the expanded path
josh authored Apr 22, 2011
119 Array(command).each do |name|
88fa6b7 @swaits Preserve command flags passed to which
swaits authored May 5, 2011
120 name, args = name.split(/\s+/, 2)
3cf772e @sstephenson Add `which` support for Windows
authored Feb 7, 2011
121 result = if ExecJS.windows?
122 `#{ExecJS.root}/support/which.bat #{name}`
123 else
0aad760 @josh Redirect which stderr to null
josh authored Apr 22, 2011
124 `which #{name} 2>/dev/null`
3cf772e @sstephenson Add `which` support for Windows
authored Feb 7, 2011
125 end
612c95e @josh Fix external runtime which to return the expanded path
josh authored Apr 22, 2011
126
127 if path = result.strip.split("\n").first
88fa6b7 @swaits Preserve command flags passed to which
swaits authored May 5, 2011
128 return args ? "#{path} #{args}" : path
612c95e @josh Fix external runtime which to return the expanded path
josh authored Apr 22, 2011
129 end
3cf772e @sstephenson Add `which` support for Windows
authored Feb 7, 2011
130 end
612c95e @josh Fix external runtime which to return the expanded path
josh authored Apr 22, 2011
131 nil
3cf772e @sstephenson Add `which` support for Windows
authored Feb 7, 2011
132 end
133
24a41df @josh Fix JSC encoding
josh authored Feb 10, 2011
134 if "".respond_to?(:force_encoding)
135 def sh(command)
136 output, options = nil, {}
1781666 @josh Force UTF-8 on external encoding
josh authored May 18, 2011
137 options[:external_encoding] = 'UTF-8'
24a41df @josh Fix JSC encoding
josh authored Feb 10, 2011
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 Feb 7, 2011
157 end
158 end
Something went wrong with that request. Please try again.