Skip to content

Commit

Permalink
Improve Module#constants etc by manually storing constants in scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
adambeynon committed Oct 12, 2013
1 parent 09f7778 commit d4d68fc
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 32 deletions.
28 changes: 1 addition & 27 deletions corelib/module.rb
Expand Up @@ -183,33 +183,7 @@ def attr_writer(*names)
# when self is not Module (or Class), implement 2nd form:
# - constants, classes and modules scoped to instance
def constants
%x{
var result = [];
var name_re = /^[A-Z][A-Za-z0-9_]+$/;
var scopes = [#{self}._scope];
var own_only;
if (#{self} === Opal.Class || #{self} === Opal.Module) {
own_only = false;
}
else {
own_only = true;
var parent = #{self}._super;
while (parent && (parent !== Opal.Object)) {
scopes.push(parent._scope);
parent = parent._super;
}
}
for (var i = 0, len = scopes.length; i < len; i++) {
var scope = scopes[i];
for (name in scope) {
if ((!own_only || scope.hasOwnProperty(name)) && name_re.test(name)) {
result.push(name);
}
}
}
return result;
}
`#{self}._scope.constants`
end

# check for constant within current scope
Expand Down
36 changes: 33 additions & 3 deletions corelib/runtime.js
Expand Up @@ -41,6 +41,8 @@
// To inherit scopes
Opal.constructor = TopScope;

Opal.constants = [];

// This is a useful reference to global object inside ruby files
Opal.global = this;

Expand Down Expand Up @@ -73,9 +75,11 @@
klass._scope = const_scope;
const_scope.base = klass;
const_scope.constructor = const_alloc;
const_scope.constants = [];

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

Expand Down Expand Up @@ -139,11 +143,18 @@
klass._name = (base === RubyObject ? id : base._name + '::' + id);

// every class gets its own constant scope, inherited from current scope
create_scope(base._scope, klass);
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) {
for (var i = 0, len = superklass._scope.constants.length; i < len; i++) {
klass._scope.constants.push(superklass._scope.constants[i]);
}
}

// call .inherited() hook with new class on the superclass
if (superklass.$inherited) {
superklass.$inherited(klass);
Expand Down Expand Up @@ -278,6 +289,7 @@
constructor.prototype._klass = klass;

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

return klass;
};
Expand Down Expand Up @@ -316,6 +328,24 @@
return klass;
};

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

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

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

/*
* Methods stubs are used to facilitate method_missing in opal. A stub is a
* placeholder function which just calls `method_missing` on the receiver.
Expand Down Expand Up @@ -634,8 +664,8 @@
RubyBasicObject._scope = RubyObject._scope = Opal;
Opal.Kernel = RubyObject;

create_scope(Opal, RubyModule);
create_scope(Opal, RubyClass);
RubyModule._scope= RubyObject._scope;
RubyClass._scope= RubyObject._scope;

RubyObject._proto.toString = function() {
return this.$to_s();
Expand Down
4 changes: 2 additions & 2 deletions lib/opal/parser.rb
Expand Up @@ -1592,14 +1592,14 @@ def process_const(sexp, level)
# s(:cdecl, :const, rhs)
def process_cdecl(sexp, level)
const, rhs = sexp
[f("$scope.#{const} = ", sexp), process(rhs)]
[f("$opal.cdecl($scope, '#{const}', "), process(rhs), f(")")]
end

# s(:casgn, s(:const, ::A), :B, val)
# A::B = 100
def process_casgn(sexp, level)
lhs, const, rhs = sexp
[process(lhs), f("._scope.#{const} = ", sexp), process(rhs)]
[f("$opal.casgn("), process(lhs), f(", '#{const}', "), process(rhs), f(")")]
end

# s(:return [val])
Expand Down
3 changes: 3 additions & 0 deletions spec/filters/bugs/module.rb
Expand Up @@ -8,4 +8,7 @@
fails "Module#method_defined? raises a TypeError when the given object is not a string/symbol/fixnum"
fails "Module#method_defined? does not search Object or Kernel when called on a module"
fails "Module#method_defined? returns true if a public or private method with the given name is defined in self, self's ancestors or one of self's included modules"

fails "Module#const_defined? should not search parent scopes of classes and modules if inherit is false"
fails "Module#const_get should not search parent scopes of classes and modules if inherit is false"
end

0 comments on commit d4d68fc

Please sign in to comment.