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 CHANGED
@@ -1,4 +1,5 @@
1
1
  .idea
2
+ nbproject
2
3
  doc
3
4
  *.gem
4
5
  .rvmrc
@@ -0,0 +1,6 @@
1
+ rvm:
2
+ - jruby-18mode
3
+ - jruby-19mode
4
+ branches:
5
+ only:
6
+ - master
@@ -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);") # => Error!
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
@@ -8,4 +8,8 @@ task :clean do
8
8
  end
9
9
 
10
10
  require 'rspec/core/rake_task'
11
- RSpec::Core::RakeTask.new
11
+ RSpec::Core::RakeTask.new do |spec|
12
+ spec.rspec_opts = ['--color', "--format documentation"]
13
+ end
14
+
15
+ task :default => :spec
@@ -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
- @factory = ContextFactory.new
60
- @factory.call do |context|
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
- @native.setInstructionObserverThreshold(limit)
125
- @factory.instruction_limit = limit
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 @native.class.isValidOptimizationLevel(level)
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
- js_context = @native.class # Context
161
- if js_context.constants.include?(const)
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(js_context::VERSION_DEFAULT)
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
- JS::Context.exit
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
- class ContextFactory < JS::ContextFactory # :nodoc:
263
+ ContextFactory = JS::ContextFactory # :nodoc: backward compatibility
220
264
 
221
- def observeInstructionCount(cxt, count)
222
- raise RunawayScriptError, "script exceeded allowable instruction count" if count > @limit
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
- def instruction_limit=(count)
226
- @limit = count
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
@@ -5,14 +5,8 @@ module Rhino
5
5
 
6
6
  def initialize(native)
7
7
  @native = native # NativeException wrapping a Java Throwable
8
- end
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
@@ -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
- s_name = name.to_s
91
- if s_name[-1, 1] == '=' && args.size == 1 # writer -> JS put
92
- self[ s_name[0...-1] ] = args[0]
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[s_name]
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 #{name}(#{args.join(', ')}) as '#{name}' is a property"
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
@@ -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
- if object.respond_to?(name_s = name.to_s)
19
- method = object.method(name_s)
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}=") || object.instance_variables.include?("@#{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 :
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Rhino
3
- VERSION = "1.73.1"
3
+ VERSION = "1.73.2"
4
4
  end
@@ -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, rb_array.to_java)
54
+ context.newArray(scope, converted_rb_array.to_java)
48
55
  else
49
- JS::NativeArray.new(rb_array.to_java)
56
+ JS::NativeArray.new(converted_rb_array.to_java)
50
57
  end
51
58
  end
52
59
 
@@ -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
@@ -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 be_nil
9
+ js_error.cause.should be nil
10
10
  js_error.message.should == 'an error message'
11
- js_error.javascript_backtrace.should be_nil
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(rhino_e)
33
+ js_error.cause.should be rhino_e
34
34
  js_error.message.should == '42'
35
- js_error.javascript_backtrace.should_not be_nil
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
@@ -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 |m|
139
- m.should be_kind_of(Rhino::JS::Function)
140
- Rhino.to_ruby(m.call(nil, nil, nil, ',')).should == ['foo', 'bar', 'baz']
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
 
@@ -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.1
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-01-24 00:00:00 Z
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: "0"
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.9
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