therubyrhino 1.72.5-jruby → 1.72.6-jruby
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/History.txt +5 -0
- data/README.rdoc +59 -1
- data/lib/rhino/context.rb +97 -11
- data/lib/rhino/java.rb +4 -1
- data/lib/rhino/native_function.rb +9 -0
- data/lib/rhino/native_object.rb +37 -3
- data/lib/rhino.rb +1 -1
- data/spec/rhino/context_spec.rb +36 -0
- data/spec/rhino/native_object_spec.rb +15 -0
- data/therubyrhino.gemspec +3 -3
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
=== 1.72.6 2009-11-30
|
2
|
+
* 2 major enhancements:
|
3
|
+
* evaluate an IO object such as a file or an socket input stream
|
4
|
+
* load javascript sources directly into the context with the file system
|
5
|
+
|
1
6
|
=== 1.72.5 2009-11-12
|
2
7
|
* 2 major enhancements:
|
3
8
|
* evaluate javascript with a ruby object as it's scope using Context#open(:with => object)
|
data/README.rdoc
CHANGED
@@ -21,7 +21,14 @@ Embed the Mozilla Rhino Javascript interpreter into Ruby
|
|
21
21
|
|
22
22
|
# evaluate some simple javascript
|
23
23
|
eval_js "7 * 6" #=> 42
|
24
|
-
|
24
|
+
|
25
|
+
# that's quick and dirty, but if you want more control over your
|
26
|
+
# environment, use a Context:
|
27
|
+
Rhino::Context.open do |cxt|
|
28
|
+
cxt['foo'] = "bar"
|
29
|
+
cxt.eval('foo') # => "bar"
|
30
|
+
end
|
31
|
+
|
25
32
|
# evaluate a ruby function from javascript
|
26
33
|
|
27
34
|
Rhino::Context.open do |context|
|
@@ -63,6 +70,57 @@ Embed the Mozilla Rhino Javascript interpreter into Ruby
|
|
63
70
|
Rhino::Context.open(:java => true) do |context|
|
64
71
|
context.eval("java.lang.System.exit()") #it's dangerous!
|
65
72
|
end
|
73
|
+
|
74
|
+
#limit the number of instructions that can be executed in order to prevent
|
75
|
+
#rogue scripts
|
76
|
+
Rhino::Context.open do |context|
|
77
|
+
context.instruction_limit = 100000
|
78
|
+
context.eval("while (true);") # => Error!
|
79
|
+
end
|
80
|
+
|
81
|
+
==== Different ways of loading javascript source
|
82
|
+
|
83
|
+
In addition to just evaluating strings, you can also use streams such as files.
|
84
|
+
|
85
|
+
# evaluate bytes read from any File/IO object:
|
86
|
+
File.open("mysource.js") do |file|
|
87
|
+
eval_js file, "mysource.js"
|
88
|
+
end
|
89
|
+
|
90
|
+
# or load it by filename
|
91
|
+
Rhino::Context.open do |context|
|
92
|
+
context.load("mysource.js")
|
93
|
+
end
|
94
|
+
|
95
|
+
=== Safe by default
|
96
|
+
|
97
|
+
The Ruby Rhino is designed to let you evaluate javascript as safely as possible unless you tell it to do something more
|
98
|
+
dangerous. The default context is a hermetically sealed javascript environment with only the standard javascript objects
|
99
|
+
and functions. Nothing from the ruby world is accessible at all.
|
100
|
+
|
101
|
+
For ruby objects that you explicitly embed into javascript, only the +public+ methods *defined in their classes* are
|
102
|
+
exposed by default. E.g.
|
103
|
+
|
104
|
+
class A
|
105
|
+
def a
|
106
|
+
"a"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class B < A
|
111
|
+
def b
|
112
|
+
"b"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
Rhino::Context.open do |cxt|
|
118
|
+
cxt['a'] = A.new
|
119
|
+
cxt['b'] = B.new
|
120
|
+
cxt.eval("a.a()") # => 'a'
|
121
|
+
cxt.eval("b.b()") # => 'b'
|
122
|
+
cxt.eval("b.a()") # => 'TypeError: undefined property 'a' is not a function'
|
123
|
+
end
|
66
124
|
|
67
125
|
== REQUIREMENTS:
|
68
126
|
|
data/lib/rhino/context.rb
CHANGED
@@ -1,12 +1,47 @@
|
|
1
1
|
module Rhino
|
2
2
|
|
3
|
+
# ==Overview
|
4
|
+
# All Javascript must be executed in a context which represents the execution environment in
|
5
|
+
# which scripts will run. The environment consists of the standard javascript objects
|
6
|
+
# and functions like Object, String, Array, etc... as well as any objects or functions which
|
7
|
+
# have been defined in it. e.g.
|
8
|
+
#
|
9
|
+
# Context.open do |cxt|
|
10
|
+
# cxt['num'] = 5
|
11
|
+
# cxt.eval('num + 5') #=> 10
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# == Multiple Contexts.
|
15
|
+
# The same object may appear in any number of contexts, but only one context may be executing javascript code
|
16
|
+
# in any given thread. If a new context is opened in a thread in which a context is already opened, the second
|
17
|
+
# context will "mask" the old context e.g.
|
18
|
+
#
|
19
|
+
# six = 6
|
20
|
+
# Context.open do |cxt|
|
21
|
+
# cxt['num'] = 5
|
22
|
+
# cxt.eval('num') # => 5
|
23
|
+
# Context.open do |cxt|
|
24
|
+
# cxt['num'] = 10
|
25
|
+
# cxt.eval('num') # => 10
|
26
|
+
# cxt.eval('++num') # => 11
|
27
|
+
# end
|
28
|
+
# cxt.eval('num') # => 5
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# == Notes
|
32
|
+
# While there are many similarities between Rhino::Context and Java::OrgMozillaJavascript::Context, they are not
|
33
|
+
# the same thing and should not be confused.
|
34
|
+
|
3
35
|
class Context
|
4
36
|
attr_reader :scope
|
5
37
|
|
6
38
|
class << self
|
7
|
-
|
39
|
+
|
40
|
+
# initalize a new context with a fresh set of standard objects. All operations on the context
|
41
|
+
# should be performed in the block that is passed.
|
42
|
+
def open(options = {}, &block)
|
8
43
|
ContextFactory.new.call do |native|
|
9
|
-
|
44
|
+
block.call(new(native, options))
|
10
45
|
end
|
11
46
|
end
|
12
47
|
|
@@ -29,33 +64,83 @@ module Rhino
|
|
29
64
|
end
|
30
65
|
end
|
31
66
|
|
67
|
+
# Read a value from the global scope of this context
|
32
68
|
def [](k)
|
33
69
|
@scope[k]
|
34
70
|
end
|
35
|
-
|
71
|
+
|
72
|
+
# Set a value in the global scope of this context. This value will be visible to all the
|
73
|
+
# javascript that is executed in this context.
|
36
74
|
def []=(k,v)
|
37
75
|
@scope[k] = v
|
38
76
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
77
|
+
|
78
|
+
# Evaluate a string of javascript in this context:
|
79
|
+
# * <tt>source</tt> - the javascript source code to evaluate. This can be either a string or an IO object.
|
80
|
+
# * <tt>source_name</tt> - associated name for this source code. Mainly useful for backtraces.
|
81
|
+
# * <tt>line_number</tt> - associate this number with the first line of executing source. Mainly useful for backtraces
|
82
|
+
def eval(source, source_name = "<eval>", line_number = 1)
|
42
83
|
begin
|
43
84
|
scope = To.javascript(@scope)
|
44
|
-
|
85
|
+
if IO === source || StringIO === source
|
86
|
+
result = @native.evaluateReader(scope, IOReader.new(source), source_name, line_number, nil)
|
87
|
+
else
|
88
|
+
result = @native.evaluateString(scope, source.to_s, source_name, line_number, nil)
|
89
|
+
end
|
45
90
|
To.ruby result
|
46
91
|
rescue J::RhinoException => e
|
47
92
|
raise Rhino::RhinoError, e
|
48
93
|
end
|
49
94
|
end
|
50
|
-
|
95
|
+
|
96
|
+
# Read the contents of <tt>filename</tt> and evaluate it as javascript. Returns the result of evaluating the
|
97
|
+
# javascript. e.g.
|
98
|
+
#
|
99
|
+
# Context.open do |cxt|
|
100
|
+
# cxt.load("path/to/some/lib.js")
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
def load(filename)
|
104
|
+
File.open(filename) do |file|
|
105
|
+
eval file, filename, 1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Set the maximum number of instructions that this context will execute.
|
110
|
+
# If this instruction limit is exceeded, then a Rhino::RunawayScriptError
|
111
|
+
# will be raised
|
51
112
|
def instruction_limit=(limit)
|
52
113
|
@native.setInstructionObserverThreshold(limit);
|
53
114
|
@native.factory.instruction_limit = limit
|
54
115
|
end
|
55
116
|
|
56
117
|
end
|
118
|
+
|
119
|
+
class IOReader < Java::JavaIo::Reader #:nodoc:
|
120
|
+
|
121
|
+
def initialize(io)
|
122
|
+
@io = io
|
123
|
+
end
|
124
|
+
|
125
|
+
def read(charbuffer, offset, length)
|
126
|
+
begin
|
127
|
+
str = @io.read(length)
|
128
|
+
if str.nil?
|
129
|
+
return -1
|
130
|
+
else
|
131
|
+
jstring = Java::JavaLang::String.new(str)
|
132
|
+
for i in 0 .. jstring.length - 1
|
133
|
+
charbuffer[i + offset] = jstring.charAt(i)
|
134
|
+
end
|
135
|
+
return jstring.length
|
136
|
+
end
|
137
|
+
rescue StandardError => e
|
138
|
+
raise Java::JavaIo::IOException.new, "Failed reading from ruby IO object"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
57
142
|
|
58
|
-
class ContextFactory < J::ContextFactory
|
143
|
+
class ContextFactory < J::ContextFactory # :nodoc:
|
59
144
|
|
60
145
|
def observeInstructionCount(cxt, count)
|
61
146
|
raise RunawayScriptError, "script exceeded allowable instruction count" if count > @limit
|
@@ -67,7 +152,7 @@ module Rhino
|
|
67
152
|
end
|
68
153
|
|
69
154
|
|
70
|
-
class RhinoError < StandardError
|
155
|
+
class RhinoError < StandardError # :nodoc:
|
71
156
|
def initialize(native)
|
72
157
|
@native = native
|
73
158
|
end
|
@@ -81,5 +166,6 @@ module Rhino
|
|
81
166
|
end
|
82
167
|
end
|
83
168
|
|
84
|
-
class RunawayScriptError < StandardError
|
169
|
+
class RunawayScriptError < StandardError # :nodoc:
|
170
|
+
end
|
85
171
|
end
|
data/lib/rhino/java.rb
CHANGED
@@ -2,13 +2,16 @@ require 'java'
|
|
2
2
|
require 'rhino/rhino-1.7R2.jar'
|
3
3
|
|
4
4
|
module Rhino
|
5
|
+
# This module contains all the native Rhino objects implemented in Java
|
6
|
+
# e.g.
|
7
|
+
# Rhino::J::NativeObject # => org.mozilla.javascript.NativeObject
|
5
8
|
module J
|
6
9
|
import "org.mozilla.javascript"
|
7
10
|
end
|
8
11
|
end
|
9
12
|
|
10
13
|
unless Object.method_defined?(:tap)
|
11
|
-
class Object
|
14
|
+
class Object #:nodoc:
|
12
15
|
def tap
|
13
16
|
yield self
|
14
17
|
self
|
@@ -1,5 +1,14 @@
|
|
1
1
|
|
2
2
|
module Rhino
|
3
|
+
|
4
|
+
# Wraps a function that has been defined in Javascript so that it can
|
5
|
+
# be referenced and called from javascript. e.g.
|
6
|
+
#
|
7
|
+
# plus = Rhino::Context.open do |cx|
|
8
|
+
# cx.eval('function(lhs, rhs) {return lhs + rhs}')
|
9
|
+
# end
|
10
|
+
# plus.call(5,4) # => 9
|
11
|
+
#
|
3
12
|
class NativeFunction < NativeObject
|
4
13
|
def call(*args)
|
5
14
|
begin
|
data/lib/rhino/native_object.rb
CHANGED
@@ -1,27 +1,60 @@
|
|
1
1
|
|
2
2
|
module Rhino
|
3
|
+
# Wraps a javascript object and makes its properties available from ruby.
|
3
4
|
class NativeObject
|
4
5
|
include Enumerable
|
6
|
+
|
7
|
+
# The native java object wrapped by this NativeObject. This will generally
|
8
|
+
# be an instance of org.mozilla.javascript.Scriptable
|
5
9
|
attr_reader :j
|
6
10
|
|
7
|
-
def initialize(j)
|
11
|
+
def initialize(j) # :nodoc:
|
8
12
|
@j = j
|
9
13
|
end
|
10
14
|
|
15
|
+
# get a property from this javascript object, where +k+ is a string or symbol
|
16
|
+
# corresponding to the property name
|
17
|
+
# e.g.
|
18
|
+
# jsobject = Context.open do |cxt|
|
19
|
+
# cxt.eval('({foo: 'bar', 'Take me to': 'a funky town'})')
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# jsobject[:foo] # => 'bar'
|
23
|
+
# jsobject['foo'] # => 'bar'
|
24
|
+
# jsobject['Take me to'] # => 'a funky town'
|
11
25
|
def [](k)
|
12
|
-
To.ruby @j
|
26
|
+
To.ruby J::ScriptableObject.getProperty(@j,k.to_s)
|
13
27
|
end
|
14
28
|
|
29
|
+
# set a property on the javascript object, where +k+ is a string or symbol corresponding
|
30
|
+
# to the property name, and +v+ is the value to set. e.g.
|
31
|
+
#
|
32
|
+
# jsobject = eval_js "new Object()"
|
33
|
+
# jsobject['foo'] = 'bar'
|
34
|
+
# Context.open(:with => jsobject) do |cxt|
|
35
|
+
# cxt.eval('foo') # => 'bar'
|
36
|
+
# end
|
37
|
+
|
15
38
|
def []=(k,v)
|
16
|
-
|
39
|
+
#@j.put(k.to_s,@j,To.javascript(v))
|
40
|
+
J::ScriptableObject.putProperty(@j, k.to_s, To.javascript(v))
|
17
41
|
end
|
18
42
|
|
43
|
+
# enumerate the key value pairs contained in this javascript object. e.g.
|
44
|
+
#
|
45
|
+
# eval_js("{foo: 'bar', baz: 'bang'}").each do |key,value|
|
46
|
+
# puts "#{key} -> #{value} "
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# outputs foo -> bar baz -> bang
|
19
50
|
def each
|
20
51
|
for id in @j.getAllIds() do
|
21
52
|
yield id,@j.get(id,@j)
|
22
53
|
end
|
23
54
|
end
|
24
55
|
|
56
|
+
# Converts the native object to a hash. This isn't really a stretch since it's
|
57
|
+
# pretty much a hash in the first place.
|
25
58
|
def to_h
|
26
59
|
{}.tap do |h|
|
27
60
|
each do |k,v|
|
@@ -30,6 +63,7 @@ module Rhino
|
|
30
63
|
end
|
31
64
|
end
|
32
65
|
|
66
|
+
# Convert this javascript object into a json string.
|
33
67
|
def to_json(*args)
|
34
68
|
to_h.to_json(*args)
|
35
69
|
end
|
data/lib/rhino.rb
CHANGED
data/spec/rhino/context_spec.rb
CHANGED
@@ -123,4 +123,40 @@ describe Rhino::Context do
|
|
123
123
|
Context.new(nil)
|
124
124
|
}.should raise_error
|
125
125
|
end
|
126
|
+
|
127
|
+
describe "loading javascript source into the interpreter" do
|
128
|
+
|
129
|
+
it "can take an IO object in the eval method instead of a string" do
|
130
|
+
source = StringIO.new(<<-EOJS)
|
131
|
+
/*
|
132
|
+
* we want to have a fairly verbose function so that we can be assured tha
|
133
|
+
* we overflow the buffer size so that we see that the reader is chunking
|
134
|
+
* it's payload in at least several fragments.
|
135
|
+
*
|
136
|
+
* That's why we're wasting space here
|
137
|
+
*/
|
138
|
+
function five() {
|
139
|
+
return 5
|
140
|
+
}
|
141
|
+
foo = 'bar'
|
142
|
+
five();
|
143
|
+
EOJS
|
144
|
+
Context.open do |cxt|
|
145
|
+
cxt.eval(source, "StringIO").should == 5
|
146
|
+
cxt['foo'].should == "bar"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
it "can load a file into the runtime" do
|
151
|
+
mock(:JavascriptSourceFile).tap do |file|
|
152
|
+
File.should_receive(:open).with("path/to/mysource.js").and_yield(file)
|
153
|
+
Context.open do |cxt|
|
154
|
+
cxt.should_receive(:eval).with(file, "path/to/mysource.js", 1)
|
155
|
+
cxt.load("path/to/mysource.js")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
126
162
|
end
|
@@ -27,6 +27,18 @@ describe Rhino::NativeObject do
|
|
27
27
|
it "returns nil when the value is null, null, or not defined" do
|
28
28
|
@o[:foo].should be_nil
|
29
29
|
end
|
30
|
+
|
31
|
+
|
32
|
+
it "traverses the prototype chain when hash accessing properties from the ruby object" do
|
33
|
+
Rhino::Context.open do |cxt|
|
34
|
+
cxt.eval(<<EOJS)['bar'].should == "baz"
|
35
|
+
function Foo() {}
|
36
|
+
Foo.prototype.bar = 'baz'
|
37
|
+
new Foo()
|
38
|
+
EOJS
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
30
42
|
|
31
43
|
describe Enumerable do
|
32
44
|
it "enumerates according to native keys and values" do
|
@@ -35,6 +47,9 @@ describe Rhino::NativeObject do
|
|
35
47
|
@j.put(5, @j, 'flip')
|
36
48
|
@o.inject({}) {|i,p| k,v = p; i.tap {i[k] = v}}.should == {"foo" => 'bar', "bang" => 'baz', 5 => 'flip'}
|
37
49
|
end
|
50
|
+
|
51
|
+
it "should traverse prototype chain when enumerating keys and values"
|
52
|
+
|
38
53
|
end
|
39
54
|
|
40
55
|
end
|
data/therubyrhino.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{therubyrhino}
|
5
|
-
s.version = "1.72.
|
5
|
+
s.version = "1.72.6"
|
6
6
|
s.platform = %q{jruby}
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
9
|
s.authors = ["Charles Lowell"]
|
10
|
-
s.date = %q{2009-11-
|
10
|
+
s.date = %q{2009-11-30}
|
11
11
|
s.description = %q{Embed the Mozilla Rhino Javascript interpreter into Ruby}
|
12
12
|
s.email = ["cowboyd@thefrontside.net"]
|
13
13
|
s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
|
14
|
-
s.files = ["History.txt", "Manifest.txt", "README.rdoc", "Rakefile", "lib/rhino.rb", "lib/rhino/context.rb", "lib/rhino/java.rb", "lib/rhino/native_function.rb", "lib/rhino/native_object.rb", "lib/rhino/rhino-1.7R2.jar", "lib/rhino/ruby_function.rb", "lib/rhino/ruby_object.rb", "lib/rhino/wormhole.rb", "script/console", "script/destroy", "script/generate", "spec/rhino/context_spec.rb", "spec/rhino/native_object_spec.rb", "spec/rhino/ruby_object_spec.rb", "spec/rhino/wormhole_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/jruby.rake", "tasks/rspec.rake", "therubyrhino.gemspec"]
|
14
|
+
s.files = ["History.txt", "Manifest.txt", "README.rdoc", "Rakefile", "lib/rhino.rb", "lib/rhino/context.rb", "lib/rhino/java.rb", "lib/rhino/native_function.rb", "lib/rhino/native_object.rb", "lib/rhino/object.rb", "lib/rhino/rhino-1.7R2.jar", "lib/rhino/ruby_function.rb", "lib/rhino/ruby_object.rb", "lib/rhino/wormhole.rb", "script/console", "script/destroy", "script/generate", "spec/rhino/context_spec.rb", "spec/rhino/native_object_spec.rb", "spec/rhino/ruby_object_spec.rb", "spec/rhino/wormhole_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/jruby.rake", "tasks/rspec.rake", "therubyrhino.gemspec"]
|
15
15
|
s.homepage = %q{http://github.com/cowboyd/therubyrhino}
|
16
16
|
s.rdoc_options = ["--main", "README.rdoc"]
|
17
17
|
s.require_paths = ["lib"]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: therubyrhino
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.72.
|
4
|
+
version: 1.72.6
|
5
5
|
platform: jruby
|
6
6
|
authors:
|
7
7
|
- Charles Lowell
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-30 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|