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 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