Re: libseed-list Hooking into the imports system
- From: Jonatan Liljedahl <lijon kymatica com>
- To: Alan Knowles <alan akbkhome com>
- Cc: Jonatan Liljedahl <j r liljedahl gmail com>, libseed-list gnome org
- Subject: Re: libseed-list Hooking into the imports system
- Date: Mon, 12 Jul 2010 00:14:06 +0200
I think I'll go with DynamicObject.create() to be similar to the
existing Object.create(). I'll send a new version in a separate mail.
Note that the getPropertyNames callback can't be implemented yet, since
in seed.h we have:
/* TODO: Have to decide on accumulator API
//typedef void (*SeedObjectGetPropertyNamesCallback) (SeedContext ctx, */
typedef void (*SeedObjectGetPropertyNamesCallback) (void);
Also, I found a typo in seed.h, the deletePropertyCallback typedef
wasn't right. Here's the fix:
diff --git a/libseed/seed.h b/libseed/seed.h
index a5824df..3606e80 100644
--- a/libseed/seed.h
+++ b/libseed/seed.h
@@ -318,9 +318,7 @@ typedef gboolean (*SeedObjectSetPropertyCallback)
(SeedContext ctx,
SeedException * e);
typedef gboolean (*SeedObjectDeletePropertyCallback) (SeedContext ctx,
SeedObject object,
- SeedString
- property_name,
- SeedValue value,
+ SeedString
property_name,
SeedException * e);
/* TODO: Have to decide on accumulator API
//typedef void (*SeedObjectGetPropertyNamesCallback) (SeedContext ctx, */
Alan Knowles wrote:
imports.DynamicObject.define(....)
could not think of anything else of the top of my head..
Regards
Alan
--- On 11/Jul/2010, Jonatan Liljedahl wrote:
Yes, that makes sense. But perhaps the module should be named something
else than autoprop. Any ideas? Perhaps it should go into the Seed module
(if you guys want to include it) or some other module for similar future
stuff?
/Jonatan
Alan Knowles wrote:
yes, that does sound good, I guess following the internal API as well makes some sense..
var o = imports.autoprop.defineObject({
getProperty : function (name) {
..
},
setProperty : function (name, value) {
..
},
deleteProperty: function(name) {
..
},
hasProperty: function(name) {
..
},
callAsFunction: function(args) {} ,
callAsConstructor: function(args) {} ,
finalize : function() { }
...
});
/* Parent Class */
NULL, /* Static Values */
NULL, /* Static Functions */
NULL,
NULL, /* Finalize */
NULL, /* Has Property */
NULL, /* Get Property */
NULL, /* Set Property */
NULL, /* Delete Property */
NULL, /* Get Property Names */
NULL, /* Call As Function */
NULL, /* Call As Constructor */
NULL, /* Has Instance */
NULL /* Convert To Type */
Regards
Alan
--- On 10/Jul/2010, Jonatan Liljedahl wrote:
Sure, defineObject() might be more in line with the current standard,
even though I think the methods should be named getProperty and
setProperty or something like that. ('get' and 'set' fields in
defineProperty() already refers to Property while in this case we define
an Object, not a property)
But, it's a little bit more work to wrap it in a function like
defineObject() since I now simply use the existing C-side JS-class
creation mechanism.. Do you think it would be worth it?
/Jonatan
Alan Knowles wrote:
Do you think it would be an idea to copy the nearest standard here for your 'autoprop' Object. ?
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Object/defineProperty
var o = imports.autoprop.defineObject({
get : function (name) {
},
set : function (name, value) {
},
enumerable: function(name) {
...
}
});
Regards
Alan
--- On 02/Jul/2010, Jonatan Liljedahl wrote:
Yes, this was a nice solution. See attached 'autoprop' module. (Feel
free to include it in the main distro, I think it can be very useful for
all sorts of special objects. Perhaps one should also add callbacks for
CallAsFunction, CallAsConstructor, GetPropertyNames, etc..)
With this I could simply do a custom module-importer object like this:
var make_importer = function(startPath, chain) {
var o = new imports.autoprop.Object;
o.get_property = function(name) {
if(name==="searchPath") return imports.searchPath;
var searchPath = startPath || imports.searchPath;
for(var i=0;i<searchPath.length;i++) {
var path = searchPath[i];
var file = path+'/'+name;
var file_als = file+'.als';
if(_module_imports[file])
return _module_imports[file];
if(GLib.file_test(file,GLib.FileTest.IS_DIR)) {
return _module_imports[file] =
make_importer([file],chain.concat(name));
} else
if(GLib.file_test(file_als,GLib.FileTest.IS_REGULAR)) {
GLib.file_get_contents(file_als,script={});
ctx = new Context;
ctx.global.__script_path__ = path;
ctx.eval(script.contents);
return _module_imports[file]=ctx.global;
}
}
// fall back to original seed imports
for(var i=0,ns=imports;i<chain.length;i++)
ns = ns[chain[i]];
return ns[name] || null;
}
o.set_property = function(name, value) {
if(name === "searchPath") {
imports.searchPath = value;
return true;
}
return false; //or true to not allow custom props to be set..
}
return o;
}
var module = make_importer(undefined, []);
// then I can use 'module' instead of 'imports' and it works exactly
// the same except it also handles my algoscript modules:
var Gtk = module.gi.Gtk;
var foo = module.mydir.mysubdirfoo;
/Jonatan
Jonatan Liljedahl wrote:
I don't see how this would be solved easily..
if 'xxx' is my magic handler, then autoloader can create an object 'xxx'
that calls my handler on get_property().. so my handler would be called
with 'zzzz'. Let's say 'zzzz' is a folder, and I want xxx.zzzz.foo to
load the file foo from that folder.. Nothing I can return from a
javascript handler would allow 'foo' to be fetched unless it's already
an existing member of 'zzzz', since there's no
Object.prototype.__lookupProperty__ hook or similar.
Maybe one could make a generic 'dynamic object' class in C, which could
be used recursively...
auto = new imports.dynamic.Object;
auto.get_prop = function(prop) {
var x = my_lookup(prop,base);
// if x is dir, return a new dynamic Object with a handler for that
directory..
// if x is a file, parse and return namespace..
// etc...
};
/Jonatan
Alan Knowles wrote:
It sounds alot like the autoload feature that was added to PHP.
It was only after the feature was made available that everyone
realized that it was a flawed design (by that time people had already
started using it...)
The partial solution was to add SPL::autoload() which does solve some
of the problems..
for seed it might be that we have something like
imports.autoloader.register('xxx', function(args) {....});
or
imports.autoloader.register('xxx', imports.xxx.importer);
ZZZ = imports.autoloader.xxx.zzzz
That should give you the syntax you are after, without making it too
confusing, along with enabling multiple handlers to be defined..
autoloader could easily be implemented in a very simple module...
Regards
Alan
--- On 30/Jun/2010, Jonatan Liljedahl wrote:
Alan Knowles wrote:
My concern here is that this would make code very difficult to
understand.
Is there a way to implement this where it is an explicit behavior
rather than an implicit,
Hence, when it is being used, you know from the syntax that it may
be trying to do
> something magical, rather than overloading the 'reasonably'
> predictable behavior of imports.
I think that would be up to the developer, to use the notFoundHandler
in a wise way. My plan is mostly very 'reasonable', simply to add
support for modules written in a custom language and not having to
bother if a module is written in C, javascript, algoscript, or
imported from GIR.
But I can see other (more or less reasonable) use cases too, creating
virtual namespaces under imports to integrate with other stuff, and I
think it would be a very elegant feature.
or could this not be done client side?
eg.
imports.smartloader.load('xxx');
Yes, that's almost what I do now, I have an
imports.algoscript.Importer class with a root instance at
imports.algoscript._root_importer, so that I can do:
zoo = imports.algoscript._root_importer._import('foo.bar.zoo');
But it means a lot of not-well-working duplication of the seed
imports object, since I want to use it for both normal seed imports
and also to handle directories the same was as seed imports does.
(above should work if foo is a dir, bar a file and zoo a variable in
that file)...
Also it looks very ugly, so I have created special syntactic sugar in
algoscript to make it look like "zoo = import foo.bar.zoo".
The very nice thing with the imports object is that the properties
are virtual (they are created/found on the fly), but that any "real"
JS object in the chain simply takes over from there. You don't need
to care what part is a directory, a file, or a variable in that file,
or a member of an object in that file, etc.. This is not possible on
client side, I'd have to write my own importer class in C for this,
more or less duplicating everything from seed-importer.c...
But I'd really prefer to just use the existing system that's already
there and does it the right way: then I could just have a single
handler function, something like this:
imports.__notFoundHandler__ = function(name,dir) {
var dirs = [dir];
var ns;
if(dir!=imports.searchPath[0])
dirs = dirs.concat(imports.searchPath);
dirs.forEach(function(d) {
if (d == '.' && __script_path__)
d = __script_path__;
var f = d+'/'+name+'.as';
if (file_exist(f)) {
var ctx = new algoscript.Context;
ctx.eval_file(f);
ns = ctx.global;
ctx.destroy();
}
});
return ns;
}
For the toString stuff, I guess that's needed only for this patch.
BTW i'll be offline tommorow till next week, unless I can get net
access...
offline, that sounds scary... ;)
see you later, thanks for the feedback!
/Jonatan
Regards
Alan
--- On 30/Jun/2010, Jonatan Liljedahl wrote:
Here is a small patch that adds a feature that I'd be very happy to
see.
It allows one to hook into the imports system by defining a handler
for
when a module was not found. Example:
imports.__notFoundHandler__ = function(name, dir) {
print("making "+name);
return {foo:123}
}
f = imports.foobar;
print(f.foo);
running above file prints:
making foobar
123
This can be used to integrate all sorts of cool stuff with the imports
object. For example, the handler can iterate over
imports.searchPath to
find n+".html" and return an object representation of the DOM tree, or
parsing a custom language (hmmmm ;)), or perhaps even connect to an
online database of modules.. x = imports.seedgems.foo; -> updates foo
from an online repository, etc...
Currently it only passes the first path from
seed_importer_search_dirs() as the second arg, at least this works
for the case when the search is done inside a single directory, but
I guess it would be better to just send the whole path GSList by
converting it to a JS array. One could still work around it on the
script side by merging the dir arg with imports.searchPath if dir
!= searchPath[0].
BTW, this patch also adds the toString and toValue hack to
seed_importer_dir_get_property() so it doesn't call the handler
saying that "toString" module wasn't found, etc..
/Jonatan
_______________________________________________
libseed-list mailing list
libseed-list gnome org
http://mail.gnome.org/mailman/listinfo/libseed-list
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]