[gjs/wip/ptomato/classes: 7/11] lang: Move all legacy Lang.Class code
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/wip/ptomato/classes: 7/11] lang: Move all legacy Lang.Class code
- Date: Sat, 29 Jul 2017 08:13:46 +0000 (UTC)
commit 191cd157937ddd6ee0d475fb66b02edcaab8447f
Author: Philip Chimento <philip chimento gmail com>
Date: Wed Jul 12 22:50:05 2017 -0700
lang: Move all legacy Lang.Class code
This moves Lang.Class into a separate Legacy module, which is not meant
to be imported directly; instead, Lang imports it and exports the same
members that it always did.
Also moves all tests for the legacy Lang.Class into a separate file. It
is named testLegacyClass in order to indicate that it tests legacy code.
Makefile-test.am | 4 +-
installed-tests/js/testClass.js | 210 -----------
installed-tests/js/testInterface.js | 341 -----------------
installed-tests/js/testLang.js | 2 +-
installed-tests/js/testLegacyClass.js | 662 +++++++++++++++++++++++++++++++++
installed-tests/js/testMetaClass.js | 117 ------
modules/_legacy.js | 390 +++++++++++++++++++
modules/lang.js | 396 +-------------------
modules/modules.gresource.xml | 1 +
modules/overrides/GObject.js | 7 +-
10 files changed, 1065 insertions(+), 1065 deletions(-)
---
diff --git a/Makefile-test.am b/Makefile-test.am
index 31ac2d6..71cd3da 100644
--- a/Makefile-test.am
+++ b/Makefile-test.am
@@ -217,7 +217,6 @@ CLEANFILES += $(TEST_INTROSPECTION_GIRS) $(TEST_INTROSPECTION_TYPELIBS)
common_jstests_files = \
installed-tests/js/testself.js \
installed-tests/js/testByteArray.js \
- installed-tests/js/testClass.js \
installed-tests/js/testCoverage.js \
installed-tests/js/testExceptions.js \
installed-tests/js/testEverythingBasic.js \
@@ -232,11 +231,10 @@ common_jstests_files = \
installed-tests/js/testGTypeClass.js \
installed-tests/js/testGio.js \
installed-tests/js/testImporter.js \
- installed-tests/js/testInterface.js \
installed-tests/js/testLang.js \
+ installed-tests/js/testLegacyClass.js \
installed-tests/js/testLocale.js \
installed-tests/js/testMainloop.js \
- installed-tests/js/testMetaClass.js \
installed-tests/js/testNamespace.js \
installed-tests/js/testPackage.js \
installed-tests/js/testParamSpec.js \
diff --git a/installed-tests/js/testLang.js b/installed-tests/js/testLang.js
index 51874bd..1e0d307 100644
--- a/installed-tests/js/testLang.js
+++ b/installed-tests/js/testLang.js
@@ -1,5 +1,5 @@
// tests for imports.lang module
-// except for Lang.Class and Lang.Interface, which are tested in separate files
+// except for Lang.Class and Lang.Interface, which are tested in testLegacyClass
const Lang = imports.lang;
diff --git a/installed-tests/js/testLegacyClass.js b/installed-tests/js/testLegacyClass.js
new file mode 100644
index 0000000..44fb3a4
--- /dev/null
+++ b/installed-tests/js/testLegacyClass.js
@@ -0,0 +1,662 @@
+// -*- mode: js; indent-tabs-mode: nil -*-
+
+const Lang = imports.lang;
+
+const NormalClass = new Lang.Class({
+ Name: 'NormalClass',
+
+ _init: function() {
+ this.one = 1;
+ }
+});
+
+let Subclassed = [];
+const MetaClass = new Lang.Class({
+ Name: 'MetaClass',
+ Extends: Lang.Class,
+
+ _init: function(params) {
+ Subclassed.push(params.Name);
+ this.parent(params);
+
+ if (params.Extended) {
+ this.prototype.dynamic_method = this.wrapFunction('dynamic_method', function() {
+ return 73;
+ });
+
+ this.DYNAMIC_CONSTANT = 2;
+ }
+ }
+});
+
+const CustomMetaOne = new MetaClass({
+ Name: 'CustomMetaOne',
+ Extends: NormalClass,
+ Extended: false,
+
+ _init: function() {
+ this.parent();
+
+ this.two = 2;
+ }
+});
+
+const CustomMetaTwo = new MetaClass({
+ Name: 'CustomMetaTwo',
+ Extends: NormalClass,
+ Extended: true,
+
+ _init: function() {
+ this.parent();
+
+ this.two = 2;
+ }
+});
+
+// This should inherit CustomMeta, even though
+// we use Lang.Class
+const CustomMetaSubclass = new Lang.Class({
+ Name: 'CustomMetaSubclass',
+ Extends: CustomMetaOne,
+ Extended: true,
+
+ _init: function() {
+ this.parent();
+
+ this.three = 3;
+ }
+});
+
+describe('A metaclass', function () {
+ it('has its constructor called each time a class is created with it', function () {
+ expect(Subclassed).toEqual(['CustomMetaOne', 'CustomMetaTwo',
+ 'CustomMetaSubclass']);
+ });
+
+ it('is an instance of Lang.Class', function () {
+ expect(NormalClass instanceof Lang.Class).toBeTruthy();
+ expect(MetaClass instanceof Lang.Class).toBeTruthy();
+ });
+
+ it('produces instances that are instances of itself and Lang.Class', function () {
+ expect(CustomMetaOne instanceof Lang.Class).toBeTruthy();
+ expect(CustomMetaOne instanceof MetaClass).toBeTruthy();
+ });
+
+ it('can dynamically define properties in its constructor', function () {
+ expect(CustomMetaTwo.DYNAMIC_CONSTANT).toEqual(2);
+ expect(CustomMetaOne.DYNAMIC_CONSTANT).not.toBeDefined();
+ });
+
+ describe('instance', function () {
+ let instanceOne, instanceTwo;
+ beforeEach(function () {
+ instanceOne = new CustomMetaOne();
+ instanceTwo = new CustomMetaTwo();
+ });
+
+ it('gets all the properties from its class and metaclass', function () {
+ expect(instanceOne).toEqual(jasmine.objectContaining({ one: 1, two: 2 }));
+ expect(instanceTwo).toEqual(jasmine.objectContaining({ one: 1, two: 2 }));
+ });
+
+ it('gets dynamically defined properties from metaclass', function () {
+ expect(() => instanceOne.dynamic_method()).toThrow();
+ expect(instanceTwo.dynamic_method()).toEqual(73);
+ });
+ });
+
+ it('can be instantiated with Lang.Class but still get the appropriate metaclass', function () {
+ expect(CustomMetaSubclass instanceof MetaClass).toBeTruthy();
+ expect(CustomMetaSubclass.DYNAMIC_CONSTANT).toEqual(2);
+
+ let instance = new CustomMetaSubclass();
+ expect(instance).toEqual(jasmine.objectContaining({ one: 1, two: 2, three: 3 }));
+ expect(instance.dynamic_method()).toEqual(73);
+ });
+});
+
+const MagicBase = new Lang.Class({
+ Name: 'MagicBase',
+
+ _init: function(a, buffer) {
+ if (buffer) buffer.push(a);
+ this.a = a;
+ },
+
+ foo: function(a, buffer) {
+ buffer.push(a);
+ return a * 3;
+ },
+
+ bar: function(a) {
+ return a * 5;
+ }
+});
+
+const Magic = new Lang.Class({
+ Name: 'Magic',
+
+ Extends: MagicBase,
+
+ _init: function(a, b, buffer) {
+ this.parent(a, buffer);
+ if (buffer) buffer.push(b);
+ this.b = b;
+ },
+
+ foo: function(a, b, buffer) {
+ let val = this.parent(a, buffer);
+ buffer.push(b);
+ return val * 2;
+ },
+
+ bar: function(a, buffer) {
+ this.foo(a, 2*a, buffer);
+ return this.parent(a);
+ }
+});
+
+const Accessor = new Lang.Class({
+ Name: 'AccessorMagic',
+
+ _init: function(val) {
+ this._val = val;
+ },
+
+ get value() {
+ return this._val;
+ },
+
+ set value(val) {
+ if (val != 42)
+ throw TypeError('Value is not a magic number');
+ this._val = val;
+ }
+});
+
+const AbstractBase = new Lang.Class({
+ Name: 'AbstractBase',
+ Abstract: true,
+
+ _init: function() {
+ this.foo = 42;
+ }
+});
+
+describe('Class framework', function () {
+ it('calls _init constructors', function () {
+ let newMagic = new MagicBase('A');
+ expect(newMagic.a).toEqual('A');
+ });
+
+ it('calls parent constructors', function () {
+ let buffer = [];
+
+ let newMagic = new Magic('a', 'b', buffer);
+ expect(buffer).toEqual(['a', 'b']);
+
+ buffer = [];
+ let val = newMagic.foo(10, 20, buffer);
+ expect(buffer).toEqual([10, 20]);
+ expect(val).toEqual(10 * 6);
+ });
+
+ it('sets the right constructor properties', function () {
+ expect(Magic.prototype.constructor).toBe(Magic);
+
+ let newMagic = new Magic();
+ expect(newMagic.constructor).toBe(Magic);
+ });
+
+ it('sets up instanceof correctly', function () {
+ let newMagic = new Magic();
+
+ expect(newMagic instanceof Magic).toBeTruthy();
+ 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]');
+ });
+
+ it('allows overriding toString()', function () {
+ const ToStringOverride = new Lang.Class({
+ Name: 'ToStringOverride',
+
+ toString: function() {
+ let oldToString = this.parent();
+ return oldToString + '; hello';
+ }
+ });
+
+ let override = new ToStringOverride();
+ expect(override.toString()).toEqual('[object ToStringOverride]; hello');
+ });
+
+ it('is not configurable', function () {
+ let newMagic = new MagicBase();
+
+ delete newMagic.foo;
+ expect(newMagic.foo).toBeDefined();
+ });
+
+ it('allows accessors for properties', function () {
+ let newAccessor = new Accessor(11);
+
+ expect(newAccessor.value).toEqual(11);
+ expect(() => newAccessor.value = 12).toThrow();
+
+ newAccessor.value = 42;
+ expect(newAccessor.value).toEqual(42);
+ });
+
+ it('raises an exception when creating an abstract class', function () {
+ expect(() => new AbstractBase()).toThrow();
+ });
+
+ it('inherits properties from abstract base classes', function () {
+ const AbstractImpl = new Lang.Class({
+ Name: 'AbstractImpl',
+ Extends: AbstractBase,
+
+ _init: function() {
+ this.parent();
+ this.bar = 42;
+ }
+ });
+
+ let newAbstract = new AbstractImpl();
+ expect(newAbstract.foo).toEqual(42);
+ expect(newAbstract.bar).toEqual(42);
+ });
+
+ it('inherits constructors from abstract base classes', function () {
+ const AbstractImpl = new Lang.Class({
+ Name: 'AbstractImpl',
+ Extends: AbstractBase,
+ });
+
+ let newAbstract = new AbstractImpl();
+ expect(newAbstract.foo).toEqual(42);
+ });
+
+ it('lets methods call other methods without clobbering __caller__', function () {
+ let newMagic = new Magic();
+ let buffer = [];
+
+ let res = newMagic.bar(10, buffer);
+ expect(buffer).toEqual([10, 20]);
+ expect(res).toEqual(50);
+ });
+
+ it('allows custom return values from constructors', function () {
+ const CustomConstruct = new Lang.Class({
+ Name: 'CustomConstruct',
+
+ _construct: function(one, two) {
+ return [one, two];
+ }
+ });
+
+ let instance = new CustomConstruct(1, 2);
+
+ expect(instance instanceof Array).toBeTruthy();
+ expect(instance instanceof CustomConstruct).toBeFalsy();
+ expect(instance).toEqual([1, 2]);
+ });
+
+ it('allows symbol-named methods', function () {
+ const SymbolClass = new Lang.Class({
+ Name: 'SymbolClass',
+ *[Symbol.iterator]() {
+ yield* [1, 2, 3];
+ },
+ });
+ let instance = new SymbolClass();
+ expect([...instance]).toEqual([1, 2, 3]);
+ });
+});
+
+const AnInterface = new Lang.Interface({
+ Name: 'AnInterface',
+
+ required: Lang.Interface.UNIMPLEMENTED,
+
+ optional: function () {
+ return 'AnInterface.optional()';
+ },
+
+ optionalGeneric: function () {
+ return 'AnInterface.optionalGeneric()';
+ },
+
+ argumentGeneric: function (arg) {
+ return 'AnInterface.argumentGeneric(' + arg + ')';
+ },
+
+ usesThis: function () {
+ return this._interfacePrivateMethod();
+ },
+
+ _interfacePrivateMethod: function () {
+ return 'interface private method';
+ },
+
+ get some_prop() {
+ return 'AnInterface.some_prop getter';
+ },
+
+ set some_prop(value) {
+ this.some_prop_setter_called = true;
+ }
+});
+
+const InterfaceRequiringOtherInterface = new Lang.Interface({
+ Name: 'InterfaceRequiringOtherInterface',
+ Requires: [ AnInterface ],
+
+ optional: function () {
+ return 'InterfaceRequiringOtherInterface.optional()\n' +
+ AnInterface.prototype.optional.apply(this, arguments);
+ },
+
+ optionalGeneric: function () {
+ return 'InterfaceRequiringOtherInterface.optionalGeneric()\n' +
+ AnInterface.optionalGeneric(this);
+ }
+});
+
+const ObjectImplementingAnInterface = new Lang.Class({
+ Name: 'ObjectImplementingAnInterface',
+ Implements: [ AnInterface ],
+
+ _init: function () {
+ this.parent();
+ },
+
+ required: function () {},
+
+ optional: function () {
+ return AnInterface.prototype.optional.apply(this, arguments);
+ },
+
+ optionalGeneric: function () {
+ return AnInterface.optionalGeneric(this);
+ },
+
+ argumentGeneric: function (arg) {
+ return AnInterface.argumentGeneric(this, arg + ' (hello from class)');
+ }
+});
+
+const InterfaceRequiringClassAndInterface = new Lang.Interface({
+ Name: 'InterfaceRequiringClassAndInterface',
+ Requires: [ ObjectImplementingAnInterface, InterfaceRequiringOtherInterface ],
+});
+
+const MinimalImplementationOfAnInterface = new Lang.Class({
+ Name: 'MinimalImplementationOfAnInterface',
+ Implements: [ AnInterface ],
+
+ required: function () {}
+});
+
+const ImplementationOfTwoInterfaces = new Lang.Class({
+ Name: 'ImplementationOfTwoInterfaces',
+ Implements: [ AnInterface, InterfaceRequiringOtherInterface ],
+
+ required: function () {},
+
+ optional: function () {
+ return InterfaceRequiringOtherInterface.prototype.optional.apply(this, arguments);
+ },
+
+ optionalGeneric: function () {
+ return InterfaceRequiringOtherInterface.optionalGeneric(this);
+ }
+});
+
+describe('An interface', function () {
+ it('is an instance of Lang.Interface', function () {
+ expect(AnInterface instanceof Lang.Interface).toBeTruthy();
+ 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();
+ });
+
+ it('can be implemented by a class', function () {
+ let obj;
+ expect(() => { obj = new ObjectImplementingAnInterface(); }).not.toThrow();
+ expect(obj.constructor.implements(AnInterface)).toBeTruthy();
+ });
+
+ it("can be implemented by a class's superclass", function () {
+ const ChildWhoseParentImplementsAnInterface = new Lang.Class({
+ Name: 'ChildWhoseParentImplementsAnInterface',
+ Extends: ObjectImplementingAnInterface
+ });
+ let obj = new ChildWhoseParentImplementsAnInterface();
+ expect(obj.constructor.implements(AnInterface)).toBeTruthy();
+ });
+
+ it("doesn't disturb a class's constructor", function () {
+ let obj = new ObjectImplementingAnInterface();
+ expect(obj.constructor).toEqual(ObjectImplementingAnInterface);
+ });
+
+ it('can have its required method implemented', function () {
+ let implementer = new ObjectImplementingAnInterface();
+ expect(() => implementer.required()).not.toThrow();
+ });
+
+ it('must have a name', function () {
+ expect(() => new Lang.Interface({
+ required: Lang.Interface.UNIMPLEMENTED,
+ })).toThrow();
+ });
+
+ it('must have its required methods implemented', function () {
+ expect(() => new Lang.Class({
+ Name: 'MyBadObject',
+ Implements: [AnInterface],
+ })).toThrow();
+ });
+
+ it('does not have to have its optional methods implemented', function () {
+ let obj;
+ expect(() => obj = new MinimalImplementationOfAnInterface()).not.toThrow();
+ expect(obj.constructor.implements(AnInterface)).toBeTruthy();
+ });
+
+ it('can have its optional method deferred to by the implementation', function () {
+ let obj = new MinimalImplementationOfAnInterface();
+ expect(obj.optional()).toEqual('AnInterface.optional()');
+ });
+
+ it('can be chained up to by a class', function () {
+ let obj = new ObjectImplementingAnInterface();
+ expect(obj.optional()).toEqual('AnInterface.optional()');
+ });
+
+ it('can include arguments when being chained up to by a class', function () {
+ let obj = new ObjectImplementingAnInterface();
+ expect(obj.argumentGeneric('arg'))
+ .toEqual('AnInterface.argumentGeneric(arg (hello from class))');
+ });
+
+ it('can have its property getter deferred to', function () {
+ let obj = new ObjectImplementingAnInterface();
+ expect(obj.some_prop).toEqual('AnInterface.some_prop getter');
+ });
+
+ it('can have its property setter deferred to', function () {
+ let obj = new ObjectImplementingAnInterface();
+ obj.some_prop = 'foobar';
+ expect(obj.some_prop_setter_called).toBeTruthy();
+ });
+
+ it('can have its property getter overridden', function () {
+ const ObjectWithGetter = new Lang.Class({
+ Name: 'ObjectWithGetter',
+ Implements: [ AnInterface ],
+ required: function () {},
+ get some_prop() {
+ return 'ObjectWithGetter.some_prop getter';
+ }
+ });
+ let obj = new ObjectWithGetter();
+ expect(obj.some_prop).toEqual('ObjectWithGetter.some_prop getter');
+ });
+
+ it('can have its property setter overridden', function () {
+ const ObjectWithSetter = new Lang.Class({
+ Name: 'ObjectWithSetter',
+ Implements: [ AnInterface ],
+ required: function () {},
+ set some_prop(value) { /* setter without getter */// jshint ignore:line
+ this.overridden_some_prop_setter_called = true;
+ }
+ });
+ let obj = new ObjectWithSetter();
+ obj.some_prop = 'foobar';
+ expect(obj.overridden_some_prop_setter_called).toBeTruthy();
+ expect(obj.some_prop_setter_called).not.toBeDefined();
+ });
+
+ it('can require another interface', function () {
+ let obj;
+ expect(() => { obj = new ImplementationOfTwoInterfaces(); }).not.toThrow();
+ expect(obj.constructor.implements(AnInterface)).toBeTruthy();
+ expect(obj.constructor.implements(InterfaceRequiringOtherInterface)).toBeTruthy();
+ });
+
+ it('can have empty requires', function () {
+ expect(() => new Lang.Interface({
+ Name: 'InterfaceWithEmptyRequires',
+ Requires: []
+ })).not.toThrow();
+ });
+
+ it('can chain up to another interface', function () {
+ let obj = new ImplementationOfTwoInterfaces();
+ expect(obj.optional())
+ .toEqual('InterfaceRequiringOtherInterface.optional()\nAnInterface.optional()');
+ });
+
+ it('can be chained up to with a generic', function () {
+ let obj = new ObjectImplementingAnInterface();
+ expect(obj.optionalGeneric()).toEqual('AnInterface.optionalGeneric()');
+ });
+
+ it('can chain up to another interface with a generic', function () {
+ let obj = new ImplementationOfTwoInterfaces();
+ expect(obj.optionalGeneric())
+ .toEqual('InterfaceRequiringOtherInterface.optionalGeneric()\nAnInterface.optionalGeneric()');
+ });
+
+ it('has its optional function defer to that of the last interface', function () {
+ const MinimalImplementationOfTwoInterfaces = new Lang.Class({
+ Name: 'MinimalImplementationOfTwoInterfaces',
+ Implements: [ AnInterface, InterfaceRequiringOtherInterface ],
+
+ required: function () {}
+ });
+ let obj = new MinimalImplementationOfTwoInterfaces();
+ expect(obj.optionalGeneric())
+ .toEqual('InterfaceRequiringOtherInterface.optionalGeneric()\nAnInterface.optionalGeneric()');
+ });
+
+ it('must have all its required interfaces implemented', function () {
+ expect(() => new Lang.Class({
+ Name: 'ObjectWithNotEnoughInterfaces',
+ Implements: [ InterfaceRequiringOtherInterface ],
+ required: function () {}
+ })).toThrow();
+ });
+
+ it('must have all its required interfaces implemented in the correct order', function () {
+ expect(() => new Lang.Class({
+ Name: 'ObjectWithInterfacesInWrongOrder',
+ Implements: [ InterfaceRequiringOtherInterface, AnInterface ],
+ required: function () {}
+ })).toThrow();
+ });
+
+ it('can have its implementation on a parent class', function () {
+ let obj;
+ expect(() => {
+ const ObjectInheritingFromInterfaceImplementation = new Lang.Class({
+ Name: 'ObjectInheritingFromInterfaceImplementation',
+ Extends: ObjectImplementingAnInterface,
+ Implements: [ InterfaceRequiringOtherInterface ],
+ });
+ obj = new ObjectInheritingFromInterfaceImplementation();
+ }).not.toThrow();
+ expect(obj.constructor.implements(AnInterface)).toBeTruthy();
+ expect(obj.constructor.implements(InterfaceRequiringOtherInterface)).toBeTruthy();
+ });
+
+ it('can require its implementor to be a subclass of some class', function () {
+ let obj;
+ expect(() => {
+ const ObjectImplementingInterfaceRequiringParentObject = new Lang.Class({
+ Name: 'ObjectImplementingInterfaceRequiringParentObject',
+ Extends: ObjectImplementingAnInterface,
+ Implements: [ InterfaceRequiringOtherInterface, InterfaceRequiringClassAndInterface ]
+ });
+ obj = new ObjectImplementingInterfaceRequiringParentObject();
+ }).not.toThrow();
+ expect(obj.constructor.implements(AnInterface)).toBeTruthy();
+ expect(obj.constructor.implements(InterfaceRequiringOtherInterface)).toBeTruthy();
+ expect(obj.constructor.implements(InterfaceRequiringClassAndInterface)).toBeTruthy();
+ });
+
+ it('must be implemented by an object which subclasses the required class', function () {
+ expect(() => new Lang.Class({
+ Name: 'ObjectWithoutRequiredParent',
+ Implements: [ AnInterface, InterfaceRequiringOtherInterface, InterfaceRequiringClassAndInterface
],
+ required: function () {},
+ })).toThrow();
+ });
+
+ it('can have methods that call others of its methods', function () {
+ let obj = new ObjectImplementingAnInterface();
+ expect(obj.usesThis()).toEqual('interface private method');
+ });
+
+ it('is implemented by a subclass of a class that implements it', function () {
+ const SubObject = new Lang.Class({
+ Name: 'SubObject',
+ Extends: ObjectImplementingAnInterface
+ });
+ let obj = new SubObject();
+ expect(obj.constructor.implements(AnInterface)).toBeTruthy();
+ });
+
+ it('can be reimplemented by a subclass of a class that implements it', function () {
+ const SubImplementer = new Lang.Class({
+ Name: 'SubImplementer',
+ Extends: ObjectImplementingAnInterface,
+ Implements: [ AnInterface ]
+ });
+ let obj = new SubImplementer();
+ expect(obj.constructor.implements(AnInterface)).toBeTruthy();
+ expect(() => obj.required()).not.toThrow();
+ });
+
+ it('tells what it is with toString()', function () {
+ expect(AnInterface.toString()).toEqual('[interface Interface for AnInterface]');
+ });
+});
diff --git a/modules/_legacy.js b/modules/_legacy.js
new file mode 100644
index 0000000..2091488
--- /dev/null
+++ b/modules/_legacy.js
@@ -0,0 +1,390 @@
+/* -*- mode: js; indent-tabs-mode: nil; -*- */
+/* exported Class, Interface */
+// Copyright 2008 litl, LLC
+// Copyright 2011 Jasper St. Pierre
+
+// Class magic
+// Adapted from MooTools, MIT license
+// https://github.com/mootools/mootools-core
+
+function _Base() {
+ throw new TypeError('Cannot instantiate abstract class _Base');
+}
+
+_Base.__super__ = null;
+_Base.prototype._init = function() { };
+_Base.prototype._construct = function() {
+ this._init.apply(this, arguments);
+ return this;
+};
+_Base.prototype.toString = function() {
+ return `[object ${this.constructor.name}]`;
+};
+
+function _parent() {
+ if (!this.__caller__)
+ throw new TypeError("The method 'parent' cannot be called");
+
+ let caller = this.__caller__;
+ let name = caller._name;
+ let parent = caller._owner.__super__;
+
+ let previous = parent ? parent.prototype[name] : undefined;
+
+ if (!previous)
+ throw new TypeError("The method '" + name + "' is not on the superclass");
+
+ return previous.apply(this, arguments);
+}
+
+function _interfacePresent(required, proto) {
+ if (!proto.__interfaces__)
+ return false;
+ if (proto.__interfaces__.indexOf(required) !== -1)
+ return true; // implemented here
+ // Might be implemented on a parent class
+ return _interfacePresent(required, proto.constructor.__super__.prototype);
+}
+
+function getMetaClass(params) {
+ if (params.MetaClass)
+ return params.MetaClass;
+
+ if (params.Extends && params.Extends.prototype.__metaclass__)
+ return params.Extends.prototype.__metaclass__;
+
+ return null;
+}
+
+function Class(params) {
+ let metaClass = getMetaClass(params);
+
+ if (metaClass && metaClass != this.constructor) {
+ return new metaClass(...arguments);
+ } else {
+ return this._construct.apply(this, arguments);
+ }
+}
+
+Class.__super__ = _Base;
+Class.prototype = Object.create(_Base.prototype);
+Class.prototype.constructor = Class;
+
+Class.prototype.wrapFunction = function(name, meth) {
+ if (meth._origin) meth = meth._origin;
+
+ function wrapper() {
+ let prevCaller = this.__caller__;
+ this.__caller__ = wrapper;
+ let result = meth.apply(this, arguments);
+ this.__caller__ = prevCaller;
+ return result;
+ }
+
+ wrapper._origin = meth;
+ wrapper._name = name;
+ wrapper._owner = this;
+
+ return wrapper;
+};
+
+Class.prototype.toString = function() {
+ return `[object ${this.constructor.name} for ${this.prototype.constructor.name}]`;
+};
+
+Class.prototype._construct = function(params) {
+ if (!params.Name) {
+ throw new TypeError("Classes require an explicit 'Name' parameter.");
+ }
+ let name = params.Name;
+
+ let parent = params.Extends;
+ if (!parent)
+ parent = _Base;
+
+ let newClass;
+ if (params.Abstract) {
+ newClass = function() {
+ throw new TypeError('Cannot instantiate abstract class ' + name);
+ };
+ } else {
+ newClass = function() {
+ this.__caller__ = null;
+
+ return this._construct.apply(this, arguments);
+ };
+ }
+
+ // Since it's not possible to create a constructor with
+ // a custom [[Prototype]], we have to do this to make
+ // "newClass instanceof Class" work, and so we can inherit
+ // methods/properties of Class.prototype, like wrapFunction.
+ Object.setPrototypeOf(newClass, this.constructor.prototype);
+
+ newClass.__super__ = parent;
+ newClass.prototype = Object.create(parent.prototype);
+ newClass.prototype.constructor = newClass;
+
+ newClass._init.apply(newClass, arguments);
+
+ let interfaces = params.Implements || [];
+ // If the parent already implements an interface, then we do too
+ if (parent instanceof Class)
+ interfaces = interfaces.filter((iface) => !parent.implements(iface));
+
+ Object.defineProperties(newClass.prototype, {
+ '__metaclass__': {
+ writable: false,
+ configurable: false,
+ enumerable: false,
+ value: this.constructor,
+ },
+ '__interfaces__': {
+ writable: false,
+ configurable: false,
+ enumerable: false,
+ value: interfaces,
+ },
+ });
+ Object.defineProperty(newClass, 'name', {
+ writable: false,
+ configurable: true,
+ enumerable: false,
+ value: name,
+ });
+
+ interfaces.forEach((iface) => {
+ iface._check(newClass.prototype);
+ });
+
+ return newClass;
+};
+
+/**
+ * Check whether this class conforms to the interface "iface".
+ * @param {object} iface a Lang.Interface
+ * @returns: whether this class implements iface
+ * @type: boolean
+ */
+Class.prototype.implements = function (iface) {
+ if (_interfacePresent(iface, this.prototype))
+ return true;
+ if (this.__super__ instanceof Class)
+ return this.__super__.implements(iface);
+ return false;
+};
+
+// key can be either a string or a symbol
+Class.prototype._copyPropertyDescriptor = function(params, propertyObj, key) {
+ let descriptor = Object.getOwnPropertyDescriptor(params, key);
+
+ if (typeof descriptor.value === 'function')
+ descriptor.value = this.wrapFunction(key, descriptor.value);
+
+ // we inherit writable and enumerable from the property
+ // descriptor of params (they're both true if created from an
+ // object literal)
+ descriptor.configurable = false;
+
+ propertyObj[key] = descriptor;
+};
+
+Class.prototype._init = function(params) {
+ let propertyObj = { };
+
+ let interfaces = params.Implements || [];
+ interfaces.forEach((iface) => {
+ Object.getOwnPropertyNames(iface.prototype)
+ .filter((name) => !name.startsWith('__') && name !== 'constructor')
+ .filter((name) => !(name in this.prototype))
+ .forEach((name) => {
+ let descriptor = Object.getOwnPropertyDescriptor(iface.prototype,
+ name);
+ // writable and enumerable are inherited, see note above
+ descriptor.configurable = false;
+ propertyObj[name] = descriptor;
+ });
+ });
+
+ Object.getOwnPropertyNames(params)
+ .filter(name =>
+ ['Name', 'Extends', 'Abstract', 'Implements'].indexOf(name) === -1)
+ .concat(Object.getOwnPropertySymbols(params))
+ .forEach(this._copyPropertyDescriptor.bind(this, params, propertyObj));
+
+ Object.defineProperties(this.prototype, propertyObj);
+ Object.defineProperties(this.prototype, {
+ 'parent': {
+ writable: false,
+ configurable: false,
+ enumerable: false,
+ value: _parent,
+ },
+ });
+};
+
+// This introduces the concept of a "meta-interface" which is given by the
+// MetaInterface property on an object's metaclass. For objects whose metaclass
+// is Lang.Class, the meta-interface is Lang.Interface. Subclasses of Lang.Class
+// such as GObject.Class supply their own meta-interface.
+// This is in order to enable creating GObject interfaces with Lang.Interface,
+// much as you can create GObject classes with Lang.Class.
+function _getMetaInterface(params) {
+ if (!params.Requires || params.Requires.length === 0)
+ return null;
+
+ let metaInterface = params.Requires.map((req) => {
+ if (req instanceof Interface)
+ return req.__super__;
+ for (let metaclass = req.prototype.__metaclass__; metaclass;
+ metaclass = metaclass.__super__) {
+ if (metaclass.hasOwnProperty('MetaInterface'))
+ return metaclass.MetaInterface;
+ }
+ return null;
+ })
+ .reduce((best, candidate) => {
+ // This function reduces to the "most derived" meta interface in the list.
+ if (best === null)
+ return candidate;
+ if (candidate === null)
+ return best;
+ for (let sup = candidate; sup; sup = sup.__super__) {
+ if (sup === best)
+ return candidate;
+ }
+ return best;
+ }, null);
+
+ // If we reach this point and we don't know the meta-interface, then it's
+ // most likely because there were only pure-C interfaces listed in Requires
+ // (and those don't have our magic properties.) However, all pure-C
+ // interfaces should require GObject.Object anyway.
+ if (metaInterface === null)
+ throw new Error('Did you forget to include GObject.Object in Requires?');
+
+ return metaInterface;
+}
+
+function Interface(params) {
+ let metaInterface = _getMetaInterface(params);
+ if (metaInterface && metaInterface !== this.constructor)
+ return new metaInterface(...arguments);
+ return this._construct.apply(this, arguments);
+}
+
+Class.MetaInterface = Interface;
+
+/**
+ * Use this to signify a function that must be overridden in an implementation
+ * of the interface. Creating a class that doesn't override the function will
+ * throw an error.
+ */
+Interface.UNIMPLEMENTED = function UNIMPLEMENTED () {
+ throw new Error('Not implemented');
+};
+
+Interface.__super__ = _Base;
+Interface.prototype = Object.create(_Base.prototype);
+Interface.prototype.constructor = Interface;
+
+Interface.prototype._construct = function (params) {
+ if (!params.Name)
+ throw new TypeError("Interfaces require an explicit 'Name' parameter.");
+
+ let newInterface = Object.create(this.constructor.prototype);
+
+ newInterface.__super__ = Interface;
+ newInterface.prototype = Object.create(Interface.prototype);
+ newInterface.prototype.constructor = newInterface;
+
+ newInterface._init.apply(newInterface, arguments);
+
+ Object.defineProperty(newInterface.prototype, '__metaclass__', {
+ writable: false,
+ configurable: false,
+ enumerable: false,
+ value: this.constructor,
+ });
+ Object.defineProperty(newInterface, 'name', {
+ writable: false,
+ configurable: true,
+ enumerable: false,
+ value: params.Name,
+ });
+
+ return newInterface;
+};
+
+Interface.prototype._check = function (proto) {
+ // Check that proto implements all of this interface's required interfaces.
+ // "proto" refers to the object's prototype (which implements the interface)
+ // whereas "this.prototype" is the interface's prototype (which may still
+ // contain unimplemented methods.)
+
+ let unfulfilledReqs = this.prototype.__requires__.filter((required) => {
+ // Either the interface is not present or it is not listed before the
+ // interface that requires it or the class does not inherit it. This is
+ // so that required interfaces don't copy over properties from other
+ // interfaces that require them.
+ let interfaces = proto.__interfaces__;
+ return ((!_interfacePresent(required, proto) ||
+ interfaces.indexOf(required) > interfaces.indexOf(this)) &&
+ !(proto instanceof required));
+ }).map((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.constructor.name}: ${unfulfilledReqs.join(', ')}`);
+ }
+
+ // Check that this interface's required methods are implemented
+ let unimplementedFns = Object.getOwnPropertyNames(this.prototype)
+ .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.constructor.name}` +
+ ' are not implemented yet: ' + unimplementedFns.join(', '));
+};
+
+Interface.prototype.toString = function () {
+ return `[interface ${this.constructor.name} for ${this.prototype.constructor.name}]`;
+};
+
+Interface.prototype._init = function (params) {
+ let propertyObj = {};
+ Object.getOwnPropertyNames(params)
+ .filter((name) => ['Name', 'Requires'].indexOf(name) === -1)
+ .forEach((name) => {
+ let descriptor = Object.getOwnPropertyDescriptor(params, name);
+
+ // Create wrappers on the interface object so that generics work (e.g.
+ // SomeInterface.some_function(this, blah) instead of
+ // SomeInterface.prototype.some_function.call(this, blah)
+ if (typeof descriptor.value === 'function') {
+ let interfaceProto = this.prototype; // capture in closure
+ this[name] = function () {
+ return interfaceProto[name].call.apply(interfaceProto[name],
+ arguments);
+ };
+ }
+
+ // writable and enumerable are inherited, see note in Class._init()
+ descriptor.configurable = false;
+
+ propertyObj[name] = descriptor;
+ });
+
+ Object.defineProperties(this.prototype, propertyObj);
+ Object.defineProperties(this.prototype, {
+ '__requires__': {
+ writable: false,
+ configurable: false,
+ enumerable: false,
+ value: params.Requires || [],
+ },
+ });
+};
diff --git a/modules/lang.js b/modules/lang.js
index e40fefd..8e5cf8d 100644
--- a/modules/lang.js
+++ b/modules/lang.js
@@ -1,4 +1,6 @@
/* -*- mode: js; indent-tabs-mode: nil; -*- */
+/* exported Class, Interface, bind, copyProperties, copyPublicProperties,
+countProperties */
// Copyright (c) 2008 litl, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -21,7 +23,10 @@
// Utilities that are "meta-language" things like manipulating object props
-const Gi = imports._gi;
+const Legacy = imports._legacy;
+
+var Class = Legacy.Class;
+var Interface = Legacy.Interface;
function countProperties(obj) {
let count = 0;
@@ -95,392 +100,3 @@ function bind(obj, callback) {
return callback.apply(me, args);
};
}
-
-// Class magic
-// Adapted from MooTools, MIT license
-// https://github.com/mootools/mootools-core
-
-function _Base() {
- throw new TypeError('Cannot instantiate abstract class _Base');
-}
-
-_Base.__super__ = null;
-_Base.prototype._init = function() { };
-_Base.prototype._construct = function() {
- this._init.apply(this, arguments);
- return this;
-};
-_Base.prototype.toString = function() {
- return `[object ${this.constructor.name}]`;
-};
-
-function _parent() {
- if (!this.__caller__)
- throw new TypeError("The method 'parent' cannot be called");
-
- let caller = this.__caller__;
- let name = caller._name;
- let parent = caller._owner.__super__;
-
- let previous = parent ? parent.prototype[name] : undefined;
-
- if (!previous)
- throw new TypeError("The method '" + name + "' is not on the superclass");
-
- return previous.apply(this, arguments);
-}
-
-function _interfacePresent(required, proto) {
- if (!proto.__interfaces__)
- return false;
- if (proto.__interfaces__.indexOf(required) !== -1)
- return true; // implemented here
- // Might be implemented on a parent class
- return _interfacePresent(required, proto.constructor.__super__.prototype);
-}
-
-function getMetaClass(params) {
- if (params.MetaClass)
- return params.MetaClass;
-
- if (params.Extends && params.Extends.prototype.__metaclass__)
- return params.Extends.prototype.__metaclass__;
-
- return null;
-}
-
-function Class(params) {
- let metaClass = getMetaClass(params);
-
- if (metaClass && metaClass != this.constructor) {
- // Trick to apply variadic arguments to constructors --
- // bind the arguments into the constructor function.
- let args = Array.prototype.slice.call(arguments);
- let curried = Function.prototype.bind.apply(metaClass, [,].concat(args));
- return new curried();
- } else {
- return this._construct.apply(this, arguments);
- }
-}
-
-Class.__super__ = _Base;
-Class.prototype = Object.create(_Base.prototype);
-Class.prototype.constructor = Class;
-
-Class.prototype.wrapFunction = function(name, meth) {
- if (meth._origin) meth = meth._origin;
-
- function wrapper() {
- let prevCaller = this.__caller__;
- this.__caller__ = wrapper;
- let result = meth.apply(this, arguments);
- this.__caller__ = prevCaller;
- return result;
- }
-
- wrapper._origin = meth;
- wrapper._name = name;
- wrapper._owner = this;
-
- return wrapper;
-}
-
-Class.prototype.toString = function() {
- return `[object ${this.constructor.name} for ${this.prototype.constructor.name}]`;
-};
-
-Class.prototype._construct = function(params) {
- if (!params.Name) {
- throw new TypeError("Classes require an explicit 'Name' parameter.");
- }
- let name = params.Name;
-
- let parent = params.Extends;
- if (!parent)
- parent = _Base;
-
- let newClass;
- if (params.Abstract) {
- newClass = function() {
- throw new TypeError('Cannot instantiate abstract class ' + name);
- };
- } else {
- newClass = function() {
- this.__caller__ = null;
-
- return this._construct.apply(this, arguments);
- };
- }
-
- // Since it's not possible to create a constructor with
- // a custom [[Prototype]], we have to do this to make
- // "newClass instanceof Class" work, and so we can inherit
- // methods/properties of Class.prototype, like wrapFunction.
- Object.setPrototypeOf(newClass, this.constructor.prototype);
-
- newClass.__super__ = parent;
- newClass.prototype = Object.create(parent.prototype);
- newClass.prototype.constructor = newClass;
-
- newClass._init.apply(newClass, arguments);
-
- let interfaces = params.Implements || [];
- // If the parent already implements an interface, then we do too
- if (parent instanceof Class)
- interfaces = interfaces.filter((iface) => !parent.implements(iface));
-
- Object.defineProperties(newClass.prototype, {
- '__metaclass__': { writable: false,
- configurable: false,
- enumerable: false,
- value: this.constructor },
- '__interfaces__': { writable: false,
- configurable: false,
- enumerable: false,
- value: interfaces }
- });
- Object.defineProperty(newClass, 'name', {
- writable: false,
- configurable: true,
- enumerable: false,
- value: name,
- });
-
- interfaces.forEach((iface) => {
- iface._check(newClass.prototype);
- });
-
- return newClass;
-};
-
-/**
- * Check whether this class conforms to the interface "iface".
- * @param {object} iface a Lang.Interface
- * @returns: whether this class implements iface
- * @type: boolean
- */
-Class.prototype.implements = function (iface) {
- if (_interfacePresent(iface, this.prototype))
- return true;
- if (this.__super__ instanceof Class)
- return this.__super__.implements(iface);
- return false;
-};
-
-// key can be either a string or a symbol
-Class.prototype._copyPropertyDescriptor = function(params, propertyObj, key) {
- let descriptor = Object.getOwnPropertyDescriptor(params, key);
-
- if (typeof descriptor.value === 'function')
- descriptor.value = this.wrapFunction(key, descriptor.value);
-
- // we inherit writable and enumerable from the property
- // descriptor of params (they're both true if created from an
- // object literal)
- descriptor.configurable = false;
-
- propertyObj[key] = descriptor;
-};
-
-Class.prototype._init = function(params) {
- let name = params.Name;
-
- let propertyObj = { };
-
- let interfaces = params.Implements || [];
- interfaces.forEach((iface) => {
- Object.getOwnPropertyNames(iface.prototype)
- .filter((name) => !name.startsWith('__') && name !== 'constructor')
- .filter((name) => !(name in this.prototype))
- .forEach((name) => {
- let descriptor = Object.getOwnPropertyDescriptor(iface.prototype,
- name);
- // writable and enumerable are inherited, see note above
- descriptor.configurable = false;
- propertyObj[name] = descriptor;
- });
- });
-
- Object.getOwnPropertyNames(params)
- .filter(name =>
- ['Name', 'Extends', 'Abstract', 'Implements'].indexOf(name) === -1)
- .concat(Object.getOwnPropertySymbols(params))
- .forEach(this._copyPropertyDescriptor.bind(this, params, propertyObj));
-
- Object.defineProperties(this.prototype, propertyObj);
- Object.defineProperties(this.prototype, {
- 'parent': { writable: false,
- configurable: false,
- enumerable: false,
- value: _parent }});
-};
-
-// This introduces the concept of a "meta-interface" which is given by the
-// MetaInterface property on an object's metaclass. For objects whose metaclass
-// is Lang.Class, the meta-interface is Lang.Interface. Subclasses of Lang.Class
-// such as GObject.Class supply their own meta-interface.
-// This is in order to enable creating GObject interfaces with Lang.Interface,
-// much as you can create GObject classes with Lang.Class.
-function _getMetaInterface(params) {
- if (!params.Requires || params.Requires.length === 0)
- return null;
-
- let metaInterface = params.Requires.map((req) => {
- if (req instanceof Interface)
- return req.__super__;
- for (let metaclass = req.prototype.__metaclass__; metaclass;
- metaclass = metaclass.__super__) {
- if (metaclass.hasOwnProperty('MetaInterface'))
- return metaclass.MetaInterface;
- }
- return null;
- })
- .reduce((best, candidate) => {
- // This function reduces to the "most derived" meta interface in the list.
- if (best === null)
- return candidate;
- if (candidate === null)
- return best;
- for (let sup = candidate; sup; sup = sup.__super__) {
- if (sup === best)
- return candidate;
- }
- return best;
- }, null);
-
- // If we reach this point and we don't know the meta-interface, then it's
- // most likely because there were only pure-C interfaces listed in Requires
- // (and those don't have our magic properties.) However, all pure-C
- // interfaces should require GObject.Object anyway.
- if (metaInterface === null)
- throw new Error('Did you forget to include GObject.Object in Requires?');
-
- return metaInterface;
-}
-
-function Interface(params) {
- let metaInterface = _getMetaInterface(params);
- if (metaInterface && metaInterface !== this.constructor) {
- // Trick to apply variadic arguments to constructors --
- // bind the arguments into the constructor function.
- let args = Array.prototype.slice.call(arguments);
- let curried = Function.prototype.bind.apply(metaInterface, [,].concat(args));
- return new curried();
- }
- return this._construct.apply(this, arguments);
-}
-
-Class.MetaInterface = Interface;
-
-/**
- * Use this to signify a function that must be overridden in an implementation
- * of the interface. Creating a class that doesn't override the function will
- * throw an error.
- */
-Interface.UNIMPLEMENTED = function UNIMPLEMENTED () {
- throw new Error('Not implemented');
-};
-
-Interface.__super__ = _Base;
-Interface.prototype = Object.create(_Base.prototype);
-Interface.prototype.constructor = Interface;
-
-Interface.prototype._construct = function (params) {
- if (!params.Name)
- throw new TypeError("Interfaces require an explicit 'Name' parameter.");
-
- let newInterface = Object.create(this.constructor.prototype);
-
- newInterface.__super__ = Interface;
- newInterface.prototype = Object.create(Interface.prototype);
- newInterface.prototype.constructor = newInterface;
-
- newInterface._init.apply(newInterface, arguments);
-
- Object.defineProperty(newInterface.prototype, '__metaclass__',
- { writable: false,
- configurable: false,
- enumerable: false,
- value: this.constructor });
- Object.defineProperty(newInterface, 'name', {
- writable: false,
- configurable: true,
- enumerable: false,
- value: params.Name,
- });
-
- return newInterface;
-};
-
-Interface.prototype._check = function (proto) {
- // Check that proto implements all of this interface's required interfaces.
- // "proto" refers to the object's prototype (which implements the interface)
- // whereas "this.prototype" is the interface's prototype (which may still
- // contain unimplemented methods.)
-
- let unfulfilledReqs = this.prototype.__requires__.filter((required) => {
- // Either the interface is not present or it is not listed before the
- // interface that requires it or the class does not inherit it. This is
- // so that required interfaces don't copy over properties from other
- // interfaces that require them.
- let interfaces = proto.__interfaces__;
- return ((!_interfacePresent(required, proto) ||
- interfaces.indexOf(required) > interfaces.indexOf(this)) &&
- !(proto instanceof required));
- }).map((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.constructor.name}: ${unfulfilledReqs.join(', ')}`);
- }
-
- // Check that this interface's required methods are implemented
- let unimplementedFns = Object.getOwnPropertyNames(this.prototype)
- .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.constructor.name}` +
- ' are not implemented yet: ' + unimplementedFns.join(', '));
-};
-
-Interface.prototype.toString = function () {
- return `[interface ${this.constructor.name} for ${this.prototype.constructor.name}]`;
-};
-
-Interface.prototype._init = function (params) {
- let name = params.Name;
-
- let propertyObj = {};
- Object.getOwnPropertyNames(params)
- .filter((name) => ['Name', 'Requires'].indexOf(name) === -1)
- .forEach((name) => {
- let descriptor = Object.getOwnPropertyDescriptor(params, name);
-
- // Create wrappers on the interface object so that generics work (e.g.
- // SomeInterface.some_function(this, blah) instead of
- // SomeInterface.prototype.some_function.call(this, blah)
- if (typeof descriptor.value === 'function') {
- let interfaceProto = this.prototype; // capture in closure
- this[name] = function () {
- return interfaceProto[name].call.apply(interfaceProto[name],
- arguments);
- };
- }
-
- // writable and enumerable are inherited, see note in Class._init()
- descriptor.configurable = false;
-
- propertyObj[name] = descriptor;
- });
-
- Object.defineProperties(this.prototype, propertyObj);
- Object.defineProperties(this.prototype, {
- '__requires__': { writable: false,
- configurable: false,
- enumerable: false,
- value: params.Requires || [] }
- });
-};
diff --git a/modules/modules.gresource.xml b/modules/modules.gresource.xml
index 8d2849c..2f7cfb6 100644
--- a/modules/modules.gresource.xml
+++ b/modules/modules.gresource.xml
@@ -14,6 +14,7 @@
<file>modules/coverage.js</file>
<file>modules/gettext.js</file>
<file>modules/lang.js</file>
+ <file>modules/_legacy.js</file>
<file>modules/mainloop.js</file>
<file>modules/jsUnit.js</file>
<file>modules/signals.js</file>
diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js
index 556b7b2..5918de4 100644
--- a/modules/overrides/GObject.js
+++ b/modules/overrides/GObject.js
@@ -18,9 +18,10 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-const Lang = imports.lang;
const Gi = imports._gi;
const GjsPrivate = imports.gi.GjsPrivate;
+const Lang = imports.lang;
+const Legacy = imports._legacy;
let GObject;
@@ -144,7 +145,7 @@ const GObjectMeta = new Lang.Class({
let newClass = Gi.register_type(parent.prototype, gtypename,
gobjectInterfaces, propertiesArray);
- // See Class.prototype._construct in lang.js for the reasoning
+ // See Class.prototype._construct in _legacy.js for the reasoning
// behind this direct prototype set.
Object.setPrototypeOf(newClass, this.constructor.prototype);
newClass.__super__ = parent;
@@ -214,7 +215,7 @@ GObjectInterface.prototype._construct = function (params) {
let newInterface = Gi.register_interface(gtypename, gobjectInterfaces,
properties);
- // See Class.prototype._construct in lang.js for the reasoning
+ // See Class.prototype._construct in _legacy.js for the reasoning
// behind this direct prototype set.
Object.setPrototypeOf(newInterface, this.constructor.prototype);
newInterface.__super__ = GObjectInterface;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]