Skip to content

Commit 6e0f547

Browse files
committed
Add some more documentation to runtime
1 parent 89ba3ce commit 6e0f547

File tree

2 files changed

+80
-23
lines changed

2 files changed

+80
-23
lines changed

corelib/opal.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def $stdout.puts(*strs)
5151
if(strs[i] instanceof Array) {
5252
#{ puts(*`strs[i]`) }
5353
} else {
54-
$opal.puts(#{ `strs[i]`.to_s });
54+
console.log(#{`strs[i]`.to_s});
5555
}
5656
}
5757
}

corelib/runtime.js

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@
198198
if ($hasOwn.call(base._scope, id)) {
199199
module = base._scope[id];
200200

201-
if (!module._mod$ && module !== RubyObject) {
201+
if (!module.__mod__ && module !== RubyObject) {
202202
throw Opal.TypeError.$new(id + " is not a module")
203203
}
204204
}
@@ -212,8 +212,11 @@
212212
return module;
213213
};
214214

215+
/*
216+
* Internal function to create a new module instance. This simply sets up
217+
* the prototype hierarchy and method tables.
218+
*/
215219
function boot_module() {
216-
217220
var mtor = function() {};
218221
mtor.prototype = RubyModule.constructor.prototype;
219222

@@ -230,7 +233,7 @@
230233
module.__inc__ = [];
231234
module.__parent = RubyModule;
232235
module._proto = {};
233-
module._mod$ = true;
236+
module.__mod__ = true;
234237
module.__dep__ = [];
235238

236239
return module;
@@ -279,26 +282,68 @@
279282
return klass;
280283
};
281284

282-
var bridge_class = function(name, constructor) {
283-
var klass = boot_class(RubyObject, constructor), idx, length, mid;
284-
285-
bridged_classes.push(klass);
286-
287-
var table = RubyObject._proto, methods = RubyObject._methods;
288-
289-
for (idx = 0, len = methods.length; idx < len; idx++) {
290-
mid = methods[idx];
291-
constructor.prototype[mid] = table[mid];
292-
}
285+
/*
286+
* For performance, some core ruby classes are toll-free bridged to their
287+
* native javascript counterparts (e.g. a ruby Array is a javascript Array).
288+
*
289+
* This method is used to setup a native constructor (e.g. Array), to have
290+
* its prototype act like a normal ruby class. Firstly, a new ruby class is
291+
* created using the native constructor so that its prototype is set as the
292+
* target for th new class. Note: all bridged classes are set to inherit
293+
* from Object.
294+
*
295+
* Bridged classes are tracked in `bridged_classes` array so that methods
296+
* defined on Object can be "donated" to all bridged classes. This allows
297+
* us to fake the inheritance of a native prototype from our Object
298+
* prototype.
299+
*
300+
* Example:
301+
*
302+
* bridge_class("Proc", Function);
303+
*
304+
* @param [String] name the name of the ruby class to create
305+
* @param [Function] constructor native javascript constructor to use
306+
* @return [Class] returns new ruby class
307+
*/
308+
function bridge_class(name, constructor) {
309+
var klass = boot_class(RubyObject, constructor);
293310

294311
klass._name = name;
312+
295313
create_scope(Opal, klass, name);
314+
bridged_classes.push(klass);
296315

297316
return klass;
298317
};
299318

300-
Opal.puts = function(a) { console.log(a); };
301-
319+
/*
320+
* Methods stubs are used to facilitate method_missing in opal. A stub is a
321+
* placeholder function which just calls `method_missing` on the receiver.
322+
* If no method with the given name is actually defined on an object, then it
323+
* is obvious to say that the stub will be called instead, and then in turn
324+
* method_missing will be called.
325+
*
326+
* When a file in ruby gets compiled to javascript, it includes a call to
327+
* this function which adds stubs for every method name in the compiled file.
328+
* It should then be safe to assume that method_missing will work for any
329+
* method call detected.
330+
*
331+
* Method stubs are added to the BasicObject prototype, which every other
332+
* ruby object inherits, so all objects should handle method missing. A stub
333+
* is only added if the given property name (method name) is not already
334+
* defined.
335+
*
336+
* Note: all ruby methods have a `$` prefix in javascript, so all stubs will
337+
* have this prefix as well (to make this method more performant).
338+
*
339+
* Opal.add_stubs(["$foo", "$bar", "$baz="]);
340+
*
341+
* All stub functions will have a private `rb_stub` property set to true so
342+
* that other internal methods can detect if a method is just a stub or not.
343+
* `Kernel#respond_to?` uses this property to detect a methods presence.
344+
*
345+
* @param [Array] stubs an array of method stubs to add
346+
*/
302347
Opal.add_stubs = function(stubs) {
303348
for (var i = 0, length = stubs.length; i < length; i++) {
304349
var stub = stubs[i];
@@ -310,18 +355,30 @@
310355
}
311356
};
312357

358+
/*
359+
* Actuall add a method_missing stub function to the given prototype for the
360+
* given name.
361+
*
362+
* @param [Prototype] prototype the target prototype
363+
* @param [String] stub stub name to add (e.g. "$foo")
364+
*/
313365
function add_stub_for(prototype, stub) {
314366
function method_missing_stub() {
367+
// Copy any given block onto the method_missing dispatcher
315368
this.$method_missing._p = method_missing_stub._p;
369+
370+
// Set block property to null ready for the next call (stop false-positives)
316371
method_missing_stub._p = null;
317372

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

321377
method_missing_stub.rb_stub = true;
322378
prototype[stub] = method_missing_stub;
323379
}
324380

381+
// Expose for other parts of Opal to use
325382
Opal.add_stub_for = add_stub_for;
326383

327384
// Const missing dispatcher
@@ -393,12 +450,12 @@
393450
};
394451

395452
/*
396-
Used to return as an expression. Sometimes, we can't simply return from
397-
a javascript function as if we were a method, as the return is used as
398-
an expression, or even inside a block which must "return" to the outer
399-
method. This helper simply throws an error which is then caught by the
400-
method. This approach is expensive, so it is only used when absolutely
401-
needed.
453+
* Used to return as an expression. Sometimes, we can't simply return from
454+
* a javascript function as if we were a method, as the return is used as
455+
* an expression, or even inside a block which must "return" to the outer
456+
* method. This helper simply throws an error which is then caught by the
457+
* method. This approach is expensive, so it is only used when absolutely
458+
* needed.
402459
*/
403460
Opal.$return = function(val) {
404461
Opal.returner.$v = val;

0 commit comments

Comments
 (0)