2009-09-24 20:06:31 -04:00
|
|
|
module Rhino
|
2009-11-11 21:12:20 -05:00
|
|
|
|
2009-11-15 21:56:31 -05:00
|
|
|
# ==Overview
|
|
|
|
# All Javascript must be executed in a context which represents the execution environment in
|
|
|
|
# which scripts will run. The environment consists of the standard javascript objects
|
|
|
|
# and functions like Object, String, Array, etc... as well as any objects or functions which
|
|
|
|
# have been defined in it. e.g.
|
|
|
|
#
|
|
|
|
# Context.open do |cxt|
|
|
|
|
# cxt['num'] = 5
|
|
|
|
# cxt.eval('num + 5') #=> 10
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# == Multiple Contexts.
|
|
|
|
# The same object may appear in any number of contexts, but only one context may be executing javascript code
|
|
|
|
# in any given thread. If a new context is opened in a thread in which a context is already opened, the second
|
|
|
|
# context will "mask" the old context e.g.
|
|
|
|
#
|
|
|
|
# six = 6
|
|
|
|
# Context.open do |cxt|
|
|
|
|
# cxt['num'] = 5
|
|
|
|
# cxt.eval('num') # => 5
|
|
|
|
# Context.open do |cxt|
|
|
|
|
# cxt['num'] = 10
|
|
|
|
# cxt.eval('num') # => 10
|
|
|
|
# cxt.eval('++num') # => 11
|
|
|
|
# end
|
|
|
|
# cxt.eval('num') # => 5
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# == Notes
|
|
|
|
# While there are many similarities between Rhino::Context and Java::OrgMozillaJavascript::Context, they are not
|
|
|
|
# the same thing and should not be confused.
|
|
|
|
|
2009-11-11 21:12:20 -05:00
|
|
|
class Context
|
2009-11-11 01:50:36 -05:00
|
|
|
attr_reader :scope
|
2009-09-24 20:06:31 -04:00
|
|
|
|
|
|
|
class << self
|
2009-11-15 21:56:31 -05:00
|
|
|
|
|
|
|
# initalize a new context with a fresh set of standard objects. All operations on the context
|
|
|
|
# should be performed in the block that is passed.
|
|
|
|
def open(options = {}, &block)
|
2009-11-10 09:52:03 -05:00
|
|
|
ContextFactory.new.call do |native|
|
2009-11-15 21:56:31 -05:00
|
|
|
block.call(new(native, options))
|
2009-10-06 09:52:45 -04:00
|
|
|
end
|
|
|
|
end
|
2009-11-11 01:50:36 -05:00
|
|
|
|
2009-09-24 20:06:31 -04:00
|
|
|
private :new
|
|
|
|
end
|
|
|
|
|
2009-11-11 01:50:36 -05:00
|
|
|
def initialize(native, options) #:nodoc:
|
2009-09-24 20:06:31 -04:00
|
|
|
@native = native
|
2009-11-13 12:09:54 -05:00
|
|
|
@global = NativeObject.new(@native.initStandardObjects(nil, options[:sealed] == true))
|
|
|
|
if with = options[:with]
|
|
|
|
@scope = To.javascript(with)
|
|
|
|
@scope.setParentScope(@global.j)
|
|
|
|
else
|
|
|
|
@scope = @global
|
|
|
|
end
|
2009-11-11 01:50:36 -05:00
|
|
|
unless options[:java]
|
|
|
|
for package in ["Packages", "java", "org", "com"]
|
2009-11-13 12:09:54 -05:00
|
|
|
@global.j.delete(package)
|
2009-10-06 09:52:45 -04:00
|
|
|
end
|
2009-11-11 01:50:36 -05:00
|
|
|
end
|
2009-09-24 20:06:31 -04:00
|
|
|
end
|
|
|
|
|
2009-11-15 21:56:31 -05:00
|
|
|
# Read a value from the global scope of this context
|
2009-11-11 01:50:36 -05:00
|
|
|
def [](k)
|
|
|
|
@scope[k]
|
|
|
|
end
|
2009-11-15 21:56:31 -05:00
|
|
|
|
|
|
|
# Set a value in the global scope of this context. This value will be visible to all the
|
|
|
|
# javascript that is executed in this context.
|
2009-11-11 01:50:36 -05:00
|
|
|
def []=(k,v)
|
|
|
|
@scope[k] = v
|
|
|
|
end
|
2009-11-15 21:56:31 -05:00
|
|
|
|
|
|
|
# Evaluate a string of javascript in this context:
|
2009-11-20 10:38:31 -05:00
|
|
|
# * <tt>source</tt> - the javascript source code to evaluate. This can be either a string or an IO object.
|
2009-11-15 21:56:31 -05:00
|
|
|
# * <tt>source_name</tt> - associated name for this source code. Mainly useful for backtraces.
|
|
|
|
# * <tt>line_number</tt> - associate this number with the first line of executing source. Mainly useful for backtraces
|
|
|
|
def eval(source, source_name = "<eval>", line_number = 1)
|
2009-09-24 20:06:31 -04:00
|
|
|
begin
|
2009-11-13 12:09:54 -05:00
|
|
|
scope = To.javascript(@scope)
|
2009-11-20 10:38:31 -05:00
|
|
|
if IO === source || StringIO === source
|
|
|
|
result = @native.evaluateReader(scope, IOReader.new(source), source_name, line_number, nil)
|
|
|
|
else
|
|
|
|
result = @native.evaluateString(scope, source.to_s, source_name, line_number, nil)
|
|
|
|
end
|
2009-11-13 12:09:54 -05:00
|
|
|
To.ruby result
|
2009-09-24 20:06:31 -04:00
|
|
|
rescue J::RhinoException => e
|
|
|
|
raise Rhino::RhinoError, e
|
|
|
|
end
|
|
|
|
end
|
2009-11-15 21:56:31 -05:00
|
|
|
|
|
|
|
# Set the maximum number of instructions that this context will execute.
|
|
|
|
# If this instruction limit is exceeded, then a Rhino::RunawayScriptError
|
|
|
|
# will be raised
|
2009-11-10 09:52:03 -05:00
|
|
|
def instruction_limit=(limit)
|
|
|
|
@native.setInstructionObserverThreshold(limit);
|
|
|
|
@native.factory.instruction_limit = limit
|
|
|
|
end
|
2009-11-11 01:50:36 -05:00
|
|
|
|
2009-09-24 20:06:31 -04:00
|
|
|
end
|
2009-11-20 10:38:31 -05:00
|
|
|
|
|
|
|
class IOReader < Java::JavaIo::Reader #:nodoc:
|
|
|
|
|
|
|
|
def initialize(io)
|
|
|
|
@io = io
|
|
|
|
end
|
|
|
|
|
|
|
|
def read(charbuffer, offset, length)
|
|
|
|
begin
|
|
|
|
str = @io.read(length)
|
|
|
|
if str.nil?
|
|
|
|
return -1
|
|
|
|
else
|
|
|
|
jstring = Java::JavaLang::String.new(str)
|
|
|
|
for i in 0 .. jstring.length - 1
|
|
|
|
charbuffer[i + offset] = jstring.charAt(i)
|
|
|
|
end
|
|
|
|
return jstring.length
|
|
|
|
end
|
|
|
|
rescue StandardError => e
|
|
|
|
raise Java::JavaIo::IOException.new, "Failed reading from ruby IO object"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2009-11-11 21:12:20 -05:00
|
|
|
|
2009-11-15 22:46:24 -05:00
|
|
|
class ContextFactory < J::ContextFactory # :nodoc:
|
2009-11-10 09:52:03 -05:00
|
|
|
|
|
|
|
def observeInstructionCount(cxt, count)
|
|
|
|
raise RunawayScriptError, "script exceeded allowable instruction count" if count > @limit
|
|
|
|
end
|
|
|
|
|
|
|
|
def instruction_limit=(count)
|
|
|
|
@limit = count
|
|
|
|
end
|
|
|
|
end
|
2009-09-24 20:06:31 -04:00
|
|
|
|
|
|
|
|
2009-11-15 22:46:24 -05:00
|
|
|
class RhinoError < StandardError # :nodoc:
|
2009-09-24 20:06:31 -04:00
|
|
|
def initialize(native)
|
|
|
|
@native = native
|
|
|
|
end
|
|
|
|
|
2009-11-09 10:45:23 -05:00
|
|
|
def message
|
|
|
|
@native.cause.details
|
2009-09-24 20:06:31 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def javascript_backtrace
|
2009-10-06 09:52:45 -04:00
|
|
|
@native.getScriptStackTrace()
|
2009-09-24 20:06:31 -04:00
|
|
|
end
|
|
|
|
end
|
2009-11-10 09:52:03 -05:00
|
|
|
|
2009-11-15 22:46:24 -05:00
|
|
|
class RunawayScriptError < StandardError # :nodoc:
|
|
|
|
end
|
2009-09-24 20:06:31 -04:00
|
|
|
end
|