therubyrhino 1.73.1 → 1.73.2

Sign up to get free protection for your applications and to get access to all the features.
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