[gjs/wip/ptomato/classes: 1/8] class: Stop using custom __name__ property
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/wip/ptomato/classes: 1/8] class: Stop using custom __name__ property
- Date: Thu, 3 Aug 2017 21:46:20 +0000 (UTC)
commit 188254fb8f93d21924087cbd3f68bee6596514ed
Author: Philip Chimento <philip chimento gmail com>
Date: Mon Jul 10 23:19:40 2017 -0700
class: Stop using custom __name__ property
Since ES6 classes are functions, if you declare 'class Foo {}' then
'Foo.name === "Foo"'. We had a custom __name__ property on Lang.Class
instances, but instead mimic the normal JS class and put a name property
on the class.
That is, the equivalent to 'instance.__name__' is now
'instance.constructor.name'.
This could potentially break client code if any was using this, but the
double underscore made it clear enough that the property should have been
internal.
https://bugzilla.gnome.org/show_bug.cgi?id=785652
NEWS | 8 +++++
installed-tests/js/testClass.js | 4 ++
installed-tests/js/testGObjectClass.js | 4 ++
installed-tests/js/testGObjectInterface.js | 10 ++++--
installed-tests/js/testInterface.js | 4 ++
modules/lang.js | 43 +++++++++++++--------------
modules/overrides/GObject.js | 15 +++++++++-
7 files changed, 61 insertions(+), 27 deletions(-)
---
diff --git a/NEWS b/NEWS
index 4963c63..a0138e3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+NEXT
+----
+
+- Backwards-incompatible change: The private "__name__" property on Lang.Class
+ instances is removed. Code should not have been using this, but if it did
+ then it will need to be changed. It is replaced by the "name" property on
+ class constructors, which is standard for ES6 classes.
+
Version 1.48.6
--------------
diff --git a/installed-tests/js/testClass.js b/installed-tests/js/testClass.js
index dfac15c..13a3f3e 100644
--- a/installed-tests/js/testClass.js
+++ b/installed-tests/js/testClass.js
@@ -102,6 +102,10 @@ describe('Class framework', function () {
expect(newMagic instanceof MagicBase).toBeTruthy();
});
+ it('has a name', function () {
+ expect(Magic.name).toEqual('Magic');
+ });
+
it('reports a sensible value for toString()', function () {
let newMagic = new MagicBase();
expect(newMagic.toString()).toEqual('[object MagicBase]');
diff --git a/installed-tests/js/testGObjectClass.js b/installed-tests/js/testGObjectClass.js
index 0d81b96..3aaa938 100644
--- a/installed-tests/js/testGObjectClass.js
+++ b/installed-tests/js/testGObjectClass.js
@@ -209,6 +209,10 @@ describe('GObject class', function () {
expect(myInstance3.construct).toEqual('quz');
});
+ it('has a name', function () {
+ expect(MyObject.name).toEqual('MyObject');
+ });
+
// the following would (should) cause a CRITICAL:
// myInstance.readonly = 'val';
// myInstance.construct = 'val';
diff --git a/installed-tests/js/testGObjectInterface.js b/installed-tests/js/testGObjectInterface.js
index 792b611..11914f2 100644
--- a/installed-tests/js/testGObjectInterface.js
+++ b/installed-tests/js/testGObjectInterface.js
@@ -157,6 +157,10 @@ describe('GObject interface', function () {
expect(() => new AGObjectInterface()).toThrow();
});
+ it('has a name', function () {
+ expect(AGObjectInterface.name).toEqual('AGObjectInterface');
+ });
+
it('reports its type name', function () {
expect(AGObjectInterface.$gtype.name).toEqual('ArbitraryGTypeName');
});
@@ -169,12 +173,10 @@ describe('GObject interface', function () {
});
it('is implemented by a GObject class with the correct class object', function () {
- expect(GObjectImplementingGObjectInterface.toString())
- .toEqual('[object GObjectClass for GObjectImplementingGObjectInterface]');
let obj = new GObjectImplementingGObjectInterface();
expect(obj.constructor).toEqual(GObjectImplementingGObjectInterface);
- expect(obj.constructor.toString())
- .toEqual('[object GObjectClass for GObjectImplementingGObjectInterface]');
+ expect(obj.constructor.name)
+ .toEqual('GObjectImplementingGObjectInterface');
});
it('can be implemented by a class also implementing a Lang.Interface', function () {
diff --git a/installed-tests/js/testInterface.js b/installed-tests/js/testInterface.js
index 08f3b94..83188e3 100644
--- a/installed-tests/js/testInterface.js
+++ b/installed-tests/js/testInterface.js
@@ -107,6 +107,10 @@ describe('An interface', function () {
expect(InterfaceRequiringOtherInterface instanceof Lang.Interface).toBeTruthy();
});
+ it('has a name', function () {
+ expect(AnInterface.name).toEqual('AnInterface');
+ });
+
it('cannot be instantiated', function () {
expect(() => new AnInterface()).toThrow();
});
diff --git a/modules/lang.js b/modules/lang.js
index 0957158..e40fefd 100644
--- a/modules/lang.js
+++ b/modules/lang.js
@@ -110,9 +110,8 @@ _Base.prototype._construct = function() {
this._init.apply(this, arguments);
return this;
};
-_Base.prototype.__name__ = '_Base';
_Base.prototype.toString = function() {
- return '[object ' + this.__name__ + ']';
+ return `[object ${this.constructor.name}]`;
};
function _parent() {
@@ -167,7 +166,6 @@ function Class(params) {
Class.__super__ = _Base;
Class.prototype = Object.create(_Base.prototype);
Class.prototype.constructor = Class;
-Class.prototype.__name__ = 'Class';
Class.prototype.wrapFunction = function(name, meth) {
if (meth._origin) meth = meth._origin;
@@ -188,7 +186,7 @@ Class.prototype.wrapFunction = function(name, meth) {
}
Class.prototype.toString = function() {
- return '[object ' + this.__name__ + ' for ' + this.prototype.__name__ + ']';
+ return `[object ${this.constructor.name} for ${this.prototype.constructor.name}]`;
};
Class.prototype._construct = function(params) {
@@ -241,6 +239,12 @@ Class.prototype._construct = function(params) {
enumerable: false,
value: interfaces }
});
+ Object.defineProperty(newClass, 'name', {
+ writable: false,
+ configurable: true,
+ enumerable: false,
+ value: name,
+ });
interfaces.forEach((iface) => {
iface._check(newClass.prototype);
@@ -305,10 +309,6 @@ Class.prototype._init = function(params) {
Object.defineProperties(this.prototype, propertyObj);
Object.defineProperties(this.prototype, {
- '__name__': { writable: false,
- configurable: false,
- enumerable: false,
- value: name },
'parent': { writable: false,
configurable: false,
enumerable: false,
@@ -384,7 +384,6 @@ Interface.UNIMPLEMENTED = function UNIMPLEMENTED () {
Interface.__super__ = _Base;
Interface.prototype = Object.create(_Base.prototype);
Interface.prototype.constructor = Interface;
-Interface.prototype.__name__ = 'Interface';
Interface.prototype._construct = function (params) {
if (!params.Name)
@@ -395,7 +394,6 @@ Interface.prototype._construct = function (params) {
newInterface.__super__ = Interface;
newInterface.prototype = Object.create(Interface.prototype);
newInterface.prototype.constructor = newInterface;
- newInterface.prototype.__name__ = params.Name;
newInterface._init.apply(newInterface, arguments);
@@ -404,6 +402,12 @@ Interface.prototype._construct = function (params) {
configurable: false,
enumerable: false,
value: this.constructor });
+ Object.defineProperty(newInterface, 'name', {
+ writable: false,
+ configurable: true,
+ enumerable: false,
+ value: params.Name,
+ });
return newInterface;
};
@@ -424,14 +428,13 @@ Interface.prototype._check = function (proto) {
interfaces.indexOf(required) > interfaces.indexOf(this)) &&
!(proto instanceof required));
}).map((required) =>
- // __name__ is only present on GJS-created classes and will be the most
- // accurate name. required.name will be present on introspected GObjects
- // but is not preferred because it will be the C name. The last option
- // is just so that we print something if there is garbage in Requires.
- required.prototype.__name__ || required.name || required);
+ // required.name will be present on JS classes, but on introspected
+ // GObjects it will be the C name. The alternative is just so that
+ // we print something if there is garbage in Requires.
+ required.name || required);
if (unfulfilledReqs.length > 0) {
throw new Error('The following interfaces must be implemented before ' +
- this.prototype.__name__ + ': ' + unfulfilledReqs.join(', '));
+ `${this.constructor.name}: ${unfulfilledReqs.join(', ')}`);
}
// Check that this interface's required methods are implemented
@@ -439,12 +442,12 @@ Interface.prototype._check = function (proto) {
.filter((p) => this.prototype[p] === Interface.UNIMPLEMENTED)
.filter((p) => !(p in proto) || proto[p] === Interface.UNIMPLEMENTED);
if (unimplementedFns.length > 0)
- throw new Error('The following members of ' + this.prototype.__name__ +
+ throw new Error(`The following members of ${this.constructor.name}` +
' are not implemented yet: ' + unimplementedFns.join(', '));
};
Interface.prototype.toString = function () {
- return '[interface ' + this.__name__ + ' for ' + this.prototype.__name__ + ']';
+ return `[interface ${this.constructor.name} for ${this.prototype.constructor.name}]`;
};
Interface.prototype._init = function (params) {
@@ -475,10 +478,6 @@ Interface.prototype._init = function (params) {
Object.defineProperties(this.prototype, propertyObj);
Object.defineProperties(this.prototype, {
- '__name__': { writable: false,
- configurable: false,
- enumerable: false,
- value: name },
'__requires__': { writable: false,
configurable: false,
enumerable: false,
diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js
index ee30779..556b7b2 100644
--- a/modules/overrides/GObject.js
+++ b/modules/overrides/GObject.js
@@ -161,6 +161,13 @@ const GObjectMeta = new Lang.Class({
enumerable: false,
value: interfaces }
});
+ // Overwrite the C++-set class name, as if it were an ES6 class
+ Object.defineProperty(newClass, 'name', {
+ writable: false,
+ configurable: true,
+ enumerable: false,
+ value: name,
+ });
interfaces.forEach((iface) => {
if (iface instanceof Lang.Interface)
@@ -189,7 +196,6 @@ GObjectMeta.MetaInterface = GObjectInterface;
GObjectInterface.__super__ = Lang.Interface;
GObjectInterface.prototype = Object.create(Lang.Interface.prototype);
GObjectInterface.prototype.constructor = GObjectInterface;
-GObjectInterface.prototype.__name__ = 'GObjectInterface';
GObjectInterface.prototype._construct = function (params) {
if (!params.Name) {
@@ -222,6 +228,13 @@ GObjectInterface.prototype._construct = function (params) {
enumerable: false,
value: this.constructor
});
+ // Overwrite the C++-set class name, as if it were an ES6 class
+ Object.defineProperty(newInterface, 'name', {
+ writable: false,
+ configurable: true,
+ enumerable: false,
+ value: params.Name,
+ });
return newInterface;
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]