1
0
Fork 0
mirror of https://github.com/rubyjs/therubyrhino synced 2023-03-27 23:21:34 -04:00
therubyrhino/lib/rhino/context.rb

171 lines
5 KiB
Ruby
Raw Normal View History

2009-09-24 20:06:31 -04:00
module Rhino
# ==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.
class Context
attr_reader :scope
2009-09-24 20:06:31 -04:00
class << self
# 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|
block.call(new(native, options))
end
end
2009-09-24 20:06:31 -04:00
private :new
end
def initialize(native, options) #:nodoc:
2009-09-24 20:06:31 -04:00
@native = native
@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
unless options[:java]
for package in ["Packages", "java", "org", "com"]
@global.j.delete(package)
end
end
2009-09-24 20:06:31 -04:00
end
# Read a value from the global scope of this context
def [](k)
@scope[k]
end
# 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.
def []=(k,v)
@scope[k] = v
end
# Evaluate a string of javascript in this context:
# * <tt>source</tt> - the javascript source code to evaluate. This can be either a string or an IO object.
# * <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
scope = To.javascript(@scope)
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
To.ruby result
2009-09-24 20:06:31 -04:00
rescue J::RhinoException => e
raise Rhino::RhinoError, e
end
end
# Read the contents of <tt>filename</tt> and evaluate it as javascript. Returns the result of evaluating the
# javascript. e.g.
#
# Context.open do |cxt|
# cxt.load("path/to/some/lib.js")
# end
#
def load(filename)
File.open(filename) do |file|
eval file, filename, 1
end
end
# 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-09-24 20:06:31 -04:00
end
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-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
def message
@native.cause.details
2009-09-24 20:06:31 -04:00
end
def javascript_backtrace
@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