diff --git a/CHANGES.md b/CHANGES.md
index 3457fa28e0fa6cb76ca37be167e2965b04ded640..afcaa98b8f79543cdc847dfb6113ec64ff12e091 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,6 @@
+## Dec 9, 2014
+* Offer new class-based API and object-based arguments
+* Version 0.11
 
 ## Oct 23, 2013
 
diff --git a/README.md b/README.md
index 5b8c779f0f5e577e8ee97fd3f7dc25077255234e..65dab4c5fcdeda2df7000f72a96c872a8e3a03d2 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,18 @@
-JSONPath [![build status](https://secure.travis-ci.org/s3u/JSONPath.png)](http://travis-ci.org/s3u/JSONPath)
-========
+# JSONPath [![build status](https://secure.travis-ci.org/s3u/JSONPath.png)](http://travis-ci.org/s3u/JSONPath)
 
 Analyse, transform, and selectively extract data from JSON documents (and JavaScript objects).
 
-Install
--------
+# Install
     
     npm install JSONPath
 
-Usage
------
+# Usage
 
 In node.js:
 
 ```js
-var jsonPath = require('JSONPath');
-jsonPath.eval(obj, path);
+var JSONPath = require('JSONPath');
+JSONPath({json: obj, path: path});
 ```
 
 For browser usage you can directly include `lib/jsonpath.js`, no browserify
@@ -24,11 +21,32 @@ magic necessary:
 ```html
 <script src="lib/jsonpath.js"></script>
 <script>
-    jsonPath.eval(obj, path);
+    JSONPath({json: obj, path: path});
 </script>
 ```
 
-Examples
+An alternative syntax is available as:
+
+```js
+JSONPath(options, obj, path);
+```
+
+The following format is now deprecated:
+
+```js
+jsonPath.eval(options, obj, path);
+```
+
+Other properties that can be supplied for
+options (the first argument) include:
+
+- ***autostart*** (**default: true**) - If this is supplied as `false`, one may call the `evaluate` method manually as needed.
+- ***flatten*** (**default: false**) - Whether the returned array of results will be flattened to a single dimension array.
+- ***resultType*** (**default: "value"**) - Can be case-insensitive form of "value" or "path" to determine whether to return results as the values of the found items or as their absolute paths.
+- ***sandbox*** (**default: An empty object **) - Key-value map of variables to be available to code evaluations such as filtering expressions. (Note that the current path and value will also be available; see the Syntax section for details.)
+- ***wrap*** (**default: true**) - Whether or not to wrap the results in an array. If `wrap` is set to false, and no results are found, `false` will be returned (as opposed to an empty array). If `wrap` is set to false and a single result is found, that result will be the only item returned. An array will still be returned if multiple results are found, however.
+
+Syntax with examples
 --------
 
 Given the following JSON, taken from http://goessner.net/articles/JsonPath/ :
@@ -73,24 +91,27 @@ Given the following JSON, taken from http://goessner.net/articles/JsonPath/ :
 ```
 
 
-XPath               | JSONPath               | Result
-------------------- | ---------------------- | -------------------------------------
-/store/book/author	| $.store.book[*].author | the authors of all books in the store 
-//author            | $..author              | all authors 
-/store/*            | $.store.*              | all things in store, which are some books and a red bicycle.
-/store//price       | $.store..price         | the price of everything in the store.
-//book[3]           | $..book[2]             | the third book
-//book[last()]      | $..book[(@.length-1)]  | the last book in order.
-                    | $..book[-1:]           |
-//book[position()<3]| $..book[0,1]           | the first two books
-                    | $..book[:2]            | 
-//book[isbn]        | $..book[?(@.isbn)]     | filter all books with isbn number
-//book[price<10]    | $..book[?(@.price<10)] | filter all books cheapier than 10
-//*[price>19]/..    | $..[?(@.price>19)]^    | categories with things more expensive than 19
-//*                 | $..*                   | all Elements in XML document. All members of JSON structure.
-
-Development
------------
+XPath               | JSONPath               | Result                                | Notes
+------------------- | ---------------------- | ------------------------------------- | -----
+/store/book/author  | $.store.book[*].author | the authors of all books in the store |
+//author            | $..author              | all authors                           |
+/store/*            | $.store.*              | all things in store, which are some books and a red bicycle.|
+/store//price       | $.store..price         | the price of everything in the store. |
+//book[3]           | $..book[2]             | the third book                        |
+//book[last()]      | $..book[(@.length-1)]<br>$..book[-1:]  | the last book in order.|
+//book[position()<3]| $..book[0,1]<br>$..book[:2]| the first two books               |
+//book/*[self::category\|self::author] or //book/(category,author) in XPath 2.0| $..book[category,author]| the categories and authors of all books |
+//book[isbn]        | $..book[?(@.isbn)]     | filter all books with isbn number     |
+//book[price<10]    | $..book[?(@.price<10)] | filter all books cheapier than 10     |
+//*[price>19]/..    | $..[?(@.price>19)]^    | categories with things more expensive than 19 | Parent (caret) not present in original spec
+//*                 | $..*                   | all Elements in XML document. All members of JSON structure. |
+/store/book/[position()!=1] | $.store.book[?(@path !== "$[\'store\'][\'book\'][0]")] | All books besides that at the path pointing to the first | @path not present in original spec
+
+Any additional variables supplied as properties on the optional
+"sandbox" object option are also available to (parenthetical-based)
+evaluations.
+
+# Development
 
 Running the tests on node: `npm test`. For in-browser tests:
 
@@ -105,7 +126,6 @@ Running the tests on node: `npm test`. For in-browser tests:
 * To run the tests visit [http://localhost:8082/test/test.html]().
 
 
-License
--------
+# License
 
 [MIT License](http://www.opensource.org/licenses/mit-license.php).
diff --git a/lib/jsonpath.js b/lib/jsonpath.js
index 79de8690f470d1453368df9396a8faa71fc3e524..28e07371bd3d46c35303321f2eb80d80f70acbaa 100644
--- a/lib/jsonpath.js
+++ b/lib/jsonpath.js
@@ -33,154 +33,50 @@ var cache = {};
 function push (arr, elem) {arr = arr.slice(); arr.push(elem); return arr;}
 function unshift (elem, arr) {arr = arr.slice(); arr.unshift(elem); return arr;}
 
-function jsonPath (obj, expr, arg) {
-    var $ = obj;
-    var P = {
-        resultType: (arg && arg.resultType) || 'VALUE',
-        flatten: (arg && arg.flatten) || false,
-        wrap: (arg && arg.hasOwnProperty('wrap')) ? arg.wrap : true,
-        sandbox: (arg && arg.sandbox) ? arg.sandbox : {},
-        normalize: function (expr) {
-            if (cache[expr]) {return cache[expr];}
-            var subx = [];
-            var normalized = expr.replace(/[\['](\??\(.*?\))[\]']/g, function ($0,$1) {return '[#' + (subx.push($1) - 1) + ']';})
-                            .replace(/'?\.'?|\['?/g, ';')
-                            .replace(/(?:;)?(\^+)(?:;)?/g, function (_, ups) {return ';' + ups.split('').join(';') + ';';})
-                            .replace(/;;;|;;/g, ';..;')
-                            .replace(/;$|'?\]|'$/g, '');
-            var exprList = normalized.split(';').map(function (expr) {
-                var match = expr.match(/#([0-9]+)/);
-                return !match || !match[1] ? expr : subx[match[1]];
-            });
-            cache[expr] = exprList;
-            return cache[expr];
-        },
-        asPath: function (path) {
-            var i, n, x = path, p = '$';
-            for (i = 1, n = x.length; i < n; i++) {
-                p += /^[0-9*]+$/.test(x[i]) ? ('[' + x[i] + ']') : ("['" + x[i] + "']");
-            }
-            return p;
-        },
-        trace: function (expr, val, path) {
-            // No expr to follow? return path and value as the result of this trace branch
-            if (!expr.length) {return [{path: path, value: val}];}
-
-            var loc = expr[0], x = expr.slice(1);
-            // The parent sel computation is handled in the frame above using the
-            // ancestor object of val
-            if (loc === '^') {return path.length ? [{path: path.slice(0, -1), expr: x, isParentSelector: true}] : [];}
-
-            // We need to gather the return value of recursive trace calls in order to
-            // do the parent sel computation.
-            var ret = [];
-            function addRet (elems) {ret = ret.concat(elems);}
-
-            if (val && val.hasOwnProperty(loc)) { // simple case, directly follow property
-                addRet(P.trace(x, val[loc], push(path, loc)));
-            }
-            else if (loc === '*') { // any property
-                P.walk(loc, x, val, path, function (m, l, x, v, p) {
-                    addRet(P.trace(unshift(m, x), v, p));
-                });
-            }
-            else if (loc === '..') { // all child properties
-                addRet(P.trace(x, val, path));
-                P.walk(loc, x, val, path, function (m, l, x, v, p) {
-                    if (typeof v[m] === 'object') {
-                        addRet(P.trace(unshift('..', x), v[m], push(p, m)));
-                    }
-                });
-            }
-            else if (loc[0] === '(') { // [(expr)]
-                addRet(P.trace(unshift(P.eval(loc, val, path[path.length], path), x), val, path));
-            }
-            else if (loc.indexOf('?(') === 0) { // [?(expr)]
-                P.walk(loc, x, val, path, function (m, l, x, v, p) {
-                    if (P.eval(l.replace(/^\?\((.*?)\)$/, '$1'), v[m], m, path)) {
-                        addRet(P.trace(unshift(m, x), v, p));
-                    }
-                });
-            }
-            else if (loc.indexOf(',') > -1) { // [name1,name2,...]
-                var parts, i;
-                for (parts = loc.split(','), i = 0; i < parts.length; i++) {
-                    addRet(P.trace(unshift(parts[i], x), val, path));
-                }
-            }
-            else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) { // [start:end:step]  Python slice syntax
-                addRet(P.slice(loc, x, val, path));
+function JSONPath (opts, obj, expr) {
+    if (!(this instanceof JSONPath)) {
+        try {
+            return new JSONPath(opts, obj, expr);
+        }
+        catch (e) {
+            if (!e.avoidNew) {
+                throw e;
             }
+            return e.value;
+        }
+    }
 
-            // We check the resulting values for parent selections. For parent
-            // selections we discard the value object and continue the trace with the
-            // current val object
-            return ret.reduce(function (all, ea) {
-                return all.concat(ea.isParentSelector ? P.trace(ea.expr, val, ea.path) : [ea]);
-            }, []);
-        },
-        walk: function (loc, expr, val, path, f) {
-            var i, n, m;
-            if (Array.isArray(val)) {
-                for (i = 0, n = val.length; i < n; i++) {
-                    f(i, loc, expr, val, path);
-                }
-            }
-            else if (typeof val === 'object') {
-                for (m in val) {
-                    if (val.hasOwnProperty(m)) {
-                        f(m, loc, expr, val, path);
-                    }
-                }
-            }
-        },
-        slice: function (loc, expr, val, path) {
-            if (!Array.isArray(val)) {return;}
-            var i,
-                len = val.length, parts = loc.split(':'),
-                start = (parts[0] && parseInt(parts[0], 10)) || 0,
-                end = (parts[1] && parseInt(parts[1], 10)) || len,
-                step = (parts[2] && parseInt(parts[2], 10)) || 1;
-            start = (start < 0) ? Math.max(0, start + len) : Math.min(len, start);
-            end    = (end < 0)    ? Math.max(0, end + len) : Math.min(len, end);
-            var ret = [];
-            for (i = start; i < end; i += step) {
-                ret = ret.concat(P.trace(unshift(i, expr), val, path));
-            }
-            return ret;
-        },
-        eval: function (code, _v, _vname, path) {
-            if (!$ || !_v) {return false;}
-            if (code.indexOf('@path') > -1) {
-                P.sandbox._path = P.asPath(path.concat([_vname]));
-                code = code.replace(/@path/g, '_path');
-            }
-            if (code.indexOf('@') > -1) {
-                P.sandbox._v = _v;
-                code = code.replace(/@/g, '_v');
-            }
-            try {
-                return vm.runInNewContext(code, P.sandbox);
-            }
-            catch(e) {
-                console.log(e);
-                throw new Error('jsonPath: ' + e.message + ': ' + code);
-            }
+    opts = opts || {};
+    var objArgs = opts.hasOwnProperty('json') && opts.hasOwnProperty('path');
+    this.resultType = (opts.resultType && opts.resultType.toLowerCase()) || 'value';
+    this.flatten = opts.flatten || false;
+    this.wrap = opts.hasOwnProperty('wrap') ? opts.wrap : true;
+    this.sandbox = opts.sandbox || {};
+
+    if (opts.autostart !== false) {
+        var ret = this.evaluate((objArgs ? opts.json : obj), (objArgs ? opts.path : expr));
+        if (!ret || typeof reg !== 'object') {
+            throw {avoidNew: true, value: ret, message: "JSONPath should not be called with 'new'"};
         }
-    };
+    }
+}
+
+// PUBLIC METHODS
 
-    var resultType = P.resultType.toLowerCase();
-    if (expr && obj && (resultType === 'value' || resultType === 'path')) {
-        var exprList = P.normalize(expr);
+JSONPath.prototype.evaluate = function (obj, expr) {
+    var self = this;
+    this._obj = obj;
+    if (expr && obj && (this.resultType === 'value' || this.resultType === 'path')) {
+        var exprList = this._normalize(expr);
         if (exprList[0] === '$' && exprList.length > 1) {exprList.shift();}
-        var result = P.trace(exprList, obj, ['$']);
+        var result = this._trace(exprList, obj, ['$']);
         result = result.filter(function (ea) { return ea && !ea.isParentSelector; });
-        if (!result.length) {return P.wrap ? [] : false;}
-        if (result.length === 1 && !P.wrap && !Array.isArray(result[0].value)) {return result[0][resultType] || false;}
+        if (!result.length) {return this.wrap ? [] : false;}
+        if (result.length === 1 && !this.wrap && !Array.isArray(result[0].value)) {return result[0][this.resultType] || false;}
         return result.reduce(function (result, ea) {
-            var valOrPath = ea[resultType];
-            if (resultType === 'path') {valOrPath = P.asPath(valOrPath);}
-            if (P.flatten && Array.isArray(valOrPath)) {
+            var valOrPath = ea[self.resultType];
+            if (self.resultType === 'path') {valOrPath = self._asPath(valOrPath);}
+            if (self.flatten && Array.isArray(valOrPath)) {
                 result = result.concat(valOrPath);
             } else {
                 result.push(valOrPath);
@@ -188,13 +84,157 @@ function jsonPath (obj, expr, arg) {
             return result;
         }, []);
     }
-}
+};
+
+// PRIVATE METHODS
+
+JSONPath.prototype._normalize = function (expr) {
+    if (cache[expr]) {return cache[expr];}
+    var subx = [];
+    var normalized = expr.replace(/[\['](\??\(.*?\))[\]']/g, function ($0, $1) {return '[#' + (subx.push($1) - 1) + ']';})
+                    .replace(/'?\.'?|\['?/g, ';')
+                    .replace(/(?:;)?(\^+)(?:;)?/g, function ($0, ups) {return ';' + ups.split('').join(';') + ';';})
+                    .replace(/;;;|;;/g, ';..;')
+                    .replace(/;$|'?\]|'$/g, '');
+    var exprList = normalized.split(';').map(function (expr) {
+        var match = expr.match(/#([0-9]+)/);
+        return !match || !match[1] ? expr : subx[match[1]];
+    });
+    cache[expr] = exprList;
+    return cache[expr];
+};
+
+JSONPath.prototype._asPath = function (path) {
+    var i, n, x = path, p = '$';
+    for (i = 1, n = x.length; i < n; i++) {
+        p += /^[0-9*]+$/.test(x[i]) ? ('[' + x[i] + ']') : ("['" + x[i] + "']");
+    }
+    return p;
+};
+
+JSONPath.prototype._trace = function (expr, val, path) {
+    // No expr to follow? return path and value as the result of this trace branch
+    var self = this;
+    if (!expr.length) {return [{path: path, value: val}];}
+
+    var loc = expr[0], x = expr.slice(1);
+    // The parent sel computation is handled in the frame above using the
+    // ancestor object of val
+    if (loc === '^') {return path.length ? [{path: path.slice(0, -1), expr: x, isParentSelector: true}] : [];}
 
-if (typeof exports === 'undefined') {
-    window.jsonPath = {eval: jsonPath};
+    // We need to gather the return value of recursive trace calls in order to
+    // do the parent sel computation.
+    var ret = [];
+    function addRet (elems) {ret = ret.concat(elems);}
+
+    if (val && val.hasOwnProperty(loc)) { // simple case, directly follow property
+        addRet(this._trace(x, val[loc], push(path, loc)));
+    }
+    else if (loc === '*') { // any property
+        this._walk(loc, x, val, path, function (m, l, x, v, p) {
+            addRet(self._trace(unshift(m, x), v, p));
+        });
+    }
+    else if (loc === '..') { // all child properties
+        addRet(this._trace(x, val, path));
+        this._walk(loc, x, val, path, function (m, l, x, v, p) {
+            if (typeof v[m] === 'object') {
+                addRet(self._trace(unshift('..', x), v[m], push(p, m)));
+            }
+        });
+    }
+    else if (loc[0] === '(') { // [(expr)]
+        addRet(this._trace(unshift(this._eval(loc, val, path[path.length], path), x), val, path));
+    }
+    else if (loc.indexOf('?(') === 0) { // [?(expr)]
+        this._walk(loc, x, val, path, function (m, l, x, v, p) {
+            if (self._eval(l.replace(/^\?\((.*?)\)$/, '$1'), v[m], m, path)) {
+                addRet(self._trace(unshift(m, x), v, p));
+            }
+        });
+    }
+    else if (loc.indexOf(',') > -1) { // [name1,name2,...]
+        var parts, i;
+        for (parts = loc.split(','), i = 0; i < parts.length; i++) {
+            addRet(this._trace(unshift(parts[i], x), val, path));
+        }
+    }
+    else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) { // [start:end:step]  Python slice syntax
+        addRet(this._slice(loc, x, val, path));
+    }
+
+    // We check the resulting values for parent selections. For parent
+    // selections we discard the value object and continue the trace with the
+    // current val object
+    return ret.reduce(function (all, ea) {
+        return all.concat(ea.isParentSelector ? self._trace(ea.expr, val, ea.path) : [ea]);
+    }, []);
+};
+
+JSONPath.prototype._walk = function (loc, expr, val, path, f) {
+    var i, n, m;
+    if (Array.isArray(val)) {
+        for (i = 0, n = val.length; i < n; i++) {
+            f(i, loc, expr, val, path);
+        }
+    }
+    else if (typeof val === 'object') {
+        for (m in val) {
+            if (val.hasOwnProperty(m)) {
+                f(m, loc, expr, val, path);
+            }
+        }
+    }
+};
+
+JSONPath.prototype._slice = function (loc, expr, val, path) {
+    if (!Array.isArray(val)) {return;}
+    var i,
+        len = val.length, parts = loc.split(':'),
+        start = (parts[0] && parseInt(parts[0], 10)) || 0,
+        end = (parts[1] && parseInt(parts[1], 10)) || len,
+        step = (parts[2] && parseInt(parts[2], 10)) || 1;
+    start = (start < 0) ? Math.max(0, start + len) : Math.min(len, start);
+    end    = (end < 0)    ? Math.max(0, end + len) : Math.min(len, end);
+    var ret = [];
+    for (i = start; i < end; i += step) {
+        ret = ret.concat(this._trace(unshift(i, expr), val, path));
+    }
+    return ret;
+};
+
+JSONPath.prototype._eval = function (code, _v, _vname, path) {
+    if (!this._obj || !_v) {return false;}
+    if (code.indexOf('@path') > -1) {
+        this.sandbox._$_path = this._asPath(path.concat([_vname]));
+        code = code.replace(/@path/g, '_$_path');
+    }
+    if (code.indexOf('@') > -1) {
+        this.sandbox._$_v = _v;
+        code = code.replace(/@/g, '_$_v');
+    }
+    try {
+        return vm.runInNewContext(code, this.sandbox);
+    }
+    catch(e) {
+        console.log(e);
+        throw new Error('jsonPath: ' + e.message + ': ' + code);
+    }
+};
+
+// For backward compatibility (deprecated)
+JSONPath.eval = function (obj, expr, opts) {
+    return JSONPath(opts, obj, expr);
+};
+
+if (typeof module === 'undefined') {
+    window.jsonPath = { // Deprecated
+        eval: JSONPath.eval
+    };
+    window.JSONPath = JSONPath;
 }
 else {
-    exports.eval = jsonPath;
+    module.exports = JSONPath;
 }
 
 }(typeof require === 'undefined' ? null : require));
diff --git a/package.json b/package.json
index 1d395d224ad996f11452e86258a8707b044d40da..7fbeacfea64b7ce28c2b30c0a63354062a492ac8 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,7 @@
             "email": "robert.krahn@gmail.com"
         }
     ],
-    "version": "0.10.0",
+    "version": "0.11.0",
     "repository": {
         "type": "git",
         "url": "git://github.com/s3u/JSONPath.git"
diff --git a/test/test.arr.js b/test/test.arr.js
index 4314fd236d4b61fd024e260948164fd887d5a0b5..d206071ee6f20bca2dde1c633cba6c54fc9c8519 100644
--- a/test/test.arr.js
+++ b/test/test.arr.js
@@ -1,4 +1,4 @@
-var jsonpath = require("../").eval,
+var JSONPath = require('../'),
     testCase = require('nodeunit').testCase
 
 var json = {
@@ -19,16 +19,16 @@ var json = {
 };
 
 module.exports = testCase({
-    "get single": function (test) {
+    'get single': function (test) {
         var expected = json.store.book;
-        var result = jsonpath(json, "store.book", {flatten: true, wrap: false});
+        var result = JSONPath({json: json, path: 'store.book', flatten: true, wrap: false});
         test.deepEqual(expected, result);
         test.done();
     },
 
-    "get arr": function (test) {
+    'get arr': function (test) {
         var expected = json.store.books;
-        var result = jsonpath(json, "store.books", {flatten: true, wrap: false});
+        var result = JSONPath({json: json, path: 'store.books', flatten: true, wrap: false});
         test.deepEqual(expected, result);
         test.done();
     }
diff --git a/test/test.at_and_dollar.js b/test/test.at_and_dollar.js
index e99d7dbf6d6770ab57a257f75c5372bed5c547cb..9c0eb42fae2f08aac4ed16e0d93cf20f2d253ef6 100644
--- a/test/test.at_and_dollar.js
+++ b/test/test.at_and_dollar.js
@@ -1,5 +1,5 @@
-var jsonpath = require("../").eval
-  , testCase = require('nodeunit').testCase
+var JSONPath = require('../'),
+    testCase = require('nodeunit').testCase
 
 
 var t1 = {
@@ -22,29 +22,29 @@ module.exports = testCase({
     
 
     // ============================================================================    
-    "test undefined, null": function(test) {
+    'test undefined, null': function(test) {
     // ============================================================================    
         test.expect(5);
-        test.equal(undefined, jsonpath(undefined, "foo"));
-        test.equal(null, jsonpath(null, "foo"));
-        test.equal(undefined, jsonpath({}, "foo")[0]);
-        test.equal(undefined, jsonpath({ a: "b" }, "foo")[0]);
-        test.equal(undefined, jsonpath({ a: "b" }, "foo")[100]);
+        test.equal(undefined, JSONPath({json: undefined, path: 'foo'}));
+        test.equal(null, JSONPath({json: null, path: 'foo'}));
+        test.equal(undefined, JSONPath({json: {}, path: 'foo'})[0]);
+        test.equal(undefined, JSONPath({json: { a: 'b' }, path: 'foo'})[0]);
+        test.equal(undefined, JSONPath({json: { a: 'b' }, path: 'foo'})[100]);
         test.done();
     },
 
     
     // ============================================================================    
-    "test $ and @": function(test) {
+    'test $ and @': function(test) {
     // ============================================================================    
         test.expect(7);
-        test.equal(t1["$"],   jsonpath(t1, "\$")[0]);
-        test.equal(t1["$"],   jsonpath(t1, "$")[0]);
-        test.equal(t1["a$a"], jsonpath(t1, "a$a")[0]);
-        test.equal(t1["@"],   jsonpath(t1, "\@")[0]);
-        test.equal(t1["@"],   jsonpath(t1, "@")[0]);
-        test.equal(t1["$"]["@"], jsonpath(t1, "$.$.@")[0]);
-        test.equal(undefined, jsonpath(t1, "\@")[1]);
+        test.equal(t1['$'],   JSONPath({json: t1, path: '\$'})[0]);
+        test.equal(t1['$'],   JSONPath({json: t1, path: '$'})[0]);
+        test.equal(t1['a$a'], JSONPath({json: t1, path: 'a$a'})[0]);
+        test.equal(t1['@'],   JSONPath({json: t1, path: '\@'})[0]);
+        test.equal(t1['@'],   JSONPath({json: t1, path: '@'})[0]);
+        test.equal(t1['$']['@'], JSONPath({json: t1, path: '$.$.@'})[0]);
+        test.equal(undefined, JSONPath({json: t1, path: '\@'})[1]);
         
         test.done();
     }
diff --git a/test/test.eval.js b/test/test.eval.js
index 8da68e90879e4bc7af97071482a150c92c893a4e..98b3459844f5f7cba4e4d633d38ff6b0f7e43eea 100644
--- a/test/test.eval.js
+++ b/test/test.eval.js
@@ -1,4 +1,4 @@
-var jsonpath = require("../").eval,
+var JSONPath = require('../'),
     testCase = require('nodeunit').testCase
 
 var json = {
@@ -26,19 +26,19 @@ var json = {
 
 
 module.exports = testCase({
-    "multi statement eval": function (test) {
+    'multi statement eval': function (test) {
         var expected = json.store.books[0];
-        var selector = "$..[?("
-                     + "var sum = @.price && @.price[0]+@.price[1];"
-                     + "sum > 20;)]"
-        var result = jsonpath(json, selector, {wrap: false});
+        var selector = '$..[?('
+                     + 'var sum = @.price && @.price[0]+@.price[1];'
+                     + 'sum > 20;)]'
+        var result = JSONPath({json: json, path: selector, wrap: false});
         test.deepEqual(expected, result);
         test.done();
     },
 
-    "accessing current path": function (test) {
+    'accessing current path': function (test) {
         var expected = json.store.books[1];
-        var result = jsonpath(json, "$..[?(@path==\"$['store']['books'][1]\")]", {wrap: false});
+        var result = JSONPath({json: json, path: "$..[?(@path==\"$['store']['books'][1]\")]", wrap: false});
         test.deepEqual(expected, result);
         test.done();
     }
diff --git a/test/test.examples.js b/test/test.examples.js
index 053272568478962fde72051223f76427f7679b56..a28e3bbfa2b9d121d521151f70db5847b79c2060 100644
--- a/test/test.examples.js
+++ b/test/test.examples.js
@@ -1,10 +1,10 @@
-var jsonpath = require("../").eval
-  , testCase = require('nodeunit').testCase
+var JSONPath = require('../'),
+    testCase = require('nodeunit').testCase
 
 // tests based on examples at http://goessner.net/articles/JsonPath/
 
 var json = {"store": {
-    "book": [ 
+    "book": [
       { "category": "reference",
         "author": "Nigel Rees",
         "title": "Sayings of the Century",
@@ -37,123 +37,123 @@ var json = {"store": {
 
 
 module.exports = testCase({
-    
-    // ============================================================================    
-    "wildcards": function(test) {
-    // ============================================================================    
+
+    // ============================================================================
+    'wildcards': function(test) {
+    // ============================================================================
         test.expect(1);
         var books = json.store.book;
         var expected = [books[0].author, books[1].author, books[2].author, books[3].author];
-        var result = jsonpath(json, "$.store.book[*].author");
+        var result = JSONPath({json: json, path: '$.store.book[*].author'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
-    
-    // ============================================================================    
-    "all properties, entire tree": function(test) {
-    // ============================================================================    
+
+    // ============================================================================
+    'all properties, entire tree': function(test) {
+    // ============================================================================
         test.expect(1);
         var books = json.store.book;
         var expected = [books[0].author, books[1].author, books[2].author, books[3].author];
-        var result = jsonpath(json, "$..author");
+        var result = JSONPath({json: json, path: '$..author'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
-    
-    // ============================================================================    
-    "all sub properties, single level": function(test) {
-    // ============================================================================    
+
+    // ============================================================================
+    'all sub properties, single level': function(test) {
+    // ============================================================================
         test.expect(1);
         var expected = [json.store.book, json.store.bicycle];
-        var result = jsonpath(json, "$.store.*");
+        var result = JSONPath({json: json, path: '$.store.*'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
 
-    // ============================================================================    
-    "all sub properties, entire tree": function(test) {
-    // ============================================================================    
+    // ============================================================================
+    'all sub properties, entire tree': function(test) {
+    // ============================================================================
         test.expect(1);
         var books = json.store.book;
         var expected = [books[0].price, books[1].price, books[2].price, books[3].price, json.store.bicycle.price];
-        var result = jsonpath(json, "$.store..price");
+        var result = JSONPath({json: json, path: '$.store..price'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
-    
-    // ============================================================================    
-    "n property of entire tree": function(test) {
-    // ============================================================================    
+
+    // ============================================================================
+    'n property of entire tree': function(test) {
+    // ============================================================================
         test.expect(1);
         var books = json.store.book;
         var expected = [books[2]];
-        var result = jsonpath(json, "$..book[2]");
+        var result = JSONPath({json: json, path: '$..book[2]'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
 
-    // ============================================================================    
-    "last property of entire tree": function(test) {
-    // ============================================================================    
+    // ============================================================================
+    'last property of entire tree': function(test) {
+    // ============================================================================
         test.expect(2);
         var books = json.store.book;
         var expected = [books[3]];
-        var result = jsonpath(json, "$..book[(@.length-1)]");
+        var result = JSONPath({json: json, path: '$..book[(@.length-1)]'});
         test.deepEqual(expected, result);
-        
-        result = jsonpath(json, "$..book[-1:]"); 
+
+        result = JSONPath({json: json, path: '$..book[-1:]'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
-    
-    // ============================================================================    
-    "range of property of entire tree": function(test) {
-    // ============================================================================    
+
+    // ============================================================================
+    'range of property of entire tree': function(test) {
+    // ============================================================================
         test.expect(2);
         var books = json.store.book;
         var expected = [books[0], books[1]];
-        var result = jsonpath(json, "$..book[0,1]"); 
+        var result = JSONPath({json: json, path: '$..book[0,1]'});
         test.deepEqual(expected, result);
-        
-        result = jsonpath(json, "$..book[:2]"); 
+
+        result = JSONPath({json: json, path: '$..book[:2]'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
-    
-    // ============================================================================    
-    "filter all properties if sub property exists,o entire tree": function(test) {
-    // ============================================================================    
+
+    // ============================================================================
+    'filter all properties if sub property exists, of entire tree': function(test) {
+    // ============================================================================
         test.expect(1);
         var books = json.store.book;
         var expected = [books[2], books[3]];
-        var result = jsonpath(json, "$..book[?(@.isbn)]"); 
+        var result = JSONPath({json: json, path: '$..book[?(@.isbn)]'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
-    
-    // ============================================================================    
-    "filter all properties if sub property greater than of entire tree": function(test) {
-    // ============================================================================    
+
+    // ============================================================================
+    'filter all properties if sub property greater than of entire tree': function(test) {
+    // ============================================================================
         test.expect(1);
         var books = json.store.book;
         var expected = [books[0], books[2]];
-        var result = jsonpath(json, "$..book[?(@.price<10)]"); 
+        var result = JSONPath({json: json, path: '$..book[?(@.price<10)]'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     },
-    
-    // ============================================================================    
-    "all properties of a json structure": function(test) {
-    // ============================================================================    
+
+    // ============================================================================
+    'all properties of a JSON structure': function(test) {
+    // ============================================================================
         // test.expect(1);
         var expected = [
           json.store,
@@ -165,13 +165,13 @@ module.exports = testCase({
         expected.push(json.store.bicycle.color);
         expected.push(json.store.bicycle.price);
 
-        var result = jsonpath(json, "$..*"); 
+        var result = JSONPath({json: json, path: '$..*'});
         test.deepEqual(expected, result);
-        
+
         test.done();
     }
-    
-    
-    
-        
+
+
+
+
 });
diff --git a/test/test.html b/test/test.html
index f9089200ec6bbf50c22ac689dfe634e0c1ef226a..505fd4f35ac098851b9248889680e1eb771cba24 100644
--- a/test/test.html
+++ b/test/test.html
@@ -7,54 +7,61 @@
         <script src="../node_modules/nodeunit/dist/browser/nodeunit.js"></script>
         <script src="../lib/jsonpath.js"></script>
         <script>
+            /*jslint nomen: true, white: true, browser:true, plusplus: true, evil:true*/
+            /*global nodeunit, JSONPath, ActiveXObject*/
             // helper to get all the test cases
+            'use strict';
             var suites = [], _testCase = nodeunit.testCase;
             nodeunit.testCase = function(tc) {
-                suites.push(tc); return _testCase(tc) };
+                suites.push(tc);
+                return _testCase(tc);
+            };
             // stubs to load nodejs tests
             function require(path) {
-                if (path === 'nodeunit') return nodeunit;
-                if (path.match(/^\.\.\/?$/)) return jsonPath;
+                if (path === 'nodeunit') {return nodeunit;}
+                if (path.match(/^\.\.\/?$/)) {return JSONPath;}
             }
             var module = {exports: {}};
-        </script>
-        <script>
+
+
             // synchronous load function for JS code, uses XMLHttpRequest abstraction from
             // http://www.quirksmode.org/js/xmlhttp.html
             // Since the tests are written in node.js style we need to wrap their code into
             // a function, otherwise they would pollute the global NS and interfere with each
             // other
             function get(url, callback) {
-                function sendRequest(url,callback) {
-                	var req = createXMLHTTPObject();
-                	req.open("GET",url,false/*sync*/);
-                	req.onreadystatechange = function () { req.readyState == 4 && callback(req); }
-                	if (req.readyState != 4) req.send();
-                };
                 function createXMLHTTPObject() {
-                    var XMLHttpFactories = [
-                    	function () {return new XMLHttpRequest()},
-                    	function () {return new ActiveXObject("Msxml2.XMLHTTP")},
-                    	function () {return new ActiveXObject("Msxml3.XMLHTTP")},
-                    	function () {return new ActiveXObject("Microsoft.XMLHTTP")}];
-                	for (var i=0;i<XMLHttpFactories.length;i++)
-                		try { return XMLHttpFactories[i](); } catch (e) { }
+                    var i, XMLHttpFactories = [
+                    	function () {return new XMLHttpRequest();},
+                    	function () {return new ActiveXObject('Msxml2.XMLHTTP');},
+                    	function () {return new ActiveXObject('Msxml3.XMLHTTP');},
+                    	function () {return new ActiveXObject('Microsoft.XMLHTTP');}];
+                	for (i = 0; i < XMLHttpFactories.length; i++) {
+                		try {return XMLHttpFactories[i]();}
+                        catch (ignore) {}
+                    }
                 	return false;
                 }
+                function sendRequest(url,callback) {
+                	var req = createXMLHTTPObject();
+                	req.open('GET', url, false /*sync*/);
+                	req.onreadystatechange = function () { if (req.readyState === 4) { callback(req); } };
+                	if (req.readyState !== 4) {req.send();}
+                }
                 sendRequest(url, callback);
             }
-            function loadJS(url) { get(url, function(req) { new Function(req.responseText)(); })}
+            function loadJS(url) { get(url, function(req) { new Function(req.responseText)(); });}
         </script>
     </head>
     <body>
         <h1 id="nodeunit-header">JSONPath Tests</h1>
         <script>
             loadJS('test.arr.js');
-            loadJS("test.at_and_dollar.js");
-            loadJS("test.eval.js");
-            loadJS("test.examples.js");
-            loadJS("test.intermixed.arr.js");
-            loadJS("test.parent-selector.js");
+            loadJS('test.at_and_dollar.js');
+            loadJS('test.eval.js');
+            loadJS('test.examples.js');
+            loadJS('test.intermixed.arr.js');
+            loadJS('test.parent-selector.js');
             nodeunit.run(suites);
         </script>
     </body>
diff --git a/test/test.intermixed.arr.js b/test/test.intermixed.arr.js
index 1cf622d5d798fb538c2a7164e03b460f2be06c45..7a9eaa035da20429f0c38a88bd63d424110fe19a 100644
--- a/test/test.intermixed.arr.js
+++ b/test/test.intermixed.arr.js
@@ -1,4 +1,4 @@
-var jsonpath = require("../").eval,
+var JSONPath = require('../'),
     testCase = require('nodeunit').testCase
 
 // tests based on examples at http://goessner.net/articles/JsonPath/
@@ -39,13 +39,13 @@ var json = {"store":{
 module.exports = testCase({
 
     // ============================================================================
-    "all sub properties, entire tree":function (test) {
+    'all sub properties, entire tree': function (test) {
         // ============================================================================
         test.expect(1);
         var books = json.store.book;
         var expected = [books[1].price, books[2].price, books[3].price, json.store.bicycle.price];
         expected = books[0].price.concat(expected);
-        var result = jsonpath(json, "$.store..price", {flatten: true});
+        var result = JSONPath({json: json, path: '$.store..price', flatten: true});
         test.deepEqual(expected, result);
 
         test.done();
diff --git a/test/test.parent-selector.js b/test/test.parent-selector.js
index 678c9e3f883b8a5d19d3cd1e206d2fe42d9ae34f..6f9c422495554c96ca6643a37ccec5ce7d4c9514 100644
--- a/test/test.parent-selector.js
+++ b/test/test.parent-selector.js
@@ -1,4 +1,4 @@
-var jsonpath = require("../").eval,
+var JSONPath = require('../'),
     testCase = require('nodeunit').testCase
 
 var json = {
@@ -14,49 +14,49 @@ var json = {
 module.exports = testCase({
 
     // ============================================================================
-    "simple parent selection": function(test) {
+    'simple parent selection': function(test) {
     // ============================================================================
         test.expect(1);
-        var result = jsonpath(json, "$.children[0]^", {flatten: true});
+        var result = JSONPath({json: json, path: '$.children[0]^', flatten: true});
         test.deepEqual(json.children, result);
         test.done();
     },
 
     // ============================================================================
-    "parent selection with multiple matches": function(test) {
+    'parent selection with multiple matches': function(test) {
     // ============================================================================
         test.expect(1);
         var expected = [json.children,json.children];
-        var result = jsonpath(json, "$.children[1:3]^");
+        var result = JSONPath({json: json, path: '$.children[1:3]^'});
         test.deepEqual(expected, result);
         test.done();
     },
 
     // ============================================================================
-    "select sibling via parent": function(test) {
+    'select sibling via parent': function(test) {
     // ============================================================================
         test.expect(1);
         var expected = [{"name": "child3_2"}];
-        var result = jsonpath(json, "$..[?(@.name && @.name.match(/3_1$/))]^[?(@.name.match(/_2$/))]");
+        var result = JSONPath({json: json, path: '$..[?(@.name && @.name.match(/3_1$/))]^[?(@.name.match(/_2$/))]'});
         test.deepEqual(expected, result);
         test.done();
     },
 
     // ============================================================================
-    "parent parent parent": function(test) {
+    'parent parent parent': function(test) {
     // ============================================================================
         test.expect(1);
         var expected = json.children[0].children;
-        var result = jsonpath(json, "$..[?(@.name && @.name.match(/1_1$/))].name^^", {flatten: true});
+        var result = JSONPath({json: json, path: '$..[?(@.name && @.name.match(/1_1$/))].name^^', flatten: true});
         test.deepEqual(expected, result);
         test.done();
     },
 
     // ============================================================================
-    "no such parent": function(test) {
+    'no such parent': function(test) {
     // ============================================================================
         test.expect(1);
-        var result = jsonpath(json, "name^^");
+        var result = JSONPath({json: json, path: 'name^^'});
         test.deepEqual([], result);
         test.done();
     }