Class: Rhino::Context

Inherits:
Object show all
Includes:
JS::ContextAction
Defined in:
lib/rhino/context.rb

Overview

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::org.mozilla.javascript.Context, they are not the same thing and should not be confused.

Constant Summary collapse

@@default_factory =
nil
@@default_optimization_level =
java.lang.Integer.getInteger('rhino.opt.level')
@@default_javascript_version =
java.lang.System.getProperty('rhino.js.version')

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) {|_self| ... } ⇒ Context

Create a new javascript environment for executing javascript and ruby code.

  • :sealed - if this is true, then the standard objects such as Object, Function, Array will not be able to be modified

  • :with - use this ruby object as the root scope for all javascript that is evaluated

  • :java - if true, java packages will be accessible from within javascript

Yields:

  • (_self)

Yield Parameters:



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/rhino/context.rb', line 85

def initialize(options = {}) #:nodoc:
  factory = options[:factory] ||
    (options[:restrictable] ? RestrictableContextFactory.instance : self.class.default_factory)
  @options = options
  factory.call(self) # org.mozilla.javascript.ContextAction (invokes #run)
  if optimization_level = options[:optimization_level] || self.class.default_optimization_level
    self.optimization_level = optimization_level
  end
  if javascript_version = options[:javascript_version] || self.class.default_javascript_version
    self.javascript_version = javascript_version
  end
  yield(self) if block_given?
end

Instance Attribute Details

#scopeObject (readonly)

Returns the value of attribute scope.



79
80
81
# File 'lib/rhino/context.rb', line 79

def scope
  @scope
end

Class Method Details

.default_factoryObject



53
54
55
# File 'lib/rhino/context.rb', line 53

def self.default_factory
  @@default_factory ||= ContextFactory.new
end

.default_factory=(factory) ⇒ Object



57
58
59
# File 'lib/rhino/context.rb', line 57

def self.default_factory=(factory)
  @@default_factory = factory
end

.default_javascript_versionObject



71
72
73
# File 'lib/rhino/context.rb', line 71

def self.default_javascript_version
  @@default_javascript_version
end

.default_javascript_version=(version) ⇒ Object



75
76
77
# File 'lib/rhino/context.rb', line 75

def self.default_javascript_version=(version)
  @@default_javascript_version = version
end

.default_optimization_levelObject



62
63
64
# File 'lib/rhino/context.rb', line 62

def self.default_optimization_level
  @@default_optimization_level
end

.default_optimization_level=(level) ⇒ Object



66
67
68
# File 'lib/rhino/context.rb', line 66

def self.default_optimization_level=(level)
  @@default_optimization_level = level
end

.eval(javascript) ⇒ Object



46
47
48
# File 'lib/rhino/context.rb', line 46

def eval(javascript)
  new.eval(javascript)
end

.open(options = {}, &block) ⇒ Object

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.



42
43
44
# File 'lib/rhino/context.rb', line 42

def open(options = {}, &block)
  new(options).open(&block)
end

Instance Method Details

#[](key) ⇒ Object

Read a value from the global scope of this context



125
126
127
# File 'lib/rhino/context.rb', line 125

def [](key)
  @scope[key]
end

#[]=(key, val) ⇒ Object

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.



131
132
133
# File 'lib/rhino/context.rb', line 131

def []=(key, val)
  @scope[key] = val
end

#eval(source, source_name = "<eval>", line_number = 1) ⇒ Object

Evaluate a string of javascript in this context:

  • source - the javascript source code to evaluate. This can be either a string or an IO object.

  • source_name - associated name for this source code. Mainly useful for backtraces.

  • line_number - associate this number with the first line of executing source. Mainly useful for backtraces



139
140
141
142
143
144
145
146
147
148
# File 'lib/rhino/context.rb', line 139

def eval(source, source_name = "<eval>", line_number = 1)
  open do
    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
    Rhino.to_ruby(result)
  end
end

#evaluate(*args) ⇒ Object

:nodoc:



150
151
152
# File 'lib/rhino/context.rb', line 150

def evaluate(*args) # :nodoc:
  eval(*args) # an alias
end

#factoryObject

Returns the ContextFactory used while creating this context.



120
121
122
# File 'lib/rhino/context.rb', line 120

def factory
  @native.getFactory
end

#instruction_limitObject



172
173
174
# File 'lib/rhino/context.rb', line 172

def instruction_limit
  restrictable? ? @native.instruction_limit : false
end

#instruction_limit=(limit) ⇒ Object

Set the maximum number of instructions that this context will execute. If this instruction limit is exceeded, then a #Rhino::RunawayScriptError will be raised.



179
180
181
182
183
184
185
186
# File 'lib/rhino/context.rb', line 179

def instruction_limit=(limit)
  if restrictable?
    @native.instruction_limit = limit
  else
    raise "setting an instruction_limit has no effect on this context, use " <<
          "Context.open(:restrictable => true) to gain a restrictable instance"
  end
end

#javascript_versionObject Also known as: version

Get the JS interpreter version. Returns a number e.g. 1.7, nil if unknown and 0 for default.



225
226
227
228
229
230
231
# File 'lib/rhino/context.rb', line 225

def javascript_version
  case const_value = @native.getLanguageVersion
    when -1 then nil # VERSION_UNKNOWN
    when  0 then 0 # VERSION_DEFAULT
    else const_value / 100.0 # VERSION_1_1 (1.1 = 110 / 100)
  end
end

#javascript_version=(version) ⇒ Object Also known as: version=

Sets interpreter mode a.k.a. JS language version e.g. 1.7 (if supported).



235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/rhino/context.rb', line 235

def javascript_version=(version)
  const = version.to_s.gsub('.', '_').upcase
  const = "VERSION_#{const}" if const[0, 7] != 'VERSION'
  if JS::Context.constants.find { |c| c.to_s == const }
    const_value = JS::Context.const_get(const)
    @native.setLanguageVersion(const_value)
    const_value
  else
    @native.setLanguageVersion(JS::Context::VERSION_DEFAULT)
    nil
  end
end

#load(filename) ⇒ Object

Read the contents of filename 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



161
162
163
164
165
# File 'lib/rhino/context.rb', line 161

def load(filename)
  File.open(filename) do |file|
    evaluate file, filename, 1
  end
end

#open(&block) ⇒ Object

Enter this context for operations. Some methods such as eval() will fail unless the context is open.



251
252
253
254
255
256
257
258
259
260
# File 'lib/rhino/context.rb', line 251

def open(&block)
  do_open(&block)
rescue JS::RhinoException => e
  if code_generation_error?(e)
    Rhino.warn "[INFO] Rhino byte-code generation failed forcing #{@native} into interpreted mode"
    self.optimization_level = -1
    retry
  end
  raise Rhino::JSError.new(e)
end

#optimization_levelObject



205
206
207
# File 'lib/rhino/context.rb', line 205

def optimization_level
  @native.getOptimizationLevel
end

#optimization_level=(level) ⇒ Object

Set the optimization level that this context will use. This is sometimes necessary in Rhino, if the bytecode size of the compiled javascript exceeds the 64KB limit. By using the -1 optimization level, you tell Rhino to run in interpretative mode, taking a hit to performance but escaping the Java bytecode limit.



213
214
215
216
217
218
219
220
221
# File 'lib/rhino/context.rb', line 213

def optimization_level=(level)
  if JS::Context.isValidOptimizationLevel(level)
    @native.setOptimizationLevel(level)
    level
  else
    @native.setOptimizationLevel(0)
    nil
  end
end

#restrictable?Boolean

Returns true if this context supports restrictions.

Returns:

  • (Boolean)


168
169
170
# File 'lib/rhino/context.rb', line 168

def restrictable?
  @native.is_a?(RestrictableContextFactory::Context)
end

#run(context) ⇒ Object

org.mozilla.javascript.ContextAction public Object run(Context context);



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rhino/context.rb', line 102

def run(context) # :nodoc:
  @native = context
  @global = @native.initStandardObjects(nil, @options[:sealed] == true)
  if with = @options[:with]
    @scope = Rhino.to_javascript(with)
    @scope.setParentScope(@global)
  else
    @scope = @global
  end
  unless @options[:java]
    @global.delete('Packages')
    @global.delete('java'); @global.delete('javax')
    @global.delete('org'); @global.delete('com')
    @global.delete('edu'); @global.delete('net')
  end
end

#timeout_limitObject



188
189
190
# File 'lib/rhino/context.rb', line 188

def timeout_limit
  restrictable? ? @native.timeout_limit : false
end

#timeout_limit=(limit) ⇒ Object

Set the duration (in seconds e.g. 1.5) this context is allowed to execute. After the timeout passes (no matter if any JS has been evaluated) and this context is still attempted to run code, a #Rhino::ScriptTimeoutError will be raised.



196
197
198
199
200
201
202
203
# File 'lib/rhino/context.rb', line 196

def timeout_limit=(limit)
  if restrictable?
    @native.timeout_limit = limit
  else
    raise "setting an timeout_limit has no effect on this context, use " <<
          "Context.open(:restrictable => true) to gain a restrictable instance"
  end
end