[gjs/wip/ptomato/classes: 7/11] lang: Move all legacy Lang.Class code



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]