views:

483

answers:

2

Is there any way that my script can retrieve metadata values that are declared in its own header? I don't see anything promising in the API, except perhaps GM_getValue(). That would of course involve a special name syntax. I have tried, for example: GM_getValue("@name").

The motivation here is to avoid redundant specification.

If GM metadata is not directly accessible, perhaps there's a way to read the body of the script itself. It's certainly in memory somewhere, and it wouldn't be too awfully hard to parse for "// @". (That may be necessary in my case any way, since the value I'm really interested in is @version, which is an extended value read by userscripts.org.)

+6  A: 

Yes. A very simple example is:

var metadata=<> 
// ==UserScript==
// @name           Reading metadata
// @namespace      http://www.afunamatata.com/greasemonkey/
// @description    Read in metadata from the header
// @version        0.9
// @include        http://stackoverflow.com/questions/104568/accessing-greasemonkey-metadata-from-within-your-script
// ==/UserScript==
</>.toString();

GM_log(metadata);

See this thread on the greasemonkey-users group for more information. A more robust implementation can be found near the end.

Athena
+3  A: 

Building on Athena's answer, here is my generalized solution that yields an object of name/value pairs, each representing a metadata property. Note that certain properties can have multiple values, (@include, @exclude, @require, @resource), therefore my parser captures those as Arrays - or in the case of @resource, as a subordinate Object of name/value pairs.

var scriptMetadata = parseMetadata(.toString());

function parseMetadata(headerBlock)
{
    // split up the lines, omitting those not containing "// @"
    var lines = headerBlock.split(/[\r\n]+/).filter(/\/\/ @/);
    // initialize the result object with empty arrays for the enumerated properties
    var metadata = { include: [], exclude: [], require: [], resource: {} };
    for each (var line in lines)
    {
        [line, name, value] = line.match(/\/\/ @(\S+)\s*(.*)/);
        if (metadata[name] instanceof Array)
            metadata[name].push(value);
        else if (metadata[name] instanceof Object) {
            [rName, rValue] = value.split(/\s+/); // each resource is named
            metadata[name][rName] = rValue;
        }
        else
            metadata[name] = value;
    }
    return metadata;
}

// example usage
GM_log("version: " + scriptMetadata["version"]);
GM_log("res1: " + scriptMetadata["resource"]["res1"]);

This is working nicely in my scripts.

EDIT: Added @resource and @require, which were introduced in Greasemonkey 0.8.0.

Chris Noe