Skip to content

Instantly share code, notes, and snippets.

@ptomato
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ptomato/a768cfbaeb26724acdab to your computer and use it in GitHub Desktop.
Save ptomato/a768cfbaeb26724acdab to your computer and use it in GitHub Desktop.
GJS overrides reader
const Gio = imports.gi.Gio;
let file = Gio.File.new_for_path(ARGV[0]);
let moduleName = file.get_basename().split('.')[0];
imports.searchPath.unshift(file.get_parent().get_path());
let module = imports[moduleName];
imports.searchPath.shift();
// Create missing parts of GObject-introspected API. Since we are importing the
// override file directly instead of together with the GIR module, then if we
// don't do this, statements like this will fail:
// GLib.Variant.prototype.toString = function () { ... };
let lastAttempt;
while (true) {
try {
module._init();
break;
} catch (e if e instanceof TypeError) {
if (!e.message.search('is undefined'))
throw e;
let undefinedSymbol = e.message.split(' ')[0];
let props = undefinedSymbol.split('.');
if (lastAttempt === undefinedSymbol)
throw e;
lastAttempt = undefinedSymbol;
if (props[0] === 'this' || props[0] === moduleName)
props.shift();
let object = module;
let name;
while((name = props.shift())) {
object[name] = function () {};
object = object[name];
}
continue;
}
}
function ApiSymbol(name, type) {
this.name = name;
this.type = type;
this.children = [];
}
// These are modules imported by the overrides files, that we don't want to
// introspect. I'm not sure if there's a way to tell if an object was imported
// via imports or imports.gi.
const MODULES = ['ByteArray', 'Gi', 'GjsPrivate', 'GObject', 'Lang'];
ApiSymbol.prototype.gather = function (object, inPrototype) {
Object.keys(object).forEach((name) => {
if (name.startsWith('_'))
return;
if (this.type === 'module' && name === this.name || MODULES.indexOf(name) !== -1)
return;
if (this.type === 'class' && name === 'prototype')
return;
if (name === 'constructor')
return;
let member = object[name];
if (typeof member === 'undefined')
return;
let symbol = new ApiSymbol(name, typeof member);
if (typeof member.prototype !== 'undefined' && Object.keys(member.prototype).length > 0)
symbol.type = 'class';
if (member instanceof Array)
symbol.type = 'array';
if (inPrototype && this.type === 'class' && symbol.type === 'function')
symbol.type = 'method';
this.children.push(symbol);
if (symbol.type === 'object') {
symbol.gather(member);
} else if (symbol.type === 'class') {
symbol.gather(member);
symbol.gather(member.prototype, true);
}
});
};
let api = new ApiSymbol(moduleName, 'module');
api.gather(module[moduleName]);
print(JSON.stringify(api, null, ' '));
import importlib
import inspect
import os.path
import sys
import gi
dirname, basename = os.path.split(sys.argv[1])
modulename, ext = os.path.splitext(basename)
oldsyspath = sys.path
sys.path = [dirname] + sys.path
module = importlib.import_module('gi.overrides.' + modulename)
sys.path = oldsyspath
class ApiSymbol(object):
def __init__(self, name, typ):
self.name = name
self.type = typ
self.children = []
_GI_INTERNAL = ['deprecated_init', 'get_introspection_module', 'override']
def gather(self, obj):
for name in obj.__dict__:
if name.startswith('_'):
continue
if name in self._GI_INTERNAL:
continue
member = obj.__dict__[name]
# This skips over the corresponding module imported from the GIR
if isinstance(member, gi.module.IntrospectionModule):
continue
# hrtype = human readable type
hrtype = type(member)
if inspect.ismodule(member):
continue
elif inspect.isclass(member):
hrtype = 'class'
elif inspect.ismethod(member):
hrtype = 'method'
elif inspect.isfunction(member):
hrtype = 'function'
# I wonder why inspect doesn't get this
if self.type == 'class' and hrtype == 'function':
hrtype = 'method'
symbol = ApiSymbol(name, hrtype)
self.children.append(symbol)
if hrtype == 'class':
symbol.gather(member)
def __str__(self):
retval = 'name: {0.name}\ntype: {0.type}\n'.format(self)
if self.children:
children_descs = '\n'.join(map(str, self.children))
children_descs = '\n'.join(map(lambda l: ' ' + l, children_descs.split('\n')))
retval += 'children:\n' + children_descs
return retval
api = ApiSymbol(modulename, 'module')
api.gather(module)
print api
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment