runtime.js

Opal = this.Opal = {}

The Opal object that is exposed globally

var Opal = this.Opal = {};

RubyBasicObject

The actual class for BasicObject

var RubyBasicObject;

RubyObject

The actual Object class

var RubyObject;

RubyModule

The actual Module class

var RubyModule;

RubyClass

The actual Class class

var RubyClass;

function: BasicObject()

Constructor for instances of BasicObject

function BasicObject(){}

function: Object()

Constructor for instances of Object

function Object(){}

function: Class()

Constructor for instances of Class

function Class(){}

function: Module()

Constructor for instances of Module

function Module(){}

function: NilClass()

Constructor for instances of NilClass (nil)

function NilClass(){}

bridged_classes = []

All bridged classes - keep track to donate methods from Object

var bridged_classes = [];

TopScope = function(){}

TopScope is used for inheriting constants from the top scope

var TopScope = function(){};

TopScope.prototype = Opal

Opal just acts as the top scope

TopScope.prototype = Opal;

Opal.constructor = TopScope

To inherit scopes

Opal.constructor  = TopScope;

Opal.global = this

This is a useful reference to global object inside ruby files

Opal.global = this;

$hasOwn = Opal.hasOwnProperty

Minify common function calls

var $hasOwn = Opal.hasOwnProperty;

unique_id = 0

Generates unique id for every ruby object

var unique_id = 0;

Opal.uid = function()

Return next unique id

Opal.uid = function() {
  return unique_id++;
};

Opal.cvars = {}

Table holds all class variables

Opal.cvars = {};

Opal.gvars = {}

Globals table

Opal.gvars = {};

function create_scope(base, klass, id)

Create a new constants scope for the given class with the given base. Constants are looked up through their parents, so the base scope will be the outer scope of the new klass.

function create_scope(base, klass, id) {
  var const_alloc   = function() {};
  var const_scope   = const_alloc.prototype = new base.constructor();
  klass._scope      = const_scope;
  const_scope.base  = klass;
  klass._base_module = base.base;
  const_scope.constructor = const_alloc;
  const_scope.constants = [];

  if (id) {
    klass._orig_scope = base;
    base[id] = base.constructor[id] = klass;
    base.constants.push(id);
  }
}

Opal.klass = function(base, superklass, id, constructor)

A class Foo; end expression in ruby is compiled to call this runtime method which either returns an existing class of the given name, or creates a new class in the given base scope. * If a constant with the given name exists, then we check to make sure that it is a class and also that the superclasses match. If either of these fail, then we raise a TypeError. Note, superklass may be null if one was not specified in the ruby code. * We pass a constructor to this method of the form function ClassName() {} simply so that classes show up with nicely formatted names inside debuggers in the web browser (or node/sprockets). * The base is the current self value where the class is being created from. We use this to get the scope for where the class should be created. If base is an object (not a class/module), we simple get its class and use that as the base instead. * @param [Object] base where the class is being created @param [Class] superklass superclass of the new class (may be null) @param [String] id the name of the class to be created @param [Function] constructor function to use as constructor @return [Class] new or existing ruby class

Opal.klass = function(base, superklass, id, constructor) {

  // If base is an object, use its class
  if (!base._isClass) {
    base = base._klass;
  }

  // Not specifying a superclass means we can assume it to be Object
  if (superklass === null) {
    superklass = RubyObject;
  }

  var klass = base._scope[id];

  // If a constant exists in the scope, then we must use that
  if ($hasOwn.call(base._scope, id) && klass._orig_scope === base._scope) {

    // Make sure the existing constant is a class, or raise error
    if (!klass._isClass) {
      throw Opal.TypeError.$new(id + " is not a class");
    }

    // Make sure existing class has same superclass
    if (superklass !== klass._super && superklass !== RubyObject) {
      throw Opal.TypeError.$new("superclass mismatch for class " + id);
    }
  }
  else if (typeof(superklass) === 'function') {
    // passed native constructor as superklass, so bridge it as ruby class
    return bridge_class(id, superklass);
  }
  else {
    // if class doesnt exist, create a new one with given superclass
    klass = boot_class(superklass, constructor);

    // name class using base (e.g. Foo or Foo::Baz)
    klass._name = id;

    // every class gets its own constant scope, inherited from current scope
    create_scope(base._scope, klass, id);

    // Name new class directly onto current scope (Opal.Foo.Baz = klass)
    base[id] = base._scope[id] = klass;

    // Copy all parent constants to child, unless parent is Object
    if (superklass !== RubyObject && superklass !== RubyBasicObject) {
      Opal.donate_constants(superklass, klass);
    }

    // call .inherited() hook with new class on the superclass
    if (superklass.$inherited) {
      superklass.$inherited(klass);
    }
  }

  return klass;
};

boot_class = Opal.boot = function(superklass, constructor)

Create generic class with given superclass.

var boot_class = Opal.boot = function(superklass, constructor) {
  // instances
  var ctor = function() {};
      ctor.prototype = superklass._proto;

  constructor.prototype = new ctor();

  constructor.prototype.constructor = constructor;

  return boot_class_meta(superklass, constructor);
};

function boot_class_meta(superklass, constructor)

class itself

function boot_class_meta(superklass, constructor) {
  var mtor = function() {};
  mtor.prototype = superklass.constructor.prototype;

  function OpalClass() {};
  OpalClass.prototype = new mtor();

  var klass = new OpalClass();

  klass._id         = unique_id++;
  klass._alloc      = constructor;
  klass._isClass    = true;
  klass.constructor = OpalClass;
  klass._super      = superklass;
  klass._methods    = [];
  klass.__inc__     = [];
  klass.__parent    = superklass;
  klass._proto      = constructor.prototype;

  constructor.prototype._klass = klass;

  return klass;
}

Opal.module = function(base, id)

Define new module (or return existing module)

Opal.module = function(base, id) {
  var module;

  if (!base._isClass) {
    base = base._klass;
  }

  if ($hasOwn.call(base._scope, id)) {
    module = base._scope[id];

    if (!module.__mod__ && module !== RubyObject) {
      throw Opal.TypeError.$new(id + " is not a module")
    }
  }
  else {
    module = boot_module()
    module._name = id;

    create_scope(base._scope, module, id);

    // Name new module directly onto current scope (Opal.Foo.Baz = module)
    base[id] = base._scope[id] = module;
  }

  return module;
};

function boot_module()

Internal function to create a new module instance. This simply sets up the prototype hierarchy and method tables.

function boot_module() {
  var mtor = function() {};
  mtor.prototype = RubyModule.constructor.prototype;

  function OpalModule() {};
  OpalModule.prototype = new mtor();

  var module = new OpalModule();

  module._id         = unique_id++;
  module._isClass    = true;
  module.constructor = OpalModule;
  module._super      = RubyModule;
  module._methods    = [];
  module.__inc__     = [];
  module.__parent    = RubyModule;
  module._proto      = {};
  module.__mod__     = true;
  module.__dep__     = [];

  return module;
}

boot_defclass = function(id, constructor, superklass)

Boot a base class (makes instances).

var boot_defclass = function(id, constructor, superklass) {
  if (superklass) {
    var ctor           = function() {};
        ctor.prototype = superklass.prototype;

    constructor.prototype = new ctor();
  }

  constructor.prototype.constructor = constructor;

  return constructor;
};

boot_makemeta = function(id, constructor, superklass)

Boot the actual (meta?) classes of core classes

var boot_makemeta = function(id, constructor, superklass) {

  var mtor = function() {};
  mtor.prototype  = superklass.prototype;

  function OpalClass() {};
  OpalClass.prototype = new mtor();

  var klass = new OpalClass();

  klass._id         = unique_id++;
  klass._alloc      = constructor;
  klass._isClass    = true;
  klass._name       = id;
  klass._super      = superklass;
  klass.constructor = OpalClass;
  klass._methods    = [];
  klass.__inc__     = [];
  klass.__parent    = superklass;
  klass._proto      = constructor.prototype;

  constructor.prototype._klass = klass;

  Opal[id] = klass;
  Opal.constants.push(id);

  return klass;
};

function bridge_class(name, constructor)

For performance, some core ruby classes are toll-free bridged to their native javascript counterparts (e.g. a ruby Array is a javascript Array). * This method is used to setup a native constructor (e.g. Array), to have its prototype act like a normal ruby class. Firstly, a new ruby class is created using the native constructor so that its prototype is set as the target for th new class. Note: all bridged classes are set to inherit from Object. * Bridged classes are tracked in bridged_classes array so that methods defined on Object can be "donated" to all bridged classes. This allows us to fake the inheritance of a native prototype from our Object prototype. * Example: * bridge_class("Proc", Function); * @param [String] name the name of the ruby class to create @param [Function] constructor native javascript constructor to use @return [Class] returns new ruby class

function bridge_class(name, constructor) {
  var klass = boot_class_meta(RubyObject, constructor);

  klass._name = name;

  create_scope(Opal, klass, name);
  bridged_classes.push(klass);

  var object_methods = RubyBasicObject._methods.concat(RubyObject._methods);

  for (var i = 0, len = object_methods.length; i < len; i++) {
    var meth = object_methods[i];
    constructor.prototype[meth] = RubyObject._proto[meth];
  }

  return klass;
};

Opal.casgn = function(base_module, name, value)

constant assign

Opal.casgn = function(base_module, name, value) {
  var scope = base_module._scope;

  if (value._isClass && value._name === nil) {
    value._name = name;
  }

  if (value._isClass) {
    value._base_module = base_module;
  }

  scope.constants.push(name);
  return scope[name] = value;
};

Opal.cdecl = function(base_scope, name, value)

constant decl

Opal.cdecl = function(base_scope, name, value) {
  base_scope.constants.push(name);
  return base_scope[name] = value;
};

Opal.cget = function(base_scope, path)

constant get

Opal.cget = function(base_scope, path) {
  if (path == null) {
    path       = base_scope;
    base_scope = Opal.Object;
  }

  var result = base_scope;

  path = path.split('::');
  while (path.length != 0) {
    result = result.$const_get(path.shift());
  }

  return result;
}

Opal.donate_constants = function(source_mod, target_mod)

When a source module is included into the target module, we must also copy its constants to the target.

Opal.donate_constants = function(source_mod, target_mod) {
  var source_constants = source_mod._scope.constants,
      target_scope     = target_mod._scope,
      target_constants = target_scope.constants;

  for (var i = 0, length = source_constants.length; i < length; i++) {
    target_constants.push(source_constants[i]);
    target_scope[source_constants[i]] = source_mod._scope[source_constants[i]];
  }
};

Opal.add_stubs = function(stubs)

Methods stubs are used to facilitate method_missing in opal. A stub is a placeholder function which just calls method_missing on the receiver. If no method with the given name is actually defined on an object, then it is obvious to say that the stub will be called instead, and then in turn method_missing will be called. * When a file in ruby gets compiled to javascript, it includes a call to this function which adds stubs for every method name in the compiled file. It should then be safe to assume that method_missing will work for any method call detected. * Method stubs are added to the BasicObject prototype, which every other ruby object inherits, so all objects should handle method missing. A stub is only added if the given property name (method name) is not already defined. * Note: all ruby methods have a $ prefix in javascript, so all stubs will have this prefix as well (to make this method more performant). * Opal.add_stubs(["$foo", "$bar", "$baz="]); * All stub functions will have a private rb_stub property set to true so that other internal methods can detect if a method is just a stub or not. Kernel#respond_to? uses this property to detect a methods presence. * @param [Array] stubs an array of method stubs to add

Opal.add_stubs = function(stubs) {
  for (var i = 0, length = stubs.length; i < length; i++) {
    var stub = stubs[i];

    if (!BasicObject.prototype[stub]) {
      BasicObject.prototype[stub] = true;
      add_stub_for(BasicObject.prototype, stub);
    }
  }
};

function add_stub_for(prototype, stub)

Actuall add a method_missing stub function to the given prototype for the given name. * @param [Prototype] prototype the target prototype @param [String] stub stub name to add (e.g. "$foo")

function add_stub_for(prototype, stub) {
  function method_missing_stub() {
    // Copy any given block onto the method_missing dispatcher
    this.$method_missing._p = method_missing_stub._p;

    // Set block property to null ready for the next call (stop false-positives)
    method_missing_stub._p = null;

    // call method missing with correct args (remove '$' prefix on method name)
    return this.$method_missing.apply(this, [stub.slice(1)].concat($slice.call(arguments)));
  }

  method_missing_stub.rb_stub = true;
  prototype[stub] = method_missing_stub;
}

Opal.add_stub_for = add_stub_for

Expose for other parts of Opal to use

Opal.add_stub_for = add_stub_for;

Opal.cm = function(name)

Const missing dispatcher

Opal.cm = function(name) {
  return this.base.$const_missing(name);
};

Opal.ac = function(actual, expected, object, meth)

Arity count error dispatcher

Opal.ac = function(actual, expected, object, meth) {
  var inspect = (object._isClass ? object._name + '.' : object._klass._name + '#') + meth;
  var msg = '[' + inspect + '] wrong number of arguments(' + actual + ' for ' + expected + ')';
  throw Opal.ArgumentError.$new(msg);
};

Opal.find_super_dispatcher = function(obj, jsid, current_func, iter, defs)

Super dispatcher

Opal.find_super_dispatcher = function(obj, jsid, current_func, iter, defs) {
  var dispatcher;

  if (defs) {
    dispatcher = obj._isClass ? defs._super : obj._klass._proto;
  }
  else {
    if (obj._isClass) {
      dispatcher = obj._super;
    }
    else {
      dispatcher = find_obj_super_dispatcher(obj, jsid, current_func);
    }
  }

  dispatcher = dispatcher['$' + jsid];
  dispatcher._p = iter;

  return dispatcher;
};

Opal.find_iter_super_dispatcher = function(obj, jsid, current_func, iter, defs)

Iter dispatcher for super in a block

Opal.find_iter_super_dispatcher = function(obj, jsid, current_func, iter, defs) {
  if (current_func._def) {
    return Opal.find_super_dispatcher(obj, current_func._jsid, current_func, iter, defs);
  }
  else {
    return Opal.find_super_dispatcher(obj, jsid, current_func, iter, defs);
  }
};

break

ok

break;

if (!klass)

if we arent in a class, we couldnt find current?

if (!klass) {

while (klass)

else, let's find the next one

while (klass) {

break

ok

break;

Opal.$return = function(val)

Used to return as an expression. Sometimes, we can't simply return from a javascript function as if we were a method, as the return is used as an expression, or even inside a block which must "return" to the outer method. This helper simply throws an error which is then caught by the method. This approach is expensive, so it is only used when absolutely needed.

Opal.$return = function(val) {
  Opal.returner.$v = val;
  throw Opal.returner;
};

Opal.$yield1 = function(block, arg)

handles yield calls for 1 yielded arg

Opal.$yield1 = function(block, arg) {
  if (typeof(block) !== "function") {
    throw Opal.LocalJumpError.$new("no block given");
  }

  if (block.length > 1) {
    if (arg._isArray) {
      return block.apply(null, arg);
    }
    else {
      return block(arg);
    }
  }
  else {
    return block(arg);
  }
};

Opal.$yieldX = function(block, args)

handles yield for > 1 yielded arg

Opal.$yieldX = function(block, args) {
  if (typeof(block) !== "function") {
    throw Opal.LocalJumpError.$new("no block given");
  }

  if (block.length > 1 && args.length == 1) {
    if (args[0]._isArray) {
      return block.apply(null, args[0]);
    }
  }

  if (!args._isArray) {
    args = $slice.call(args);
  }

  return block.apply(null, args);
};

Opal.to_ary = function(value)

Helper to convert the given object to an array

Opal.to_ary = function(value) {
  if (value._isArray) {
    return value;
  }
  else if (value.$to_ary && !value.$to_ary.rb_stub) {
    return value.$to_ary();
  }

  return [value];
};

Opal.send = function(recv, mid)

Call a ruby method on a ruby object with some arguments:

var my_array = [1, 2, 3, 4] Opal.send(my_array, 'length') # => 4 Opal.send(my_array, 'reverse!') # => [4, 3, 2, 1]

A missing method will be forwarded to the object via method_missing.

The result of either call with be returned.

@param [Object] recv the ruby object @param [String] mid ruby method to call

Opal.send = function(recv, mid) {
  var args = $slice.call(arguments, 2),
      func = recv['$' + mid];

  if (func) {
    return func.apply(recv, args);
  }

  return recv.$method_missing.apply(recv, [mid].concat(args));
};

Opal.donate = function(klass, defined, indirect)

Donate methods for a class/module

Opal.donate = function(klass, defined, indirect) {
  var methods = klass._methods, included_in = klass.__dep__;

  // if (!indirect) {
    klass._methods = methods.concat(defined);
  // }

  if (included_in) {
    for (var i = 0, length = included_in.length; i < length; i++) {
      var includee = included_in[i];
      var dest = includee._proto;

      for (var j = 0, jj = defined.length; j < jj; j++) {
        var method = defined[j];
        dest[method] = klass._proto[method];
        dest[method]._donated = true;
      }

      if (includee.__dep__) {
        Opal.donate(includee, defined, true);
      }
    }
  }
};

Opal.defs = function(obj, jsid, body)

Define a singleton method on the given object.

Opal.defs = function(obj, jsid, body) {
  if (obj._isClass || obj.__mod__) {
    obj.constructor.prototype[jsid] = body;
  }
  else {
    obj[jsid] = body;
  }
};

Opal.hash2 = function(keys, map)

hash2 is a faster creator for hashes that just use symbols and strings as keys. The map and keys array can be constructed at compile time, so they are just added here by the constructor function

Opal.hash2 = function(keys, map) {
  var hash = new Opal.Hash._alloc;

  hash.keys = keys;
  hash.map  = map;

  return hash;
};

Opal.range = function(first, last, exc)

Create a new range instance with first and last values, and whether the range excludes the last value.

Opal.range = function(first, last, exc) {
  var range         = new Opal.Range._alloc;
      range.begin   = first;
      range.end     = last;
      range.exclude = exc;

  return range;
};

``

Initialization


boot_defclass('BasicObject', BasicObject)

Constructors for instances of core objects

boot_defclass('BasicObject', BasicObject);

RubyBasicObject = boot_makemeta('BasicObject', BasicObject, Class)

Constructors for classes of core objects

RubyBasicObject = boot_makemeta('BasicObject', BasicObject, Class);

RubyBasicObject._klass = RubyClass

Fix booted classes to use their metaclass

RubyBasicObject._klass = RubyClass;

RubyBasicObject._super = null

Fix superclasses of booted classes

RubyBasicObject._super = null;

RubyObject.__dep__ = bridged_classes

Internally, Object acts like a module as it is "included" into bridged classes. In other words, we donate methods from Object into our bridged classes as their prototypes don't inherit from our root Object, so they act like module includes.

RubyObject.__dep__ = bridged_classes;