therubyrhino 1.73.1 → 1.73.2
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.
- data/.gitignore +1 -0
- data/.travis.yml +6 -0
- data/README.rdoc +55 -7
- data/Rakefile +5 -1
- data/lib/rhino/context.rb +159 -22
- data/lib/rhino/error.rb +13 -8
- data/lib/rhino/rhino_ext.rb +5 -5
- data/lib/rhino/ruby.rb +1 -1
- data/lib/rhino/ruby/attribute_access.rb +8 -6
- data/lib/rhino/version.rb +1 -1
- data/lib/rhino/wormhole.rb +9 -2
- data/spec/rhino/context_spec.rb +74 -0
- data/spec/rhino/error_spec.rb +29 -4
- data/spec/rhino/wormhole_spec.rb +44 -4
- data/therubyrhino.gemspec +1 -1
- metadata +5 -4
data/.travis.yml
ADDED
data/README.rdoc
CHANGED
@@ -47,18 +47,18 @@ Embed the Mozilla Rhino Javascript interpreter into Ruby
|
|
47
47
|
|
48
48
|
Rhino::Context.open do |context|
|
49
49
|
context["math"] = MyMath.new
|
50
|
-
context.eval("math.plus(20,22)") #=> 42
|
50
|
+
context.eval("math.plus(20, 22)") #=> 42
|
51
51
|
end
|
52
52
|
|
53
53
|
# make a ruby object *be* your javascript environment
|
54
54
|
math = MyMath.new
|
55
55
|
Rhino::Context.open(:with => math) do |context|
|
56
|
-
context.eval("plus(20,22)") #=> 42
|
56
|
+
context.eval("plus(20, 22)") #=> 42
|
57
57
|
end
|
58
58
|
|
59
59
|
#or the equivalent
|
60
60
|
|
61
|
-
math.eval_js("plus(20,22)")
|
61
|
+
math.eval_js("plus(20, 22)")
|
62
62
|
|
63
63
|
# Configure your embedding setup
|
64
64
|
|
@@ -69,14 +69,25 @@ Embed the Mozilla Rhino Javascript interpreter into Ruby
|
|
69
69
|
|
70
70
|
#Turn on Java integration from javascript (probably a bad idea)
|
71
71
|
Rhino::Context.open(:java => true) do |context|
|
72
|
-
context.eval("java.lang.System.exit()") #it's dangerous!
|
72
|
+
context.eval("java.lang.System.exit()") # it's dangerous!
|
73
73
|
end
|
74
74
|
|
75
75
|
#limit the number of instructions that can be executed in order to prevent
|
76
76
|
#rogue scripts
|
77
|
-
Rhino::Context.open do |context|
|
77
|
+
Rhino::Context.open(:restrictable => true) do |context|
|
78
78
|
context.instruction_limit = 100000
|
79
|
-
context.eval("while (true);") # =>
|
79
|
+
context.eval("while (true);") # => Rhino::RunawayScriptError
|
80
|
+
end
|
81
|
+
|
82
|
+
#limit the time a script executes
|
83
|
+
#rogue scripts
|
84
|
+
Rhino::Context.open(:restrictable => true, :java => true) do |context|
|
85
|
+
context.timeout_limit = 1.5 # seconds
|
86
|
+
context.eval %Q{
|
87
|
+
for (var i = 0; i < 100; i++) {
|
88
|
+
java.lang.Thread.sleep(100);
|
89
|
+
}
|
90
|
+
} # => Rhino::ScriptTimeoutError
|
80
91
|
end
|
81
92
|
|
82
93
|
==== Different ways of loading javascript source
|
@@ -93,6 +104,43 @@ In addition to just evaluating strings, you can also use streams such as files.
|
|
93
104
|
context.load("mysource.js")
|
94
105
|
end
|
95
106
|
|
107
|
+
==== Configurable Ruby access
|
108
|
+
|
109
|
+
By default accessing Ruby objects from javascript is compatible with therubyracer:
|
110
|
+
https://github.com/cowboyd/therubyracer/wiki/Accessing-Ruby-Objects-From-JavaScript
|
111
|
+
|
112
|
+
Thus you end-up calling arbitrary no-arg methods as if they were javascript properties,
|
113
|
+
since instance accessors (properties) and methods (functions) are indistinguishable:
|
114
|
+
|
115
|
+
Rhino::Context.open do |context|
|
116
|
+
context['Time'] = Time
|
117
|
+
context.eval('Time.now')
|
118
|
+
end
|
119
|
+
|
120
|
+
However, you can customize this behavior and there's another access implementation
|
121
|
+
that attempts to mirror only attributes as properties as close as possible:
|
122
|
+
|
123
|
+
class Foo
|
124
|
+
attr_accessor :bar
|
125
|
+
|
126
|
+
def initialize
|
127
|
+
@bar = "bar"
|
128
|
+
end
|
129
|
+
|
130
|
+
def check_bar
|
131
|
+
bar == "bar"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
Rhino::Ruby::Scriptable.access = Rhino::Ruby::AttributeAccess
|
136
|
+
Rhino::Context.open do |context|
|
137
|
+
context['Foo'] = Foo
|
138
|
+
context.eval('var foo = new Foo()')
|
139
|
+
context.eval('foo.bar') # get property using reader
|
140
|
+
context.eval('foo.bar = null') # set property using writer
|
141
|
+
context.eval('foo.check_bar()') # called like a function
|
142
|
+
end
|
143
|
+
|
96
144
|
=== Safe by default
|
97
145
|
|
98
146
|
The Ruby Rhino is designed to let you evaluate javascript as safely as possible unless you tell it to do something more
|
@@ -135,7 +183,7 @@ exposed by default. E.g.
|
|
135
183
|
|
136
184
|
(The MIT License)
|
137
185
|
|
138
|
-
Copyright (c) 2009 Charles Lowell
|
186
|
+
Copyright (c) 2009-2012 Charles Lowell
|
139
187
|
|
140
188
|
Permission is hereby granted, free of charge, to any person obtaining
|
141
189
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
data/lib/rhino/context.rb
CHANGED
@@ -46,9 +46,18 @@ module Rhino
|
|
46
46
|
def eval(javascript)
|
47
47
|
new.eval(javascript)
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
|
+
@@default_factory = nil
|
53
|
+
def self.default_factory
|
54
|
+
@@default_factory ||= ContextFactory.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.default_factory=(factory)
|
58
|
+
@@default_factory = factory
|
59
|
+
end
|
60
|
+
|
52
61
|
attr_reader :scope
|
53
62
|
|
54
63
|
# Create a new javascript environment for executing javascript and ruby code.
|
@@ -56,8 +65,9 @@ module Rhino
|
|
56
65
|
# * <tt>:with</tt> - use this ruby object as the root scope for all javascript that is evaluated
|
57
66
|
# * <tt>:java</tt> - if true, java packages will be accessible from within javascript
|
58
67
|
def initialize(options = {}) #:nodoc:
|
59
|
-
|
60
|
-
|
68
|
+
factory = options[:factory] ||
|
69
|
+
(options[:restrictable] ? RestrictableContextFactory.instance : self.class.default_factory)
|
70
|
+
factory.call do |context|
|
61
71
|
@native = context
|
62
72
|
@global = @native.initStandardObjects(nil, options[:sealed] == true)
|
63
73
|
if with = options[:with]
|
@@ -73,7 +83,12 @@ module Rhino
|
|
73
83
|
end
|
74
84
|
end
|
75
85
|
end
|
76
|
-
|
86
|
+
|
87
|
+
# Returns the ContextFactory used while creating this context.
|
88
|
+
def factory
|
89
|
+
@native.getFactory
|
90
|
+
end
|
91
|
+
|
77
92
|
# Read a value from the global scope of this context
|
78
93
|
def [](key)
|
79
94
|
@scope[key]
|
@@ -117,14 +132,44 @@ module Rhino
|
|
117
132
|
end
|
118
133
|
end
|
119
134
|
|
135
|
+
# Returns true if this context supports restrictions.
|
136
|
+
def restrictable?
|
137
|
+
@native.is_a?(RestrictableContextFactory::Context)
|
138
|
+
end
|
139
|
+
|
140
|
+
def instruction_limit
|
141
|
+
restrictable? ? @native.instruction_limit : false
|
142
|
+
end
|
143
|
+
|
120
144
|
# Set the maximum number of instructions that this context will execute.
|
121
|
-
# If this instruction limit is exceeded, then a Rhino::RunawayScriptError
|
122
|
-
# will be raised
|
145
|
+
# If this instruction limit is exceeded, then a #Rhino::RunawayScriptError
|
146
|
+
# will be raised.
|
123
147
|
def instruction_limit=(limit)
|
124
|
-
|
125
|
-
|
148
|
+
if restrictable?
|
149
|
+
@native.instruction_limit = limit
|
150
|
+
else
|
151
|
+
raise "setting an instruction_limit has no effect on this context, use " +
|
152
|
+
"Context.open(:restricted => true) to gain a restrictable instance"
|
153
|
+
end
|
126
154
|
end
|
127
155
|
|
156
|
+
def timeout_limit
|
157
|
+
restrictable? ? @native.timeout_limit : false
|
158
|
+
end
|
159
|
+
|
160
|
+
# Set the duration (in seconds e.g. 1.5) this context is allowed to execute.
|
161
|
+
# After the timeout passes (no matter if any JS has been evaluated) and this
|
162
|
+
# context is still attempted to run code, a #Rhino::ScriptTimeoutError will
|
163
|
+
# be raised.
|
164
|
+
def timeout_limit=(limit)
|
165
|
+
if restrictable?
|
166
|
+
@native.timeout_limit = limit
|
167
|
+
else
|
168
|
+
raise "setting an timeout_limit has no effect on this context, use " +
|
169
|
+
"Context.open(:restricted => true) to gain a restrictable instance"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
128
173
|
def optimization_level
|
129
174
|
@native.getOptimizationLevel
|
130
175
|
end
|
@@ -134,7 +179,7 @@ module Rhino
|
|
134
179
|
# By using the -1 optimization level, you tell Rhino to run in interpretative mode,
|
135
180
|
# taking a hit to performance but escaping the Java bytecode limit.
|
136
181
|
def optimization_level=(level)
|
137
|
-
if
|
182
|
+
if JS::Context.isValidOptimizationLevel(level)
|
138
183
|
@native.setOptimizationLevel(level)
|
139
184
|
level
|
140
185
|
else
|
@@ -157,13 +202,12 @@ module Rhino
|
|
157
202
|
def version=(version)
|
158
203
|
const = version.to_s.gsub('.', '_').upcase
|
159
204
|
const = "VERSION_#{const}" if const[0, 7] != 'VERSION'
|
160
|
-
|
161
|
-
|
162
|
-
const_value = js_context.const_get(const)
|
205
|
+
if JS::Context.constants.find { |c| c.to_s == const }
|
206
|
+
const_value = JS::Context.const_get(const)
|
163
207
|
@native.setLanguageVersion(const_value)
|
164
208
|
const_value
|
165
209
|
else
|
166
|
-
@native.setLanguageVersion(
|
210
|
+
@native.setLanguageVersion(JS::Context::VERSION_DEFAULT)
|
167
211
|
nil
|
168
212
|
end
|
169
213
|
end
|
@@ -179,11 +223,11 @@ module Rhino
|
|
179
223
|
private
|
180
224
|
|
181
225
|
def do_open
|
226
|
+
factory.enterContext(@native)
|
182
227
|
begin
|
183
|
-
@factory.enterContext(@native)
|
184
228
|
yield self
|
185
229
|
ensure
|
186
|
-
|
230
|
+
factory.exit
|
187
231
|
end
|
188
232
|
end
|
189
233
|
|
@@ -216,22 +260,115 @@ module Rhino
|
|
216
260
|
|
217
261
|
end
|
218
262
|
|
219
|
-
|
263
|
+
ContextFactory = JS::ContextFactory # :nodoc: backward compatibility
|
220
264
|
|
221
|
-
|
222
|
-
|
265
|
+
class RestrictableContextFactory < ContextFactory # :nodoc:
|
266
|
+
|
267
|
+
@@instance = nil
|
268
|
+
def self.instance
|
269
|
+
@@instance ||= new
|
270
|
+
end
|
271
|
+
|
272
|
+
# protected Context makeContext()
|
273
|
+
def makeContext
|
274
|
+
Context.new(self)
|
223
275
|
end
|
276
|
+
|
277
|
+
# protected void observeInstructionCount(Context context, int instructionCount)
|
278
|
+
def observeInstructionCount(context, count)
|
279
|
+
context.check!(count) if context.is_a?(Context)
|
280
|
+
end
|
281
|
+
|
282
|
+
# protected Object doTopCall(Callable callable, Context context,
|
283
|
+
# Scriptable scope, Scriptable thisObj, Object[] args)
|
284
|
+
def doTopCall(callable, context, scope, this, args)
|
285
|
+
context.reset! if context.is_a?(Context)
|
286
|
+
super
|
287
|
+
end
|
288
|
+
|
289
|
+
class Context < JS::Context # :nodoc:
|
290
|
+
|
291
|
+
def initialize(factory)
|
292
|
+
super(factory)
|
293
|
+
reset!
|
294
|
+
end
|
224
295
|
|
225
|
-
|
226
|
-
|
296
|
+
attr_reader :instruction_limit
|
297
|
+
|
298
|
+
def instruction_limit=(limit)
|
299
|
+
treshold = getInstructionObserverThreshold
|
300
|
+
if limit && (treshold == 0 || treshold > limit)
|
301
|
+
setInstructionObserverThreshold(limit)
|
302
|
+
end
|
303
|
+
@instruction_limit = limit
|
304
|
+
end
|
305
|
+
|
306
|
+
attr_reader :instruction_count
|
307
|
+
|
308
|
+
TIMEOUT_INSTRUCTION_TRESHOLD = 42
|
309
|
+
|
310
|
+
attr_reader :timeout_limit
|
311
|
+
|
312
|
+
def timeout_limit=(limit) # in seconds
|
313
|
+
treshold = getInstructionObserverThreshold
|
314
|
+
if limit && (treshold == 0 || treshold > TIMEOUT_INSTRUCTION_TRESHOLD)
|
315
|
+
setInstructionObserverThreshold(TIMEOUT_INSTRUCTION_TRESHOLD)
|
316
|
+
end
|
317
|
+
@timeout_limit = limit
|
318
|
+
end
|
319
|
+
|
320
|
+
attr_reader :start_time
|
321
|
+
|
322
|
+
def check!(count = nil)
|
323
|
+
@instruction_count += count if count
|
324
|
+
check_instruction_limit!
|
325
|
+
check_timeout_limit!(count)
|
326
|
+
end
|
327
|
+
|
328
|
+
def check_instruction_limit!
|
329
|
+
if instruction_limit && instruction_count > instruction_limit
|
330
|
+
raise RunawayScriptError, "script exceeded allowable instruction count: #{instruction_limit}"
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def check_timeout_limit!(count = nil)
|
335
|
+
if timeout_limit
|
336
|
+
elapsed_time = Time.now.to_f - start_time.to_f
|
337
|
+
if elapsed_time > timeout_limit
|
338
|
+
raise ScriptTimeoutError, "script exceeded timeout: #{timeout_limit} seconds"
|
339
|
+
end
|
340
|
+
# adapt instruction treshold as needed :
|
341
|
+
if count
|
342
|
+
treshold = getInstructionObserverThreshold
|
343
|
+
if elapsed_time * 2 < timeout_limit
|
344
|
+
next_treshold_guess = treshold * 2
|
345
|
+
if instruction_limit && instruction_limit < next_treshold_guess
|
346
|
+
setInstructionObserverThreshold(instruction_limit)
|
347
|
+
else
|
348
|
+
setInstructionObserverThreshold(next_treshold_guess)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def reset!
|
356
|
+
@instruction_count = 0
|
357
|
+
@start_time = Time.now
|
358
|
+
self
|
359
|
+
end
|
360
|
+
|
227
361
|
end
|
228
362
|
|
229
363
|
end
|
230
|
-
|
364
|
+
|
231
365
|
class ContextError < StandardError # :nodoc:
|
232
366
|
end
|
233
367
|
|
234
368
|
class RunawayScriptError < ContextError # :nodoc:
|
235
369
|
end
|
370
|
+
|
371
|
+
class ScriptTimeoutError < ContextError # :nodoc:
|
372
|
+
end
|
236
373
|
|
237
374
|
end
|
data/lib/rhino/error.rb
CHANGED
@@ -5,14 +5,8 @@ module Rhino
|
|
5
5
|
|
6
6
|
def initialize(native)
|
7
7
|
@native = native # NativeException wrapping a Java Throwable
|
8
|
-
|
9
|
-
|
10
|
-
def message
|
11
|
-
cause ? cause.details : @native.to_s
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_s
|
15
|
-
super
|
8
|
+
message = value ? value : ( cause ? cause.details : @native )
|
9
|
+
super(message)
|
16
10
|
end
|
17
11
|
|
18
12
|
# most likely a Rhino::JS::JavaScriptException
|
@@ -20,6 +14,17 @@ module Rhino
|
|
20
14
|
@native.respond_to?(:cause) ? @native.cause : nil
|
21
15
|
end
|
22
16
|
|
17
|
+
def value
|
18
|
+
return @value if defined?(@value)
|
19
|
+
if cause.respond_to?(:value) # e.g. JavaScriptException.getValue
|
20
|
+
@value = cause.value
|
21
|
+
elsif ( unwrap = self.unwrap ) && unwrap.respond_to?(:value)
|
22
|
+
@value = unwrap.value
|
23
|
+
else
|
24
|
+
@value = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
23
28
|
def unwrap
|
24
29
|
return @unwrap if defined?(@unwrap)
|
25
30
|
cause = self.cause
|
data/lib/rhino/rhino_ext.rb
CHANGED
@@ -87,11 +87,11 @@ class Java::OrgMozillaJavascript::ScriptableObject
|
|
87
87
|
|
88
88
|
# Delegate methods to JS object if possible when called from Ruby.
|
89
89
|
def method_missing(name, *args)
|
90
|
-
|
91
|
-
if
|
92
|
-
self[
|
90
|
+
name_str = name.to_s
|
91
|
+
if name_str[-1, 1] == '=' && args.size == 1 # writer -> JS put
|
92
|
+
self[ name_str[0...-1] ] = args[0]
|
93
93
|
else
|
94
|
-
if property = self[
|
94
|
+
if property = self[name_str]
|
95
95
|
if property.is_a?(Rhino::JS::Function)
|
96
96
|
begin
|
97
97
|
context = Rhino::JS::Context.enter
|
@@ -103,7 +103,7 @@ class Java::OrgMozillaJavascript::ScriptableObject
|
|
103
103
|
end
|
104
104
|
else
|
105
105
|
if args.size > 0
|
106
|
-
raise ArgumentError, "can't #{
|
106
|
+
raise ArgumentError, "can't call '#{name_str}' with args: #{args.inspect} as it's a property"
|
107
107
|
end
|
108
108
|
Rhino.to_ruby property
|
109
109
|
end
|
data/lib/rhino/ruby.rb
CHANGED
@@ -32,7 +32,7 @@ module Rhino
|
|
32
32
|
ids = []
|
33
33
|
unwrap.public_methods(false).each do |name|
|
34
34
|
name = name[0...-1] if name[-1, 1] == '=' # 'foo=' ... 'foo'
|
35
|
-
name = name.to_java # java.lang.String
|
35
|
+
name = name.to_s.to_java # java.lang.String
|
36
36
|
ids << name unless ids.include?(name)
|
37
37
|
end
|
38
38
|
super.each { |id| ids.unshift(id) }
|
@@ -4,7 +4,7 @@ module Rhino
|
|
4
4
|
|
5
5
|
def self.has(object, name, scope)
|
6
6
|
if object.respond_to?(name.to_s) ||
|
7
|
-
object.respond_to?("#{name}=") # might have a writer but no reader
|
7
|
+
object.respond_to?(:"#{name}=") # might have a writer but no reader
|
8
8
|
return true
|
9
9
|
end
|
10
10
|
# try [](name) method :
|
@@ -15,10 +15,12 @@ module Rhino
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.get(object, name, scope)
|
18
|
-
|
19
|
-
|
18
|
+
name_sym = name.to_s.to_sym
|
19
|
+
if object.respond_to?(name_sym)
|
20
|
+
method = object.method(name_sym)
|
20
21
|
if method.arity == 0 && # check if it is an attr_reader
|
21
|
-
( object.respond_to?("#{name}=") ||
|
22
|
+
( object.respond_to?(:"#{name}=") ||
|
23
|
+
object.instance_variables.find { |var| var.to_sym == :"@#{name}" } )
|
22
24
|
begin
|
23
25
|
return Rhino.to_javascript(method.call, scope)
|
24
26
|
rescue => e
|
@@ -27,7 +29,7 @@ module Rhino
|
|
27
29
|
else
|
28
30
|
return Function.wrap(method.unbind)
|
29
31
|
end
|
30
|
-
elsif object.respond_to?("#{name}=")
|
32
|
+
elsif object.respond_to?(:"#{name}=")
|
31
33
|
return nil # it does have the property but is non readable
|
32
34
|
end
|
33
35
|
# try [](name) method :
|
@@ -40,7 +42,7 @@ module Rhino
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def self.put(object, name, value)
|
43
|
-
if object.respond_to?(set_name = "#{name}=")
|
45
|
+
if object.respond_to?(set_name = :"#{name}=")
|
44
46
|
return object.send(set_name, Rhino.to_ruby(value))
|
45
47
|
end
|
46
48
|
# try []=(name, value) method :
|
data/lib/rhino/version.rb
CHANGED
data/lib/rhino/wormhole.rb
CHANGED
@@ -43,10 +43,17 @@ module Rhino
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def array_to_javascript(rb_array, scope = nil)
|
46
|
+
# First convert all array elements to their javascript equivalents and
|
47
|
+
# then invoke to_java below in order to create a Java array. This allows
|
48
|
+
# arrays with nested hashes to be converted properly.
|
49
|
+
converted_rb_array = rb_array.map do |rb_element|
|
50
|
+
to_javascript(rb_element, scope)
|
51
|
+
end
|
52
|
+
|
46
53
|
if scope && context = JS::Context.getCurrentContext
|
47
|
-
context.newArray(scope,
|
54
|
+
context.newArray(scope, converted_rb_array.to_java)
|
48
55
|
else
|
49
|
-
JS::NativeArray.new(
|
56
|
+
JS::NativeArray.new(converted_rb_array.to_java)
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
data/spec/rhino/context_spec.rb
CHANGED
@@ -65,5 +65,79 @@ describe Rhino::Context do
|
|
65
65
|
context.version = '1.7'
|
66
66
|
context.version.should == 1.7
|
67
67
|
end
|
68
|
+
|
69
|
+
it "should have a (shared) factory by default" do
|
70
|
+
context1 = Rhino::Context.new
|
71
|
+
context1.factory.should_not be nil
|
72
|
+
context1.factory.should be_a(Rhino::JS::ContextFactory)
|
73
|
+
|
74
|
+
context1.factory.should be Rhino::Context.default_factory
|
75
|
+
|
76
|
+
context2 = Rhino::Context.new
|
77
|
+
context2.factory.should be context1.factory
|
78
|
+
end
|
79
|
+
|
80
|
+
it "allows limiting instruction count" do
|
81
|
+
context = Rhino::Context.new :restrictable => true
|
82
|
+
context.instruction_limit = 100
|
83
|
+
lambda {
|
84
|
+
context.eval %Q{ for (var i = 0; i < 100; i++) Number(i).toString(); }
|
85
|
+
}.should raise_error(Rhino::RunawayScriptError)
|
86
|
+
|
87
|
+
context.instruction_limit = nil
|
88
|
+
lambda {
|
89
|
+
context.eval %Q{ for (var i = 0; i < 100; i++) Number(i).toString(); }
|
90
|
+
}.should_not raise_error(Rhino::RunawayScriptError)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "allows a timeout limit per context" do
|
94
|
+
context1 = Rhino::Context.new :restrictable => true, :java => true
|
95
|
+
context1.timeout_limit = 0.3
|
96
|
+
|
97
|
+
context2 = Rhino::Context.new :restrictable => true, :java => true
|
98
|
+
context2.timeout_limit = 0.3
|
99
|
+
|
100
|
+
lambda {
|
101
|
+
context2.eval %Q{
|
102
|
+
var notDone = true;
|
103
|
+
(function foo() {
|
104
|
+
if (notDone) {
|
105
|
+
notDone = false;
|
106
|
+
java.lang.Thread.sleep(300);
|
107
|
+
foo();
|
108
|
+
}
|
109
|
+
})();
|
110
|
+
}
|
111
|
+
}.should raise_error(Rhino::ScriptTimeoutError)
|
112
|
+
|
113
|
+
lambda {
|
114
|
+
context1.eval %Q{
|
115
|
+
var notDone = true;
|
116
|
+
(function foo {
|
117
|
+
if (notDone) {
|
118
|
+
notDone = false;
|
119
|
+
java.lang.Thread.sleep(100);
|
120
|
+
foo();
|
121
|
+
}
|
122
|
+
})();
|
123
|
+
}
|
124
|
+
}.should_not raise_error(Rhino::RunawayScriptError)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "allows instruction and timeout limits at the same time" do
|
128
|
+
context = Rhino::Context.new :restrictable => true, :java => true
|
129
|
+
context.timeout_limit = 0.5
|
130
|
+
context.instruction_limit = 10000
|
131
|
+
lambda {
|
132
|
+
context.eval %Q{ for (var i = 0; i < 100; i++) { java.lang.Thread.sleep(100); } }
|
133
|
+
}.should raise_error(Rhino::ScriptTimeoutError)
|
134
|
+
|
135
|
+
context = Rhino::Context.new :restrictable => true, :java => true
|
136
|
+
context.timeout_limit = 0.5
|
137
|
+
context.instruction_limit = 1000
|
138
|
+
lambda {
|
139
|
+
context.eval %Q{ for (var i = 0; i < 100; i++) { java.lang.Thread.sleep(10); } }
|
140
|
+
}.should raise_error(Rhino::RunawayScriptError)
|
141
|
+
end
|
68
142
|
|
69
143
|
end
|
data/spec/rhino/error_spec.rb
CHANGED
@@ -6,9 +6,9 @@ describe Rhino::JSError do
|
|
6
6
|
js_error = Rhino::JSError.new 'an error message'
|
7
7
|
lambda { js_error.to_s && js_error.inspect }.should_not raise_error
|
8
8
|
|
9
|
-
js_error.cause.should
|
9
|
+
js_error.cause.should be nil
|
10
10
|
js_error.message.should == 'an error message'
|
11
|
-
js_error.javascript_backtrace.should
|
11
|
+
js_error.javascript_backtrace.should be nil
|
12
12
|
end
|
13
13
|
|
14
14
|
it "might wrap a RhinoException wrapped in a NativeException like error" do
|
@@ -30,9 +30,34 @@ describe Rhino::JSError do
|
|
30
30
|
js_error = Rhino::JSError.new native_error_class.new(rhino_e)
|
31
31
|
lambda { js_error.to_s && js_error.inspect }.should_not raise_error
|
32
32
|
|
33
|
-
js_error.cause.should be
|
33
|
+
js_error.cause.should be rhino_e
|
34
34
|
js_error.message.should == '42'
|
35
|
-
js_error.javascript_backtrace.should_not
|
35
|
+
js_error.javascript_backtrace.should_not be nil
|
36
|
+
end
|
37
|
+
|
38
|
+
it "keeps the thrown javascript object value" do
|
39
|
+
begin
|
40
|
+
Rhino::Context.eval "throw { foo: 'bar' }"
|
41
|
+
rescue => e
|
42
|
+
e.should be_a(Rhino::JSError)
|
43
|
+
e.value.should be_a(Rhino::JS::NativeObject)
|
44
|
+
e.value['foo'].should == 'bar'
|
45
|
+
e.value.should == e.message
|
46
|
+
else
|
47
|
+
fail "expected to rescue"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "keeps the thrown javascript string value" do
|
52
|
+
begin
|
53
|
+
Rhino::Context.eval "throw 'mehehehe'"
|
54
|
+
rescue => e
|
55
|
+
e.should be_a(Rhino::JSError)
|
56
|
+
e.value.should == 'mehehehe'
|
57
|
+
e.value.should == e.message
|
58
|
+
else
|
59
|
+
fail "expected to rescue"
|
60
|
+
end
|
36
61
|
end
|
37
62
|
|
38
63
|
end
|
data/spec/rhino/wormhole_spec.rb
CHANGED
@@ -91,6 +91,46 @@ describe Rhino::To do
|
|
91
91
|
h.prototype.should be_nil # this is how Rhino works !
|
92
92
|
end
|
93
93
|
end
|
94
|
+
|
95
|
+
it "converts deeply nested ruby hashes into native objects" do
|
96
|
+
hash = {
|
97
|
+
:array => [
|
98
|
+
{
|
99
|
+
:breed => "Pug"
|
100
|
+
},
|
101
|
+
{
|
102
|
+
:breed => "English Bulldog"
|
103
|
+
},
|
104
|
+
{
|
105
|
+
:breed => [
|
106
|
+
"Pug",
|
107
|
+
"Beagle"
|
108
|
+
]
|
109
|
+
}
|
110
|
+
]
|
111
|
+
}
|
112
|
+
|
113
|
+
Rhino.to_javascript(hash).tap do |h|
|
114
|
+
h.should be_kind_of(Rhino::JS::NativeObject)
|
115
|
+
|
116
|
+
a = h.get("array", h)
|
117
|
+
a.should be_kind_of(Rhino::JS::NativeArray)
|
118
|
+
|
119
|
+
element0 = a.get(0,a)
|
120
|
+
element0.should be_kind_of(Rhino::JS::NativeObject)
|
121
|
+
element0.get("breed", element0).should == "Pug"
|
122
|
+
|
123
|
+
element2 = a.get(2,a)
|
124
|
+
element2.should be_kind_of(Rhino::JS::NativeObject)
|
125
|
+
|
126
|
+
nested_array = element2.get("breed", element2)
|
127
|
+
nested_array.should be_kind_of(Rhino::JS::NativeArray)
|
128
|
+
nested_array.get(0,nested_array).should == "Pug"
|
129
|
+
nested_array.get(1,nested_array).should == "Beagle"
|
130
|
+
|
131
|
+
h.prototype.should be_nil # this is how Rhino works !
|
132
|
+
end
|
133
|
+
end
|
94
134
|
|
95
135
|
describe "with a scope" do
|
96
136
|
|
@@ -132,12 +172,12 @@ describe Rhino::To do
|
|
132
172
|
it "converts procs and methods into native functions" do
|
133
173
|
Rhino.to_javascript(lambda {|lhs,rhs| lhs * rhs}).tap do |f|
|
134
174
|
f.should be_kind_of(Rhino::JS::Function)
|
135
|
-
f.call(nil, nil, nil, [7,6]).should be(42)
|
175
|
+
f.call(nil, nil, nil, [7, 6].to_java).should be(42)
|
136
176
|
end
|
137
177
|
|
138
|
-
Rhino.to_javascript("foo,bar,baz".method(:split)).tap do |
|
139
|
-
|
140
|
-
Rhino.to_ruby(
|
178
|
+
Rhino.to_javascript("foo,bar,baz".method(:split)).tap do |f|
|
179
|
+
f.should be_kind_of(Rhino::JS::Function)
|
180
|
+
Rhino.to_ruby(f.call(nil, nil, nil, [','].to_java)).should == ['foo', 'bar', 'baz']
|
141
181
|
end
|
142
182
|
end
|
143
183
|
|
data/therubyrhino.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.summary = %q{Embed the Rhino JavaScript interpreter into JRuby}
|
17
17
|
|
18
18
|
s.add_development_dependency "rake"
|
19
|
-
s.add_development_dependency "rspec"
|
19
|
+
s.add_development_dependency "rspec", ">= 2.7"
|
20
20
|
s.add_development_dependency "mocha"
|
21
21
|
s.add_development_dependency "jruby-openssl"
|
22
22
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: therubyrhino
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.73.
|
5
|
+
version: 1.73.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Charles Lowell
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-04-11 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: "
|
33
|
+
version: "2.7"
|
34
34
|
requirement: *id002
|
35
35
|
prerelease: false
|
36
36
|
type: :development
|
@@ -67,6 +67,7 @@ extra_rdoc_files:
|
|
67
67
|
files:
|
68
68
|
- .gitignore
|
69
69
|
- .gitmodules
|
70
|
+
- .travis.yml
|
70
71
|
- Gemfile
|
71
72
|
- History.txt
|
72
73
|
- README.rdoc
|
@@ -124,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
125
|
requirements: []
|
125
126
|
|
126
127
|
rubyforge_project: therubyrhino
|
127
|
-
rubygems_version: 1.8.
|
128
|
+
rubygems_version: 1.8.15
|
128
129
|
signing_key:
|
129
130
|
specification_version: 3
|
130
131
|
summary: Embed the Rhino JavaScript interpreter into JRuby
|