Module: __JS__::Opal

Defined in:
opal/opal/corelib/runtime.js.rb

Overview

This module is just a placeholder for showing the documentation of the internal JavaScript runtime. The methods you'll find defined below are actually JavaScript functions attached to the Opal global object

Class Method Summary collapse

Class Method Details

.add_stub_forObject

Add a method_missing stub function to the given prototype for the given name. *

Parameters:

  • prototype (Prototype)

    the target prototype

  • stub (String)

    stub name to add (e.g. "$foo")



352
353
354
355
356
357
358
359
# File 'opal/opal/corelib/runtime.js.rb', line 352

def self.add_stub_for(*)
<<-JAVASCRIPT
   function add_stub_for(prototype, stub) {
     var method_missing_stub = stub_for(stub);
     prototype[stub] = method_missing_stub;
   }
JAVASCRIPT
end

.add_stubs_subscriberObject

Add a prototype to the subscribers list, and (TODO) add previously stubbed methods. *

Parameters:

  • (Prototype)


337
338
339
340
341
342
343
344
# File 'opal/opal/corelib/runtime.js.rb', line 337

def self.add_stubs_subscriber(*)
<<-JAVASCRIPT
   function add_stubs_subscriber(prototype) {
     // TODO: Add previously stubbed methods too.
     Opal.stub_subscribers.push(prototype);
   }
JAVASCRIPT
end

.boot_classObject

Create generic class with given superclass.



33
34
35
36
37
38
39
40
41
# File 'opal/opal/corelib/runtime.js.rb', line 33

def self.boot_class(*)
<<-JAVASCRIPT
   function boot_class(superklass, constructor) {
     var alloc = boot_class_alloc(null, constructor, superklass)
   
     return boot_class_object(superklass, alloc);
   }
JAVASCRIPT
end

.boot_class_allocObject

Boot a base class (makes instances).



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'opal/opal/corelib/runtime.js.rb', line 209

def self.boot_class_alloc(*)
<<-JAVASCRIPT
   function boot_class_alloc(id, constructor, superklass) {
     if (superklass) {
       var ctor = function() {};
           ctor.prototype   = superklass.$$proto || superklass.prototype;
   
       if (id) {
         ctor.displayName = id;
       }
   
       constructor.prototype = new ctor();
     }
   
     constructor.prototype.constructor = constructor;
   
     return constructor;
   }
JAVASCRIPT
end

.boot_class_objectObject

The class object itself (as in Class.new) *

Parameters:

  • superklass ((Opal) Class)

    Another class object (as in Class.new)

  • alloc (constructor)

    The constructor that holds the prototype that will be used for instances of the newly constructed class.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'opal/opal/corelib/runtime.js.rb', line 50

def self.boot_class_object(*)
<<-JAVASCRIPT
   function boot_class_object(superklass, alloc) {
     var singleton_class = function() {};
     singleton_class.prototype = superklass.constructor.prototype;
   
     function OpalClass() {}
     OpalClass.prototype = new singleton_class();
   
     var klass = new OpalClass();
   
     setup_module_or_class_object(klass, OpalClass, superklass, alloc.prototype);
   
     // @property $$alloc This is the constructor of instances of the current
     //                   class. Its prototype will be used for method lookup
     klass.$$alloc = alloc;
   
     // @property $$proto.$$class Make available to instances a reference to the
     //                           class they belong to.
     klass.$$proto.$$class = klass;
   
     return klass;
   }
JAVASCRIPT
end

.boot_core_class_objectObject

Builds the class object for core classes:

  • make the class object have a singleton class
  • make the singleton class inherit from its parent singleton class *

Parameters:

  • id (String)

    the name of the class

  • alloc (Function)

    the constructor for the core class instances

  • superclass (Class alloc)

    the constructor of the superclass



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'opal/opal/corelib/runtime.js.rb', line 238

def self.boot_core_class_object(*)
<<-JAVASCRIPT
   function boot_core_class_object(id, alloc, superclass) {
     var superclass_constructor = function() {};
         superclass_constructor.prototype = superclass.prototype;
   
     var singleton_class = function() {};
         singleton_class.prototype = new superclass_constructor();
   
     singleton_class.displayName = "#<Class:"+id+">";
   
     // the singleton_class acts as the class object constructor
     var klass = new singleton_class();
   
     setup_module_or_class_object(klass, singleton_class, superclass, alloc.prototype);
   
     klass.$$alloc = alloc;
     klass.$$name  = id;
   
     // Give all instances a ref to their class
     alloc.prototype.$$class = klass;
   
     Opal[id] = klass;
     Opal.constants.push(id);
   
     return klass;
   }
JAVASCRIPT
end

.boot_module_objectObject

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



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'opal/opal/corelib/runtime.js.rb', line 135

def self.boot_module_object(*)
<<-JAVASCRIPT
   function boot_module_object() {
     var mtor = function() {};
     mtor.prototype = ModuleClass.constructor.prototype;
   
     function module_constructor() {}
     module_constructor.prototype = new mtor();
   
     var module = new module_constructor();
     var module_prototype = {};
   
     setup_module_or_class_object(module, module_constructor, ModuleClass, module_prototype);
   
     module.$$is_mod = true;
     module.$$dep    = [];
   
     return module;
   }
JAVASCRIPT
end

.bridge_classClass

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); *

Parameters:

  • name (String)

    the name of the ruby class to create

  • constructor (Function)

    native javascript constructor to use

Returns:

  • (Class)

    returns new ruby class



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'opal/opal/corelib/runtime.js.rb', line 290

def self.bridge_class(*)
<<-JAVASCRIPT
   function bridge_class(name, constructor) {
     var klass = boot_class_object(ObjectClass, constructor);
   
     klass.$$name = name;
   
     create_scope(Opal, klass, name);
     bridged_classes.push(klass);
   
     var object_methods = BasicObjectClass.$$methods.concat(ObjectClass.$$methods);
   
     for (var i = 0, len = object_methods.length; i < len; i++) {
       var meth = object_methods[i];
       constructor.prototype[meth] = ObjectClass.$$proto[meth];
     }
   
     add_stubs_subscriber(constructor.prototype);
   
     return klass;
   }
JAVASCRIPT
end

.build_class_singleton_classRubyClass

Build the singleton class for an existing class.

NOTE: Actually in MRI a class' singleton class inherits from its superclass' singleton class which in turn inherits from Class.

Parameters:

  • klass (RubyClass)

Returns:

  • (RubyClass)


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'opal/opal/corelib/runtime.js.rb', line 165

def self.build_class_singleton_class(*)
<<-JAVASCRIPT
   function build_class_singleton_class(klass) {
     var meta = new Opal.Class.$$alloc;
   
     meta.$$class = Opal.Class;
     meta.$$proto = klass.constructor.prototype;
   
     meta.$$is_singleton = true;
     meta.$$inc          = [];
     meta.$$methods      = [];
     meta.$$scope        = klass.$$scope;
   
     return klass.$$meta = meta;
   }
JAVASCRIPT
end

.build_object_singleton_classRubyClass

Build the singleton class for a Ruby (non class) Object.

Parameters:

  • object (RubyObject)

Returns:

  • (RubyClass)


188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'opal/opal/corelib/runtime.js.rb', line 188

def self.build_object_singleton_class(*)
<<-JAVASCRIPT
   function build_object_singleton_class(object) {
     var orig_class = object.$$class,
         class_id   = "#<Class:#<" + orig_class.$$name + ":" + orig_class.$$id + ">>";
   
     var Singleton = function () {};
     var meta = Opal.boot(orig_class, Singleton);
     meta.$$name   = class_id;
   
     meta.$$proto  = object;
     meta.$$class  = orig_class.$$class;
     meta.$$scope  = orig_class.$$scope;
     meta.$$parent = orig_class;
     return object.$$meta = meta;
   }
JAVASCRIPT
end

.create_scopeObject

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.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'opal/opal/corelib/runtime.js.rb', line 9

def self.create_scope(*)
<<-JAVASCRIPT
   function create_scope(base, klass, id) {
     var const_alloc = function() {};
     var const_scope = const_alloc.prototype = new base.constructor();
   
     klass.$$scope       = const_scope;
     klass.$$base_module = base.base;
   
     const_scope.base        = klass;
     const_scope.constructor = const_alloc;
     const_scope.constants   = [];
   
     if (id) {
       klass.$$orig_scope = base;
       base[id] = base.constructor[id] = klass;
       base.constants.push(id);
     }
   }
JAVASCRIPT
end

.define_module_methodObject

Define the given method on the module.

This also handles donating methods to all classes that include this module. Method conflicts are also handled here, where a class might already have defined a method of the same name, or another included module defined the same method.

Parameters:

  • module (RubyModule)

    the module method defined on

  • jsid (String)

    javascript friendly method name (e.g. "$foo")

  • body (Function)

    method body of actual function



429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
# File 'opal/opal/corelib/runtime.js.rb', line 429

def self.define_module_method(*)
<<-JAVASCRIPT
   function define_module_method(module, jsid, body) {
     module.$$proto[jsid] = body;
     body.$$owner = module;
   
     module.$$methods.push(jsid);
   
     if (module.$$module_function) {
       module[jsid] = body;
     }
   
     var included_in = module.$$dep;
   
     if (included_in) {
       for (var i = 0, length = included_in.length; i < length; i++) {
         var includee = included_in[i];
         var dest = includee.$$proto;
         var current = dest[jsid];
   
   
         if (dest.hasOwnProperty(jsid) && !current.$$donated && !current.$$stub) {
           // target class has already defined the same method name - do nothing
         }
         else if (dest.hasOwnProperty(jsid) && !current.$$stub) {
           // target class includes another module that has defined this method
           var klass_includees = includee.$$inc;
   
           for (var j = 0, jj = klass_includees.length; j < jj; j++) {
             if (klass_includees[j] === current.$$owner) {
               var current_owner_index = j;
             }
             if (klass_includees[j] === module) {
               var module_index = j;
             }
           }
   
           // only redefine method on class if the module was included AFTER
           // the module which defined the current method body. Also make sure
           // a module can overwrite a method it defined before
           if (current_owner_index <= module_index) {
             dest[jsid] = body;
             dest[jsid].$$donated = true;
           }
         }
         else {
           // neither a class, or module included by class, has defined method
           dest[jsid] = body;
           dest[jsid].$$donated = true;
         }
   
         if (includee.$$dep) {
           donate_methods(includee, [jsid], true);
         }
       }
     }
   }
JAVASCRIPT
end

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



317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'opal/opal/corelib/runtime.js.rb', line 317

def self.donate_constants(*)
<<-JAVASCRIPT
   function donate_constants(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]];
     }
   };
JAVASCRIPT
end

Donate methods for a class/module



388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'opal/opal/corelib/runtime.js.rb', line 388

def self.donate_methods(*)
<<-JAVASCRIPT
   function donate_methods(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) {
           donate_methods(includee, defined, true);
         }
       }
     }
   };
JAVASCRIPT
end

.setup_module_or_class_objectObject

Adds common/required properties to a module or class object (as in Module.new / Class.new) * * * *

Parameters:

  • module

    The module or class that needs to be prepared

  • constructor

    The constructor of the module or class itself, usually it's already assigned by using new. Some ipothesis on why it's needed can be found below.

  • superklass

    The superclass of the class/module object, for modules is Module (of ModuleClass in JS context)

  • prototype

    The prototype on which the class/module methods will be stored.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'opal/opal/corelib/runtime.js.rb', line 91

def self.setup_module_or_class_object(*)
<<-JAVASCRIPT
   function setup_module_or_class_object(module, constructor, superklass, prototype) {
     // @property $$id Each class is assigned a unique `id` that helps
     //                comparation and implementation of `#object_id`
     module.$$id = unique_id++;
   
     // @property $$proto This is the prototype on which methods will be defined
     module.$$proto = prototype;
   
     // @property constructor keeps a ref to the constructor, but apparently the
     //                       constructor is already set on:
     //
     //                          `var module = new constructor` is called.
     //
     //                       Maybe there are some browsers not abiding (IE6?)
     module.constructor = constructor;
   
     // @property $$is_class Clearly mark this as a class-like
     module.$$is_class = true;
   
     // @property $$super the superclass, doesn't get changed by module inclusions
     module.$$super = superklass;
   
     // @property $$parent direct parent class or module
     //                    starts with the superclass, after module inclusion is
     //                    the last included module
     module.$$parent = superklass;
   
     // @property $$methods keeps track of methods defined on the class
     //                     but seems to be used just by `define_basic_object_method`
     //                     and for donating (Ruby) Object methods to bridged classes
     //                     TODO: check if it can be removed
     module.$$methods = [];
   
     // @property $$inc included modules
     module.$$inc = [];
   }
JAVASCRIPT
end

.stub_forObject

Generate the method_missing stub for a given method name. *

Parameters:

  • method_name (String)

    The js-name of the method to stub (e.g. "$foo")



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'opal/opal/corelib/runtime.js.rb', line 365

def self.stub_for(*)
<<-JAVASCRIPT
   function stub_for(method_name) {
     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, [method_name.slice(1)].concat($slice.call(arguments)));
     }
   
     method_missing_stub.$$stub = true;
   
     return method_missing_stub;
   }
JAVASCRIPT
end