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 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
- def open(options = {})
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
- yield new(native, options)
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
- def eval(str)
41
- str = str.to_s
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
- result = @native.evaluateString(scope, str, "<eval>", 1, nil)
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; end
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
@@ -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.get(k.to_s, @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
- @j.put(k.to_s,@j,To.javascript(v))
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
@@ -3,7 +3,7 @@ $:.unshift(File.dirname(__FILE__)) unless
3
3
 
4
4
 
5
5
  module Rhino
6
- VERSION = '1.72.5'
6
+ VERSION = '1.72.6'
7
7
  require 'rhino/java'
8
8
  require 'rhino/object'
9
9
  require 'rhino/context'
@@ -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"
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-13}
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.5
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-13 00:00:00 -05:00
12
+ date: 2009-11-30 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency