opal/corelib/runtime.js in opal-1.5.1 vs opal/corelib/runtime.js in opal-1.6.0.alpha1
- old
+ new
@@ -21,14 +21,16 @@
if (typeof(globalThis) !== 'undefined') { global_object = globalThis; }
else if (typeof(global) !== 'undefined') { global_object = global; }
else if (typeof(window) !== 'undefined') { global_object = window; }
// Setup a dummy console object if missing
+ if (global_object.console == null) {
+ global_object.console = {};
+ }
+
if (typeof(global_object.console) === 'object') {
console = global_object.console;
- } else if (global_object.console == null) {
- console = global_object.console = {};
} else {
console = {};
}
if (!('log' in console)) { console.log = function () {}; }
@@ -63,11 +65,10 @@
// The Opal object that is exposed globally
var Opal = global_object.Opal = {};
// This is a useful reference to global object inside ruby files
Opal.global = global_object;
- global_object.Opal = Opal;
// Configure runtime behavior with regards to require and unsupported features
Opal.config = {
missing_require_severity: 'error', // error, warning, ignore
unsupported_features_severity: 'warning', // error, warning, ignore
@@ -88,45 +89,45 @@
// Generates even sequential numbers greater than 4
// (nil_id) to serve as unique ids for ruby objects
var unique_id = nil_id;
// Return next unique id
- Opal.uid = function() {
+ function $uid() {
unique_id += 2;
return unique_id;
};
+ Opal.uid = $uid;
// Retrieve or assign the id of an object
Opal.id = function(obj) {
if (obj.$$is_number) return (obj * 2)+1;
- if (obj.$$id != null) {
- return obj.$$id;
+ if (obj.$$id == null) {
+ $prop(obj, '$$id', $uid());
}
- $prop(obj, '$$id', Opal.uid());
return obj.$$id;
};
// Globals table
- Opal.gvars = {};
+ var $gvars = Opal.gvars = {};
// Exit function, this should be replaced by platform specific implementation
// (See nodejs and chrome for examples)
- Opal.exit = function(status) { if (Opal.gvars.DEBUG) console.log('Exited with status '+status); };
+ Opal.exit = function(status) { if ($gvars.DEBUG) console.log('Exited with status '+status); };
// keeps track of exceptions for $!
Opal.exceptions = [];
// @private
// Pops an exception from the stack and updates `$!`.
Opal.pop_exception = function() {
var exception = Opal.exceptions.pop();
if (exception) {
- Opal.gvars["!"] = exception;
- Opal.gvars["@"] = exception.$backtrace();
+ $gvars["!"] = exception;
+ $gvars["@"] = exception.$backtrace();
}
else {
- Opal.gvars["!"] = Opal.gvars["@"] = nil;
+ $gvars["!"] = $gvars["@"] = nil;
}
};
function $prop(object, name, initialValue) {
if (typeof(object) === "string") {
@@ -306,11 +307,11 @@
function const_lookup_ancestors(cref, name) {
var i, ii, ancestors;
if (cref == null) return;
- ancestors = Opal.ancestors(cref);
+ ancestors = $ancestors(cref);
for (i = 0, ii = ancestors.length; i < ii; i++) {
if (ancestors[i].$$const && $has_own.call(ancestors[i].$$const, name)) {
return ancestors[i].$$const[name];
} else if (ancestors[i].$$autoload && ancestors[i].$$autoload[name]) {
@@ -326,14 +327,12 @@
return const_lookup_ancestors(_Object, name);
}
}
// Call const_missing if nothing else worked
- function const_missing(cref, name, skip_missing) {
- if (!skip_missing) {
- return (cref || _Object).$const_missing(name);
- }
+ function const_missing(cref, name) {
+ return (cref || _Object).$const_missing(name);
}
// Look for the constant just in the current cref or call `#const_missing`
Opal.const_get_local = function(cref, name, skip_missing) {
var result;
@@ -344,12 +343,12 @@
if (!cref.$$is_module && !cref.$$is_class) {
throw new Opal.TypeError(cref.toString() + " is not a class/module");
}
- result = const_get_name(cref, name); if (result != null) return result;
- result = const_missing(cref, name, skip_missing); if (result != null) return result;
+ result = const_get_name(cref, name);
+ return result != null || skip_missing ? result : const_missing(cref, name);
};
// Look for the constant relative to a cref or call `#const_missing` (when the
// constant is prefixed by `::`).
Opal.const_get_qualified = function(cref, name, skip_missing) {
@@ -383,11 +382,11 @@
cache[name] = [current_version, result];
} else {
result = cached[1];
}
- return result != null ? result : const_missing(cref, name, skip_missing);
+ return result != null || skip_missing ? result : const_missing(cref, name);
};
// Initialize the top level constant cache generation counter
Opal.const_cache_version = 1;
@@ -411,11 +410,11 @@
cache[name] = [current_version, result];
} else {
result = cached[1];
}
- return result != null ? result : const_missing(cref, name, skip_missing);
+ return result != null || skip_missing ? result : const_missing(cref, name);
};
// Register the constant on a cref and opportunistically set the name of
// unnamed classes/modules.
function $const_set(cref, name, value) {
@@ -452,12 +451,12 @@
Opal.constants = function(cref, inherit) {
if (inherit == null) inherit = true;
var module, modules = [cref], i, ii, constants = {}, constant;
- if (inherit) modules = modules.concat(Opal.ancestors(cref));
- if (inherit && cref.$$is_module) modules = modules.concat([Opal.Object]).concat(Opal.ancestors(Opal.Object));
+ if (inherit) modules = modules.concat($ancestors(cref));
+ if (inherit && cref.$$is_module) modules = modules.concat([Opal.Object]).concat($ancestors(Opal.Object));
for (i = 0, ii = modules.length; i < ii; i++) {
module = modules[i];
// Do not show Objects constants unless we're querying Object itself
@@ -532,37 +531,35 @@
// @param singleton [Boolean,null] a true value denotes we want to allocate
// a singleton
//
// @return new [Class] or existing ruby class
//
- Opal.allocate_class = function(name, superclass, singleton) {
- var klass, constructor;
+ function $allocate_class(name, superclass, singleton) {
+ var klass;
if (superclass != null && superclass.$$bridge) {
// Inheritance from bridged classes requires
// calling original JS constructors
- constructor = function() {
+ klass = function() {
var args = $slice.call(arguments),
self = new ($bind.apply(superclass.$$constructor, [null].concat(args)))();
// and replacing a __proto__ manually
$set_proto(self, klass.$$prototype);
return self;
}
} else {
- constructor = function(){};
+ klass = function(){};
}
if (name && name !== nil) {
- $prop(constructor, 'displayName', '::'+name);
+ $prop(klass, 'displayName', '::'+name);
}
- klass = constructor;
-
$prop(klass, '$$name', name);
- $prop(klass, '$$constructor', constructor);
- $prop(klass, '$$prototype', constructor.prototype);
+ $prop(klass, '$$constructor', klass);
+ $prop(klass, '$$prototype', klass.prototype);
$prop(klass, '$$const', {});
$prop(klass, '$$is_class', true);
$prop(klass, '$$is_a_module', true);
$prop(klass, '$$super', superclass);
$prop(klass, '$$cvars', {});
@@ -612,10 +609,11 @@
}
}
return klass;
};
+ Opal.allocate_class = $allocate_class;
function find_existing_class(scope, name) {
// Try to find the class in the current scope
var klass = const_get_name(scope, name);
@@ -665,41 +663,38 @@
}
}
var klass = find_existing_class(scope, name);
- if (klass) {
+ if (klass != null) {
if (superclass) {
// Make sure existing class has same superclass
ensureSuperclassMatch(klass, superclass);
}
-
- if (Opal.trace_class) { invoke_tracers_for_class(klass); }
-
- return klass;
}
+ else {
+ // Class doesn't exist, create a new one with given superclass...
- // Class doesn't exist, create a new one with given superclass...
+ // Not specifying a superclass means we can assume it to be Object
+ if (superclass == null) {
+ superclass = _Object;
+ }
- // Not specifying a superclass means we can assume it to be Object
- if (superclass == null) {
- superclass = _Object;
- }
+ // Create the class object (instance of Class)
+ klass = $allocate_class(name, superclass);
+ $const_set(scope, name, klass);
- // Create the class object (instance of Class)
- klass = Opal.allocate_class(name, superclass);
- $const_set(scope, name, klass);
+ // Call .inherited() hook with new class on the superclass
+ if (superclass.$inherited) {
+ superclass.$inherited(klass);
+ }
- // Call .inherited() hook with new class on the superclass
- if (superclass.$inherited) {
- superclass.$inherited(klass);
+ if (bridged) {
+ Opal.bridge(bridged, klass);
+ }
}
- if (bridged) {
- Opal.bridge(bridged, klass);
- }
-
if (Opal.trace_class) { invoke_tracers_for_class(klass); }
return klass;
};
@@ -720,16 +715,12 @@
//
// @param scope [Module, Class] class or module this definition is inside
// @param id [String] the name of the new (or existing) module
//
// @return [Module]
- Opal.allocate_module = function(name) {
+ function $allocate_module(name) {
var constructor = function(){};
- if (name) {
- $prop(constructor, 'displayName', name+'.$$constructor');
- }
-
var module = constructor;
if (name)
$prop(constructor, 'displayName', name+'.constructor');
@@ -747,10 +738,11 @@
$set_proto(module, Opal.Module.prototype);
return module;
};
+ Opal.allocate_module = $allocate_module;
function find_existing_module(scope, name) {
var module = const_get_name(scope, name);
if (module == null && scope === _Object) module = const_lookup_ancestors(_Object, name);
@@ -774,21 +766,16 @@
scope = scope.$$class;
}
module = find_existing_module(scope, name);
- if (module) {
-
- if (Opal.trace_class) { invoke_tracers_for_class(module); }
-
- return module;
+ if (module == null) {
+ // Module doesnt exist, create a new one...
+ module = $allocate_module(name);
+ $const_set(scope, name, module);
}
- // Module doesnt exist, create a new one...
- module = Opal.allocate_module(name);
- $const_set(scope, name, module);
-
if (Opal.trace_class) { invoke_tracers_for_class(module); }
return module;
};
@@ -815,37 +802,51 @@
} else {
return Opal.build_object_singleton_class(object);
}
};
+ // helper to set $$meta on klass, module or instance
+ function set_meta(obj, meta) {
+ if (obj.hasOwnProperty('$$meta')) {
+ obj.$$meta = meta;
+ } else {
+ $prop(obj, '$$meta', meta);
+ }
+ if (obj.$$frozen) {
+ // If a object is frozen (sealed), freeze $$meta too.
+ // No need to inject $$meta.$$prototype in the prototype chain,
+ // as $$meta cannot be modified anyway.
+ obj.$$meta.$freeze();
+ } else {
+ $set_proto(obj, meta.$$prototype);
+ }
+ };
+
// Build the singleton class for an existing class. Class object are built
// with their singleton class already in the prototype chain and inheriting
// from their superclass object (up to `Class` itself).
//
// NOTE: Actually in MRI a class' singleton class inherits from its
// superclass' singleton class which in turn inherits from Class.
//
// @param klass [Class]
// @return [Class]
Opal.build_class_singleton_class = function(klass) {
- var superclass, meta;
-
if (klass.$$meta) {
return klass.$$meta;
}
// The singleton_class superclass is the singleton_class of its superclass;
// but BasicObject has no superclass (its `$$super` is null), thus we
// fallback on `Class`.
- superclass = klass === BasicObject ? Class : Opal.get_singleton_class(klass.$$super);
+ var superclass = klass === BasicObject ? Class : Opal.get_singleton_class(klass.$$super);
- meta = Opal.allocate_class(null, superclass, true);
+ var meta = $allocate_class(null, superclass, true);
$prop(meta, '$$is_singleton', true);
$prop(meta, '$$singleton_of', klass);
- $prop(klass, '$$meta', meta);
- $set_proto(klass, meta.$$prototype);
+ set_meta(klass, meta);
// Restoring ClassName.class
$prop(klass, '$$class', Opal.Class);
return meta;
};
@@ -853,16 +854,15 @@
Opal.build_module_singleton_class = function(mod) {
if (mod.$$meta) {
return mod.$$meta;
}
- var meta = Opal.allocate_class(null, Opal.Module, true);
+ var meta = $allocate_class(null, Opal.Module, true);
$prop(meta, '$$is_singleton', true);
$prop(meta, '$$singleton_of', mod);
- $prop(mod, '$$meta', meta);
- $set_proto(mod, meta.$$prototype);
+ set_meta(mod, meta);
// Restoring ModuleName.class
$prop(mod, '$$class', Opal.Module);
return meta;
};
@@ -871,30 +871,28 @@
//
// @param object [Object]
// @return [Class]
Opal.build_object_singleton_class = function(object) {
var superclass = object.$$class,
- klass = Opal.allocate_class(nil, superclass, true);
+ klass = $allocate_class(nil, superclass, true);
$prop(klass, '$$is_singleton', true);
$prop(klass, '$$singleton_of', object);
delete klass.$$prototype.$$class;
- $prop(object, '$$meta', klass);
+ set_meta(object, klass);
- $set_proto(object, object.$$meta.$$prototype);
-
return klass;
};
Opal.is_method = function(prop) {
return (prop[0] === '$' && prop[1] !== '$');
};
Opal.instance_methods = function(mod) {
- var exclude = [], results = [], ancestors = Opal.ancestors(mod);
+ var exclude = [], results = [], ancestors = $ancestors(mod);
for (var i = 0, l = ancestors.length; i < l; i++) {
var ancestor = ancestors[i],
proto = ancestor.$$prototype;
@@ -954,16 +952,11 @@
Opal.methods = function(obj) {
return Opal.instance_methods(obj.$$meta || obj.$$class);
};
Opal.own_methods = function(obj) {
- if (obj.$$meta) {
- return Opal.own_instance_methods(obj.$$meta);
- }
- else {
- return [];
- }
+ return obj.$$meta ? Opal.own_instance_methods(obj.$$meta) : [];
};
Opal.receiver_methods = function(obj) {
var mod = Opal.get_singleton_class(obj);
var singleton_methods = Opal.own_instance_methods(mod);
@@ -976,11 +969,11 @@
// and its ancestors.
//
// @param module [Module]
// @return [Object]
Opal.class_variables = function(module) {
- var ancestors = Opal.ancestors(module),
+ var ancestors = $ancestors(module),
i, length = ancestors.length,
result = {};
for (i = length - 1; i >= 0; i--) {
var ancestor = ancestors[i];
@@ -998,11 +991,11 @@
//
// @param module [Module]
// @param name [String]
// @param value [Object]
Opal.class_variable_set = function(module, name, value) {
- var ancestors = Opal.ancestors(module),
+ var ancestors = $ancestors(module),
i, length = ancestors.length;
for (i = length - 2; i >= 0; i--) {
var ancestor = ancestors[i];
@@ -1023,11 +1016,11 @@
// @param name [String]
Opal.class_variable_get = function(module, name, tolerant) {
if ($has_own.call(module.$$cvars, name))
return module.$$cvars[name];
- var ancestors = Opal.ancestors(module),
+ var ancestors = $ancestors(module),
i, length = ancestors.length;
for (i = 0; i < length; i++) {
var ancestor = ancestors[i];
@@ -1103,11 +1096,11 @@
//
// @param module [Module] the module to include
// @param includer [Module] the target class to include module into
// @return [null]
Opal.append_features = function(module, includer) {
- var module_ancestors = Opal.ancestors(module);
+ var module_ancestors = $ancestors(module);
var iclasses = [];
if (module_ancestors.indexOf(includer) !== -1) {
throw Opal.ArgumentError.$new('cyclic include detected');
}
@@ -1115,11 +1108,11 @@
for (var i = 0, length = module_ancestors.length; i < length; i++) {
var ancestor = module_ancestors[i], iclass = create_iclass(ancestor);
$prop(iclass, '$$included', true);
iclasses.push(iclass);
}
- var includer_ancestors = Opal.ancestors(includer),
+ var includer_ancestors = $ancestors(includer),
chain = chain_iclasses(iclasses),
start_chain_after,
end_chain_on;
if (includer_ancestors.indexOf(module) === -1) {
@@ -1208,11 +1201,11 @@
// iclass(module)
// |
// iclass(prepender)
// |
// parent
- var module_ancestors = Opal.ancestors(module);
+ var module_ancestors = $ancestors(module);
var iclasses = [];
if (module_ancestors.indexOf(prepender) !== -1) {
throw Opal.ArgumentError.$new('cyclic prepend detected');
}
@@ -1247,11 +1240,11 @@
// dummy(prepender) -> iclass(prepender) -> previous_parent
$set_proto(dummy_prepender, prepender_iclass);
$set_proto(prepender_iclass, previous_parent);
}
- var prepender_ancestors = Opal.ancestors(prepender);
+ var prepender_ancestors = $ancestors(prepender);
if (prepender_ancestors.indexOf(module) === -1) {
// first time prepend
start_chain_after = dummy_prepender;
@@ -1407,11 +1400,11 @@
function own_ancestors(module) {
return module.$$own_prepended_modules.concat([module]).concat(module.$$own_included_modules);
}
// The Array of ancestors for a given module/class
- Opal.ancestors = function(module) {
+ function $ancestors(module) {
if (!module) { return []; }
if (module.$$ancestors_cache_version === Opal.const_cache_version) {
return module.$$ancestors;
}
@@ -1421,20 +1414,21 @@
for (i = 0, mods = own_ancestors(module), length = mods.length; i < length; i++) {
result.push(mods[i]);
}
if (module.$$super) {
- for (i = 0, mods = Opal.ancestors(module.$$super), length = mods.length; i < length; i++) {
+ for (i = 0, mods = $ancestors(module.$$super), length = mods.length; i < length; i++) {
result.push(mods[i]);
}
}
module.$$ancestors_cache_version = Opal.const_cache_version;
module.$$ancestors = result;
return result;
};
+ Opal.ancestors = $ancestors;
Opal.included_modules = function(module) {
var result = [], mod = null, proto = Object.getPrototypeOf(module.$$prototype);
for (; proto && Object.getPrototypeOf(proto); proto = Object.getPrototypeOf(proto)) {
@@ -1512,11 +1506,11 @@
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)
- delete method_missing_stub.$$p;
+ method_missing_stub.$$p = null;
// call method missing with correct args (remove '$' prefix on method name)
var args_ary = new Array(arguments.length);
for(var i = 0, l = args_ary.length; i < l; i++) { args_ary[i] = arguments[i]; }
@@ -1562,19 +1556,23 @@
var inspect = "`block in " + context + "'";
throw Opal.ArgumentError.$new(inspect + ': wrong number of arguments (given ' + actual + ', expected ' + expected + ')');
};
+ function get_ancestors(obj) {
+ if (obj.hasOwnProperty('$$meta') && obj.$$meta !== null) {
+ return $ancestors(obj.$$meta);
+ } else {
+ return $ancestors(obj.$$class);
+ }
+ };
+
// Super dispatcher
Opal.find_super = function(obj, mid, current_func, defcheck, allow_stubs) {
var jsid = '$' + mid, ancestors, super_method;
- if (obj.hasOwnProperty('$$meta')) {
- ancestors = Opal.ancestors(obj.$$meta);
- } else {
- ancestors = Opal.ancestors(obj.$$class);
- }
+ ancestors = get_ancestors(obj);
var current_index = ancestors.indexOf(current_func.$$owner);
for (var i = current_index + 1; i < ancestors.length; i++) {
var ancestor = ancestors[i],
@@ -1624,34 +1622,10 @@
Opal.find_super_dispatcher = Opal.find_super;
// @deprecated
Opal.find_iter_super_dispatcher = Opal.find_block_super;
- // 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.ret = function(val) {
- Opal.returner.$v = val;
- throw Opal.returner;
- };
-
- // Used to break out of a block.
- Opal.brk = function(val, breaker) {
- breaker.$v = val;
- throw breaker;
- };
-
- // Builds a new unique breaker, this is to avoid multiple nested breaks to get
- // in the way of each other.
- Opal.new_brk = function() {
- return new Error('unexpected break');
- };
-
// handles yield calls for 1 yielded arg
Opal.yield1 = function(block, arg) {
if (typeof(block) !== "function") {
throw Opal.LocalJumpError.$new("no block given");
}
@@ -1704,16 +1678,13 @@
if (result) {
return result;
}
}
- else if (candidate === Opal.JS.Error) {
+ else if (candidate === Opal.JS.Error || candidate['$==='](exception)) {
return candidate;
}
- else if (candidate['$==='](exception)) {
- return candidate;
- }
}
return null;
};
@@ -1724,11 +1695,11 @@
if (object.$$is_number && klass.$$is_number_class) {
return (klass.$$is_integer_class) ? (object % 1) === 0 : true;
}
- var ancestors = Opal.ancestors(object.$$is_class ? Opal.get_singleton_class(object) : (object.$$meta || object.$$class));
+ var ancestors = $ancestors(object.$$is_class ? Opal.get_singleton_class(object) : (object.$$meta || object.$$class));
return ancestors.indexOf(klass) !== -1;
};
// Helpers for extracting kwsplats
@@ -1813,15 +1784,12 @@
//
Opal.extract_kwargs = function(parameters) {
var kwargs = parameters[parameters.length - 1];
if (kwargs != null && Opal.respond_to(kwargs, '$to_hash', true)) {
$splice.call(parameters, parameters.length - 1);
- return kwargs.$to_hash();
+ return kwargs;
}
- else {
- return Opal.hash2([], {});
- }
};
// Used to get a list of rest keyword arguments. Method takes the given
// keyword args, i.e. the hash literal passed to the method containing all
// keyword arguemnts passed to method, as well as the used args which are
@@ -1911,37 +1879,37 @@
};
Opal.refined_send = function(refinement_groups, recv, method, args, block, blockopts) {
var i, j, k, ancestors, ancestor, refinements, refinement, refine_modules, refine_module, body;
- if (recv.hasOwnProperty('$$meta')) {
- ancestors = Opal.ancestors(recv.$$meta);
- } else {
- ancestors = Opal.ancestors(recv.$$class);
- }
+ ancestors = get_ancestors(recv);
// For all ancestors that there are, starting from the closest to the furthest...
for (i = 0; i < ancestors.length; i++) {
ancestor = Opal.id(ancestors[i]);
+
// For all refinement groups there are, starting from the closest scope to the furthest...
for (j = 0; j < refinement_groups.length; j++) {
refinements = refinement_groups[j];
+
// For all refinements there are, starting from the last `using` call to the furthest...
for (k = refinements.length - 1; k >= 0; k--) {
refinement = refinements[k];
if (typeof refinement.$$refine_modules === 'undefined') continue;
+
// A single module being given as an argument of the `using` call contains multiple
// refinement modules
refine_modules = refinement.$$refine_modules;
+
// Does this module refine a given call for a given ancestor module?
- if (typeof refine_modules[ancestor] !== 'undefined') {
- refine_module = refine_modules[ancestor];
- // Does this module define a method we want to call?
- if (typeof refine_module.$$prototype['$'+method] !== 'undefined') {
- body = refine_module.$$prototype['$'+method];
- return Opal.send2(recv, body, method, args, block, blockopts);
- }
+ if (typeof refine_modules[ancestor] === 'undefined') continue;
+ refine_module = refine_modules[ancestor];
+
+ // Does this module define a method we want to call?
+ if (typeof refine_module.$$prototype['$'+method] !== 'undefined') {
+ body = refine_module.$$prototype['$'+method];
+ return Opal.send2(recv, body, method, args, block, blockopts);
}
}
}
}
@@ -2010,10 +1978,12 @@
}
};
// Define method on a module or class (see Opal.def).
Opal.defn = function(module, jsid, body) {
+ $deny_frozen_access(module);
+
body.displayName = jsid;
body.$$owner = module;
var name = jsid.substr(1);
@@ -2147,11 +2117,11 @@
args = new Array(arguments.length);
for(i = 0, ii = arguments.length; i < ii; i++) {
args[i] = arguments[i];
}
- delete alias.$$p;
+ alias.$$p = null;
return Opal.send(this, body, args, block);
};
// Assign the 'length' value with defineProperty because
@@ -2175,18 +2145,18 @@
return obj;
};
Opal.alias_gvar = function(new_name, old_name) {
- Object.defineProperty(Opal.gvars, new_name, {
+ Object.defineProperty($gvars, new_name, {
configurable: true,
enumerable: true,
get: function() {
- return Opal.gvars[old_name];
+ return $gvars[old_name];
},
set: function(new_value) {
- Opal.gvars[old_name] = new_value;
+ $gvars[old_name] = new_value;
}
});
return nil;
}
@@ -2428,39 +2398,41 @@
}
hash = new Opal.Hash();
Opal.hash_init(hash);
- if (arguments_length === 1 && arguments[0].$$is_array) {
+ if (arguments_length === 1) {
args = arguments[0];
- length = args.length;
- for (i = 0; i < length; i++) {
- if (args[i].length !== 2) {
- throw Opal.ArgumentError.$new("value not of length 2: " + args[i].$inspect());
- }
+ if (arguments[0].$$is_array) {
+ length = args.length;
- key = args[i][0];
- value = args[i][1];
+ for (i = 0; i < length; i++) {
+ if (args[i].length !== 2) {
+ throw Opal.ArgumentError.$new("value not of length 2: " + args[i].$inspect());
+ }
- Opal.hash_put(hash, key, value);
- }
+ key = args[i][0];
+ value = args[i][1];
- return hash;
- }
-
- if (arguments_length === 1) {
- args = arguments[0];
- for (key in args) {
- if ($has_own.call(args, key)) {
- value = args[key];
-
Opal.hash_put(hash, key, value);
}
+
+ return hash;
}
+ else {
+ args = arguments[0];
+ for (key in args) {
+ if ($has_own.call(args, key)) {
+ value = args[key];
- return hash;
+ Opal.hash_put(hash, key, value);
+ }
+ }
+
+ return hash;
+ }
}
if (arguments_length % 2 !== 0) {
throw Opal.ArgumentError.$new("odd number of arguments for Hash");
}
@@ -2500,35 +2472,94 @@
range.excl = exc;
return range;
};
+ var reserved_ivar_names = [
+ // properties
+ "constructor", "displayName", "__count__", "__noSuchMethod__",
+ "__parent__", "__proto__",
+ // methods
+ "hasOwnProperty", "valueOf"
+ ];
+
// Get the ivar name for a given name.
// Mostly adds a trailing $ to reserved names.
//
Opal.ivar = function(name) {
- if (
- // properties
- name === "constructor" ||
- name === "displayName" ||
- name === "__count__" ||
- name === "__noSuchMethod__" ||
- name === "__parent__" ||
- name === "__proto__" ||
-
- // methods
- name === "hasOwnProperty" ||
- name === "valueOf"
- )
- {
- return name + "$";
+ if (reserved_ivar_names.indexOf(name) !== -1) {
+ name += "$";
}
return name;
};
+ // Support for #freeze
+ // -------------------
+ // helper that can be used from methods
+ function $deny_frozen_access(obj) {
+ if (obj.$$frozen) {
+ throw Opal.FrozenError.$new("can't modify frozen " + (obj.$class()) + ": " + (obj), Opal.hash2(["receiver"], {"receiver": obj}));
+ }
+ };
+ Opal.deny_frozen_access = $deny_frozen_access;
+
+ // common #freeze runtime support
+ Opal.freeze = function(obj) {
+ $prop(obj, "$$frozen", true);
+
+ // set $$id
+ if (!obj.hasOwnProperty('$$id')) { $prop(obj, '$$id', $uid()); }
+
+ if (obj.hasOwnProperty('$$meta')) {
+ // freeze $$meta if it has already been set
+ obj.$$meta.$freeze();
+ } else {
+ // ensure $$meta can be set lazily, $$meta is frozen when set in runtime.js
+ $prop(obj, '$$meta', null);
+ }
+
+ // $$comparable is used internally and set multiple times
+ // defining it before sealing ensures it can be modified later on
+ if (!obj.hasOwnProperty('$$comparable')) { $prop(obj, '$$comparable', null); }
+
+ // seal the Object
+ Object.seal(obj);
+
+ return obj;
+ };
+
+ // freze props, make setters of instance variables throw FrozenError
+ Opal.freeze_props = function(obj) {
+ var prop, prop_type, desc;
+
+ for(prop in obj) {
+ prop_type = typeof(prop);
+
+ // prop_type "object" here is a String(), skip $ props
+ if ((prop_type === "string" || prop_type === "object") && prop[0] === '$') {
+ continue;
+ }
+
+ desc = Object.getOwnPropertyDescriptor(obj, prop);
+ if (desc && desc.enumerable && desc.writable) {
+ // create closure to retain current value as cv
+ // for Opal 2.0 let for cv should do the trick, instead of a function
+ (function() {
+ // set v to undefined, as if the property is not set
+ var cv = obj[prop];
+ Object.defineProperty(obj, prop, {
+ get: function() { return cv; },
+ set: function(_val) { $deny_frozen_access(obj); },
+ enumerable: true
+ });
+ })();
+ }
+ }
+ };
+
// Regexps
// -------
// Escape Regexp special chars letting the resulting string be used to build
// a new Regexp.
@@ -2558,25 +2589,27 @@
// Create a global multiline Regexp from a RegExp object and cache the result
// on the object itself ($$gm or $$g attribute).
//
Opal.global_multiline_regexp = function(pattern) {
- var result;
+ var result, flags;
+
+ // RegExp already has the global and multiline flag
+ if (pattern.global && pattern.multiline) return pattern;
+
+ flags = 'gm' + (pattern.ignoreCase ? 'i' : '');
if (pattern.multiline) {
- if (pattern.global) {
- return pattern; // RegExp already has the global and multiline flag
- }
// we are using the $$g attribute because the Regexp is already multiline
- if (pattern.$$g != null) {
- result = pattern.$$g;
- } else {
- result = pattern.$$g = new RegExp(pattern.source, 'gm' + (pattern.ignoreCase ? 'i' : ''));
+ if (pattern.$$g == null) {
+ pattern.$$g = new RegExp(pattern.source, flags);
}
- } else if (pattern.$$gm != null) {
- result = pattern.$$gm;
+ result = pattern.$$g;
} else {
- result = pattern.$$gm = new RegExp(pattern.source, 'gm' + (pattern.ignoreCase ? 'i' : ''));
+ if (pattern.$$gm == null) {
+ pattern.$$gm = new RegExp(pattern.source, flags);
+ }
+ result = pattern.$$gm;
}
result.lastIndex = null; // reset lastIndex property
return result;
};
@@ -2648,13 +2681,11 @@
Opal.loaded_features.push(path);
Opal.require_table[path] = true;
}
};
- Opal.load = function(path) {
- path = Opal.normalize(path);
-
+ Opal.load_normalized = function(path) {
Opal.loaded([path]);
var module = Opal.modules[path];
if (module) {
@@ -2682,18 +2713,24 @@
}
return true;
};
+ Opal.load = function(path) {
+ path = Opal.normalize(path);
+
+ return Opal.load_normalized(path);
+ };
+
Opal.require = function(path) {
path = Opal.normalize(path);
if (Opal.require_table[path]) {
return false;
}
- return Opal.load(path);
+ return Opal.load_normalized(path);
};
// Strings
// -------
@@ -2773,46 +2810,41 @@
}
}
// Operator helpers
// ----------------
- Opal.rb_plus = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l + r : l['$+'](r); }
- Opal.rb_minus = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l - r : l['$-'](r); }
- Opal.rb_times = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l * r : l['$*'](r); }
- Opal.rb_divide = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l / r : l['$/'](r); }
- Opal.rb_lt = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l < r : l['$<'](r); }
- Opal.rb_gt = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l > r : l['$>'](r); }
- Opal.rb_le = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l <= r : l['$<='](r); }
- Opal.rb_ge = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l >= r : l['$>='](r); }
+ function are_both_numbers(l,r) { return typeof(l) === 'number' && typeof(r) === 'number' }
+
+ Opal.rb_plus = function(l,r) { return are_both_numbers(l,r) ? l + r : l['$+'](r); }
+ Opal.rb_minus = function(l,r) { return are_both_numbers(l,r) ? l - r : l['$-'](r); }
+ Opal.rb_times = function(l,r) { return are_both_numbers(l,r) ? l * r : l['$*'](r); }
+ Opal.rb_divide = function(l,r) { return are_both_numbers(l,r) ? l / r : l['$/'](r); }
+ Opal.rb_lt = function(l,r) { return are_both_numbers(l,r) ? l < r : l['$<'](r); }
+ Opal.rb_gt = function(l,r) { return are_both_numbers(l,r) ? l > r : l['$>'](r); }
+ Opal.rb_le = function(l,r) { return are_both_numbers(l,r) ? l <= r : l['$<='](r); }
+ Opal.rb_ge = function(l,r) { return are_both_numbers(l,r) ? l >= r : l['$>='](r); }
+
// Optimized helpers for calls like $truthy((a)['$==='](b)) -> $eqeqeq(a, b)
+ function are_both_numbers_or_strings(lhs, rhs) {
+ return (typeof lhs === 'number' && typeof rhs === 'number') ||
+ (typeof lhs === 'string' && typeof rhs === 'string');
+ }
+
function $eqeq(lhs, rhs) {
- if ((typeof lhs === 'number' && typeof rhs === 'number') ||
- (typeof lhs === 'string' && typeof rhs === 'string')) {
- return lhs === rhs;
- }
- return $truthy((lhs)['$=='](rhs));
+ return are_both_numbers_or_strings(lhs,rhs) ? lhs === rhs : $truthy((lhs)['$=='](rhs));
};
Opal.eqeq = $eqeq;
-
Opal.eqeqeq = function(lhs, rhs) {
- if ((typeof lhs === 'number' && typeof rhs === 'number') ||
- (typeof lhs === 'string' && typeof rhs === 'string')) {
- return lhs === rhs;
- }
- return $truthy((lhs)['$==='](rhs));
+ return are_both_numbers_or_strings(lhs,rhs) ? lhs === rhs : $truthy((lhs)['$==='](rhs));
};
Opal.neqeq = function(lhs, rhs) {
- if ((typeof lhs === 'number' && typeof rhs === 'number') ||
- (typeof lhs === 'string' && typeof rhs === 'string')) {
- return lhs !== rhs;
- }
- return $truthy((lhs)['$!='](rhs));
+ return are_both_numbers_or_strings(lhs,rhs) ? lhs !== rhs : $truthy((lhs)['$!='](rhs));
};
Opal.not = function(arg) {
- if (true === arg) return false;
if (undefined === arg || null === arg || false === arg || nil === arg) return true;
+ if (true === arg || arg['$!'].$$pristine) return false;
return $truthy(arg['$!']());
}
// Shortcuts - optimized function generators for simple kinds of functions
function $return_val(arg) {
@@ -2825,41 +2857,61 @@
Opal.return_self = function() {
return this;
}
Opal.return_ivar = function(ivar) {
return function() {
- if (this[ivar] == null) this[ivar] = nil;
+ if (this[ivar] == null) { return nil; }
return this[ivar];
}
}
Opal.assign_ivar = function(ivar) {
return function(val) {
+ $deny_frozen_access(this);
return this[ivar] = val;
}
}
Opal.assign_ivar_val = function(ivar, static_val) {
return function() {
+ $deny_frozen_access(this);
return this[ivar] = static_val;
}
}
+ // Primitives for handling parameters
+ Opal.ensure_kwargs = function(kwargs) {
+ if (kwargs == null) {
+ return Opal.hash2([], {});
+ } else if (kwargs.$$is_hash) {
+ return kwargs;
+ } else {
+ throw Opal.ArgumentError.$new('expected kwargs');
+ }
+ }
+
+ Opal.get_kwarg = function(kwargs, key) {
+ if (!$has_own.call(kwargs.$$smap, key)) {
+ throw Opal.ArgumentError.$new('missing keyword: '+key);
+ }
+ return kwargs.$$smap[key];
+ }
+
// Initialization
// --------------
- Opal.BasicObject = BasicObject = Opal.allocate_class('BasicObject', null);
- Opal.Object = _Object = Opal.allocate_class('Object', Opal.BasicObject);
- Opal.Module = Module = Opal.allocate_class('Module', Opal.Object);
- Opal.Class = Class = Opal.allocate_class('Class', Opal.Module);
- Opal.Opal = _Opal = Opal.allocate_module('Opal');
- Opal.Kernel = Kernel = Opal.allocate_module('Kernel');
+ Opal.BasicObject = BasicObject = $allocate_class('BasicObject', null);
+ Opal.Object = _Object = $allocate_class('Object', Opal.BasicObject);
+ Opal.Module = Module = $allocate_class('Module', Opal.Object);
+ Opal.Class = Class = $allocate_class('Class', Opal.Module);
+ Opal.Opal = _Opal = $allocate_module('Opal');
+ Opal.Kernel = Kernel = $allocate_module('Kernel');
$set_proto(Opal.BasicObject, Opal.Class.$$prototype);
$set_proto(Opal.Object, Opal.Class.$$prototype);
$set_proto(Opal.Module, Opal.Class.$$prototype);
$set_proto(Opal.Class, Opal.Class.$$prototype);
// BasicObject can reach itself, avoid const_set to skip the $$base_module logic
- BasicObject.$$const["BasicObject"] = BasicObject;
+ BasicObject.$$const.BasicObject = BasicObject;
// Assign basic constants
$const_set(_Object, "BasicObject", BasicObject);
$const_set(_Object, "Object", _Object);
$const_set(_Object, "Module", Module);
@@ -2897,21 +2949,38 @@
// Foward calls to define_method on the top object to Object
function top_define_method() {
var args = Opal.slice.call(arguments);
var block = top_define_method.$$p;
- delete top_define_method.$$p;
+ top_define_method.$$p = null;
return Opal.send(_Object, 'define_method', args, block)
};
// Nil
- Opal.NilClass = Opal.allocate_class('NilClass', Opal.Object);
+ Opal.NilClass = $allocate_class('NilClass', Opal.Object);
$const_set(_Object, 'NilClass', Opal.NilClass);
nil = Opal.nil = new Opal.NilClass();
nil.$$id = nil_id;
nil.call = nil.apply = function() { throw Opal.LocalJumpError.$new('no block given'); };
+ nil.$$frozen = true;
+ nil.$$comparable = false;
+ Object.seal(nil);
- // Errors
- Opal.breaker = new Error('unexpected break (old)');
- Opal.returner = new Error('unexpected return');
+ Opal.thrower = function(type) {
+ var thrower = new Error('unexpected '+type);
+ thrower.$thrower_type = type;
+ thrower.$throw = function(value) {
+ if (value == null) value = nil;
+ thrower.$v = value;
+ throw thrower;
+ };
+ return thrower;
+ };
+
+ Opal.t_eval_return = Opal.thrower("return");
+
TypeError.$$super = Error;
+
+ // If enable-file-source-embed compiler option is enabled, each module loaded will add its
+ // sources to this object
+ Opal.file_sources = {};
}).call(this);