Skip to content

Commit

Permalink
Add some more documentation to runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
adambeynon committed Sep 26, 2013
1 parent 89ba3ce commit 6e0f547
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 23 deletions.
2 changes: 1 addition & 1 deletion corelib/opal.rb
Expand Up @@ -51,7 +51,7 @@ def $stdout.puts(*strs)
if(strs[i] instanceof Array) {
#{ puts(*`strs[i]`) }
} else {
$opal.puts(#{ `strs[i]`.to_s });
console.log(#{`strs[i]`.to_s});

This comment has been minimized.

Copy link
@elia

elia Sep 26, 2013

Member

Is this on purpose or just debug stuff slipped in the commit? :)

This comment has been minimized.

Copy link
@adambeynon

adambeynon Sep 26, 2013

Author Contributor

On purpose. We used to use $opal.puts() to allow overriding, but now we have $stdout it is recommended to just override $stdout.puts() for custom behaviour (we need to update opalrb.org/try to use this approach as well - and possibly opal-irb @fkchang).

This comment has been minimized.

Copy link
@fkchang

fkchang Sep 26, 2013

Contributor

I need to keep this in mind. I wrote a log director so I could have various things listen (more or less an observer pattern impl) in on the console.log() call

}
}
}
Expand Down
101 changes: 79 additions & 22 deletions corelib/runtime.js
Expand Up @@ -198,7 +198,7 @@
if ($hasOwn.call(base._scope, id)) {
module = base._scope[id];

if (!module._mod$ && module !== RubyObject) {
if (!module.__mod__ && module !== RubyObject) {
throw Opal.TypeError.$new(id + " is not a module")
}
}
Expand All @@ -212,8 +212,11 @@
return 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;

Expand All @@ -230,7 +233,7 @@
module.__inc__ = [];
module.__parent = RubyModule;
module._proto = {};
module._mod$ = true;
module.__mod__ = true;
module.__dep__ = [];

return module;
Expand Down Expand Up @@ -279,26 +282,68 @@
return klass;
};

var bridge_class = function(name, constructor) {
var klass = boot_class(RubyObject, constructor), idx, length, mid;

bridged_classes.push(klass);

var table = RubyObject._proto, methods = RubyObject._methods;

for (idx = 0, len = methods.length; idx < len; idx++) {
mid = methods[idx];
constructor.prototype[mid] = table[mid];
}
/*
* 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(RubyObject, constructor);

klass._name = name;

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

return klass;
};

Opal.puts = function(a) { console.log(a); };

/*
* 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];
Expand All @@ -310,18 +355,30 @@
}
};

/*
* 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;
}

// Expose for other parts of Opal to use
Opal.add_stub_for = add_stub_for;

// Const missing dispatcher
Expand Down Expand Up @@ -393,12 +450,12 @@
};

/*
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.
* 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;
Expand Down

0 comments on commit 6e0f547

Please sign in to comment.