Class: Rhino::Context

Inherits:
Object show all
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
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rhino/context.rb', line 85

def initialize(options = {}) #:nodoc:
  factory = options[:factory] || 
    (options[:restrictable] ? RestrictableContextFactory.instance : self.class.default_factory)
  factory.call do |context|
    @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]
      for package in ["Packages", "java", "javax", "org", "com", "edu", "net"]
        @global.delete(package)
      end
    end
  end
  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



118
119
120
# File 'lib/rhino/context.rb', line 118

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.



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

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



132
133
134
135
136
137
138
139
140
141
# File 'lib/rhino/context.rb', line 132

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:



143
144
145
# File 'lib/rhino/context.rb', line 143

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

#factoryObject

Returns the ContextFactory used while creating this context.



113
114
115
# File 'lib/rhino/context.rb', line 113

def factory
  @native.getFactory
end

#instruction_limitObject



165
166
167
# File 'lib/rhino/context.rb', line 165

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.



172
173
174
175
176
177
178
179
# File 'lib/rhino/context.rb', line 172

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.



218
219
220
221
222
223
224
# File 'lib/rhino/context.rb', line 218

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



228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/rhino/context.rb', line 228

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



154
155
156
157
158
# File 'lib/rhino/context.rb', line 154

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.



244
245
246
247
248
249
250
251
252
253
# File 'lib/rhino/context.rb', line 244

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



198
199
200
# File 'lib/rhino/context.rb', line 198

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.



206
207
208
209
210
211
212
213
214
# File 'lib/rhino/context.rb', line 206

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)


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

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

#timeout_limitObject



181
182
183
# File 'lib/rhino/context.rb', line 181

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.



189
190
191
192
193
194
195
196
# File 'lib/rhino/context.rb', line 189

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