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