dienashorner 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/LICENSE +201 -0
- data/README.md +157 -0
- data/Rakefile +18 -0
- data/dienashorner.gemspec +24 -0
- data/lib/nashorn/context.rb +188 -0
- data/lib/nashorn/convert.rb +57 -0
- data/lib/nashorn/error.rb +105 -0
- data/lib/nashorn/ext.rb +201 -0
- data/lib/nashorn/rhino/less.rb +84 -0
- data/lib/nashorn/rhino.rb +34 -0
- data/lib/nashorn/ruby/access.rb +68 -0
- data/lib/nashorn/ruby/attribute_access.rb +41 -0
- data/lib/nashorn/ruby/default_access.rb +37 -0
- data/lib/nashorn/ruby.rb +361 -0
- data/lib/nashorn/version.rb +3 -0
- data/lib/nashorn.rb +37 -0
- data/spec/nashorn/access_spec.rb +122 -0
- data/spec/nashorn/error_spec.rb +199 -0
- data/spec/nashorn/integration/bar.js +11 -0
- data/spec/nashorn/integration/foo.js +7 -0
- data/spec/nashorn/integration/index.js +7 -0
- data/spec/nashorn/integration/loop/element1.js +3 -0
- data/spec/nashorn/integration/loop/element2.js +8 -0
- data/spec/nashorn/integration/loop.js +3 -0
- data/spec/nashorn/integration_spec.rb +149 -0
- data/spec/nashorn/ruby_spec.rb +352 -0
- data/spec/nashorn_spec.rb +23 -0
- data/spec/spec_helper.rb +38 -0
- metadata +105 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Nashorn::JSError do
|
4
|
+
|
5
|
+
it "works as a StandardError with a message being passed" do
|
6
|
+
js_error = Nashorn::JSError.new 'an error message'
|
7
|
+
lambda { js_error.to_s && js_error.inspect }.should_not raise_error
|
8
|
+
|
9
|
+
js_error.cause.should be nil
|
10
|
+
js_error.message.should == 'an error message'
|
11
|
+
js_error.javascript_backtrace.should be nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# it "might wrap a NashornException wrapped in a NativeException like error" do
|
15
|
+
# # JRuby's NativeException.new(Nashorn_e) does not work as it is
|
16
|
+
# # intended to handle Java exceptions ... no new on the Ruby side
|
17
|
+
# native_error_class = Class.new(RuntimeError) do
|
18
|
+
# def initialize(cause); @cause = cause end
|
19
|
+
# def cause; @cause end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# nashorn_e = javax.script.ScriptException.new("42".to_java)
|
23
|
+
# js_error = Nashorn::JSError.new native_error_class.new(nashorn_e)
|
24
|
+
# lambda { js_error.to_s && js_error.inspect }.should_not raise_error
|
25
|
+
#
|
26
|
+
# js_error.cause.should be nashorn_e
|
27
|
+
# js_error.message.should == '42'
|
28
|
+
# js_error.javascript_backtrace.should be nil
|
29
|
+
# end
|
30
|
+
|
31
|
+
it "keeps the thrown javascript object value" do
|
32
|
+
begin
|
33
|
+
Nashorn::Context.eval "throw { foo: 'bar' }"
|
34
|
+
rescue => e
|
35
|
+
e.should be_a(Nashorn::JSError)
|
36
|
+
e.message.should == e.value.to_s
|
37
|
+
|
38
|
+
pending
|
39
|
+
|
40
|
+
puts e.value.inspect
|
41
|
+
puts e.value.class
|
42
|
+
puts e.value.class.included_modules.inspect
|
43
|
+
puts e.value.class.superclass
|
44
|
+
puts e.value.class.superclass.included_modules.inspect
|
45
|
+
|
46
|
+
e.value.should be_a(Nashorn::JS::JSObject)
|
47
|
+
e.value['foo'].should == 'bar'
|
48
|
+
else
|
49
|
+
fail "expected to rescue"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it "keeps the thrown javascript string value" do
|
54
|
+
begin
|
55
|
+
Nashorn::Context.eval "throw 'mehehehe'"
|
56
|
+
rescue => e
|
57
|
+
e.should be_a(Nashorn::JSError)
|
58
|
+
e.value.should == 'mehehehe'
|
59
|
+
e.message.should == e.value.to_s
|
60
|
+
else
|
61
|
+
fail "expected to rescue"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "contains the native error as the cause 42" do
|
66
|
+
begin
|
67
|
+
Nashorn::Context.eval "throw 42"
|
68
|
+
rescue => e # javax.script.ScriptException
|
69
|
+
e.cause.should_not be nil
|
70
|
+
e.cause.should be_a Java::JdkNashornInternalRuntime::ECMAException
|
71
|
+
e.cause.value.should == 42
|
72
|
+
e.cause.lineNumber.should == 1
|
73
|
+
e.cause.fileName.should == '<eval>'
|
74
|
+
else
|
75
|
+
fail "expected to rescue"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "has a correct javascript backtrace" do
|
80
|
+
begin
|
81
|
+
Nashorn::Context.eval "throw 42"
|
82
|
+
rescue => e
|
83
|
+
#
|
84
|
+
e.javascript_backtrace.should be_a Enumerable
|
85
|
+
e.javascript_backtrace.size.should >= 1
|
86
|
+
e.javascript_backtrace[0].should =~ /.*?<eval>:1/
|
87
|
+
e.javascript_backtrace(true).should be_a Enumerable
|
88
|
+
e.javascript_backtrace(true).size.should >= 1
|
89
|
+
element = e.javascript_backtrace(true)[0]
|
90
|
+
element.file_name.should == '<eval>'
|
91
|
+
# element.function_name.should be nil
|
92
|
+
element.line_number.should == 1
|
93
|
+
else
|
94
|
+
fail "expected to rescue"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it "contains function name in javascript backtrace" do
|
99
|
+
begin
|
100
|
+
Nashorn::Context.eval "function fortyTwo() { throw 42 }\n fortyTwo()"
|
101
|
+
rescue => e
|
102
|
+
# ["<<eval>>.fortyTwo(<eval>:1)", "<<eval>>.<program>(<eval>:2)"]
|
103
|
+
e.javascript_backtrace.size.should >= 2
|
104
|
+
e.javascript_backtrace[0].should =~ /fortyTwo\(<eval>:1\)/
|
105
|
+
expect( e.javascript_backtrace.find { |trace| trace.index("<eval>:2") } ).to_not be nil
|
106
|
+
else
|
107
|
+
fail "expected to rescue"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "backtrace starts with the javascript part" do
|
112
|
+
begin
|
113
|
+
Nashorn::Context.eval "throw 42"
|
114
|
+
rescue => e
|
115
|
+
e.backtrace.should be_a Array
|
116
|
+
e.backtrace[0].should =~ /.*?<eval>:1/
|
117
|
+
e.backtrace[1].should_not be nil
|
118
|
+
else
|
119
|
+
fail "expected to rescue"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it "inspect shows the javascript value" do
|
124
|
+
begin
|
125
|
+
Nashorn::Context.eval "throw '42'"
|
126
|
+
rescue => e
|
127
|
+
e.inspect.should == '#<Nashorn::JSError: 42>'
|
128
|
+
e.to_s.should == '42'
|
129
|
+
else
|
130
|
+
fail "expected to rescue"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "wrapps false value correctly" do
|
135
|
+
begin
|
136
|
+
Nashorn::Context.eval "throw false"
|
137
|
+
rescue => e
|
138
|
+
e.inspect.should == '#<Nashorn::JSError: false>'
|
139
|
+
e.value.should be false
|
140
|
+
else
|
141
|
+
fail "expected to rescue"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "wrapps null value correctly" do
|
146
|
+
begin
|
147
|
+
Nashorn::Context.eval "throw null"
|
148
|
+
rescue => e
|
149
|
+
e.inspect.should == '#<Nashorn::JSError: null>'
|
150
|
+
e.value.should be nil
|
151
|
+
else
|
152
|
+
fail "expected to rescue"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it "raises correct error from function#apply" do
|
157
|
+
begin
|
158
|
+
context = Nashorn::Context.new
|
159
|
+
context.eval "function foo() { throw 'bar' }"
|
160
|
+
context['foo'].apply(nil)
|
161
|
+
rescue => e
|
162
|
+
e.should be_a Nashorn::JSError
|
163
|
+
e.value.should == 'bar'
|
164
|
+
else
|
165
|
+
fail "expected to rescue"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it "prints info about nested (ruby) error" do
|
170
|
+
context = Nashorn::Context.new
|
171
|
+
klass = Class.new do
|
172
|
+
def hello(arg = 42)
|
173
|
+
raise RuntimeError, 'hello' if arg != 42
|
174
|
+
end
|
175
|
+
end
|
176
|
+
context[:Hello] = klass.new
|
177
|
+
hi = context.eval "( function hi(arg) { Hello.hello(arg); } )"
|
178
|
+
begin
|
179
|
+
hi.call(24)
|
180
|
+
rescue => e
|
181
|
+
e.should be_a Nashorn::JSError
|
182
|
+
e.value.should_not be nil
|
183
|
+
# Java::JdkNashornInternalObjects::NativeTypeError
|
184
|
+
# e.value.should be_a Nashorn::Ruby::Object
|
185
|
+
# e.value(true).should be_a RuntimeError # unwraps ruby object
|
186
|
+
# prints the original message (beyond [ruby RuntimeError]) :
|
187
|
+
e.message.should =~ /TypeError: .* has no such function \"hello\"/
|
188
|
+
else
|
189
|
+
fail "expected to rescue"
|
190
|
+
end
|
191
|
+
# Nashorn::JSError:
|
192
|
+
# jdk.nashorn.internal.objects.NativeTypeError@52719fb6
|
193
|
+
# # <<eval>>.hi(<eval>:1)
|
194
|
+
# # <jdk/nashorn/internal/scripts/<eval>>.hi(jdk/nashorn/internal/scripts/<eval>:1)
|
195
|
+
# # ./lib/nashorn/ext.rb:157:in `call'
|
196
|
+
# # ./spec/nashorn/error_spec.rb:179:in `(root)'
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
//console.log('bar.js 1');
|
2
|
+
var util = require('util');
|
3
|
+
//console.log('bar.js 2');
|
4
|
+
var Bar = {};
|
5
|
+
Bar.puts = function (message) {
|
6
|
+
util.puts(message);
|
7
|
+
return message;
|
8
|
+
};
|
9
|
+
//console.log('bar.js 3');
|
10
|
+
exports.Bar = Bar;
|
11
|
+
//console.log('bar.js 4');
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'nashorn'
|
2
|
+
require 'nashorn/context'
|
3
|
+
require 'pathname'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
puts "Nashorn #{Nashorn::VERSION}"
|
7
|
+
|
8
|
+
describe 'integration' do
|
9
|
+
|
10
|
+
it "Less.js: loads (less.rb)" do
|
11
|
+
require 'nashorn/rhino/less'
|
12
|
+
require 'less'
|
13
|
+
|
14
|
+
expect( Less.Parser ).to be_a(Nashorn::JS::ScriptObjectMirror)
|
15
|
+
# exposes less.tree e.g. for attaching custom functions
|
16
|
+
Less.tree.functions['foo'] = lambda { |*args| 'bar' }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "CommonJS: require foo" do # CommonJS
|
20
|
+
environment = new_environment(:console => Console)
|
21
|
+
environment.native 'util', Util.new(out = StringIO.new)
|
22
|
+
exports = environment.require 'foo'
|
23
|
+
out.string.should == "Hello Bar!\n"
|
24
|
+
|
25
|
+
exports.should_not be nil
|
26
|
+
exports.foo.should respond_to(:'[]')
|
27
|
+
exports.foo['Bar'].should respond_to(:'[]')
|
28
|
+
exports.foo['Bar'][:puts].should be_a Nashorn::JS::JSObject # Rhino::JS::Function
|
29
|
+
end
|
30
|
+
|
31
|
+
it "CommonJS: require index/loop" do # CommonJS
|
32
|
+
environment = new_environment(:console => Console)
|
33
|
+
environment.require 'index'
|
34
|
+
environment.context['Loop'].should_not be nil
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def new_environment(globals = {})
|
40
|
+
context = Nashorn::Context.new
|
41
|
+
globals.each { |key, obj| context[key] = obj }
|
42
|
+
path = Pathname(__FILE__).dirname.join('integration')
|
43
|
+
Env.new(context, :path => path.to_s)
|
44
|
+
end
|
45
|
+
|
46
|
+
class Env # a CommonJS like environment (inspired by commonjs.rb)
|
47
|
+
|
48
|
+
attr_reader :context, :modules
|
49
|
+
|
50
|
+
def initialize(context, options = {})
|
51
|
+
@context = context
|
52
|
+
@paths = [ options[:path] ].flatten.map { |path| Pathname(path) }
|
53
|
+
@modules = {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def require(module_id)
|
57
|
+
unless mod = modules[module_id]
|
58
|
+
filepath = find(module_id) or fail LoadError, "no such module '#{module_id}'"
|
59
|
+
js = "( function(module, require, exports) {\n#{File.read(filepath)}\n} )"
|
60
|
+
load = context.eval(js, filepath.expand_path.to_s)
|
61
|
+
modules[module_id] = mod = Module.new(module_id, self)
|
62
|
+
load.call(mod, mod.require_function, mod.exports)
|
63
|
+
end
|
64
|
+
return mod.exports
|
65
|
+
end
|
66
|
+
|
67
|
+
def native(module_id, impl)
|
68
|
+
modules[module_id] = Module::Native.new(impl)
|
69
|
+
end
|
70
|
+
|
71
|
+
def new_object
|
72
|
+
context['Object'].new
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def find(module_id)
|
78
|
+
if loadpath = @paths.find { |path| path.join("#{module_id}.js").exist? }
|
79
|
+
loadpath.join("#{module_id}.js")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class Module
|
84
|
+
|
85
|
+
attr_reader :id, :exports
|
86
|
+
|
87
|
+
def initialize(id, env)
|
88
|
+
@id, @env = id, env
|
89
|
+
@exports = env.new_object
|
90
|
+
@segments = id.split('/')
|
91
|
+
end
|
92
|
+
|
93
|
+
def require_function
|
94
|
+
@require_function ||= lambda do |*args|
|
95
|
+
this, module_id = *args
|
96
|
+
module_id ||= this #backwards compatibility with TRR < 0.10
|
97
|
+
@env.require(expand(module_id))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def expand(module_id)
|
104
|
+
return module_id unless module_id =~ /(\.|\..)/
|
105
|
+
module_id.split('/').inject(@segments[0..-2]) do |path, element|
|
106
|
+
path.tap do
|
107
|
+
if element == '.'
|
108
|
+
# do nothing
|
109
|
+
elsif element == '..'
|
110
|
+
path.pop
|
111
|
+
else
|
112
|
+
path.push element
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end.join('/')
|
116
|
+
end
|
117
|
+
|
118
|
+
class Native
|
119
|
+
|
120
|
+
def initialize(impl); @impl = impl; end
|
121
|
+
def exports; @impl; end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
class Util
|
130
|
+
|
131
|
+
def initialize(io = STDOUT)
|
132
|
+
@io = io
|
133
|
+
end
|
134
|
+
|
135
|
+
def puts(*args)
|
136
|
+
args.each { |arg| @io.puts(arg) }
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
class Console
|
142
|
+
|
143
|
+
def self.log(*msgs)
|
144
|
+
puts msgs.join(', ')
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|