[UP] py.js, old != operator and basic dict handling
bzr revid: xmo@openerp.com-20120806110638-1m4rg205sb3vjvm5
This commit is contained in:
parent
6f4abdfbd5
commit
6a23c24da1
|
@ -1,5 +1,5 @@
|
|||
repo: 076b192d0d8ab2b92d1dbcfa3da055382f30eaea
|
||||
node: 1758bfec1ec1dcff95dcc4c72269cc0e3d000afd
|
||||
node: 87e977311edbbb5f281b87390a9a304eb194ce89
|
||||
branch: default
|
||||
latesttag: 0.5
|
||||
latesttagdistance: 11
|
||||
latesttagdistance: 15
|
||||
|
|
|
@ -60,7 +60,7 @@ Builtins
|
|||
Same as tuple (``list`` is currently an alias for ``tuple``)
|
||||
|
||||
``dict``
|
||||
Implements just about nothing
|
||||
Implements trivial getting and setting, nothing beyond that.
|
||||
|
||||
Note that most methods are probably missing from all of these.
|
||||
|
||||
|
@ -72,14 +72,14 @@ sub-protocols) of the `Python 2.7 data model
|
|||
<http://docs.python.org/reference/datamodel.html>`_:
|
||||
|
||||
Rich comparisons
|
||||
Roughly complete implementation but for two limits: ``__eq__`` and
|
||||
``__ne__`` can't return ``NotImplemented`` (well they can but it's
|
||||
not going to work right), and the behavior is undefined if a
|
||||
rich-comparison operation does not return a ``py.bool``.
|
||||
Pretty much complete (including operator fallbacks), although the
|
||||
behavior is currently undefined if an operation does not return
|
||||
either a ``py.bool`` or ``NotImplemented``.
|
||||
|
||||
Also, a ``NotImplemented`` result does not try the reverse
|
||||
operation, not sure if it's supposed to. It directly falls back to
|
||||
comparing type names.
|
||||
``__hash__`` is supported (and used), but it should return **a
|
||||
javascript string**. ``py.js``'s dict build on javascript objects,
|
||||
reimplementing numeral hashing is worthless complexity at this
|
||||
point.
|
||||
|
||||
Boolean conversion
|
||||
Implementing ``__nonzero__`` should work.
|
||||
|
@ -93,6 +93,12 @@ Descriptor protocol
|
|||
As with attributes, ``__delete__`` is not implemented.
|
||||
|
||||
Callable objects
|
||||
Work, although the handling of arguments isn't exactly nailed
|
||||
down. For now, callables get two (javascript) arguments ``args``
|
||||
and ``kwargs``, holding (respectively) positional and keyword
|
||||
arguments.
|
||||
|
||||
Conflicts are *not* handled at this point.
|
||||
|
||||
Collections Abstract Base Classes
|
||||
Container is the only implemented ABC protocol (ABCs themselves
|
||||
|
@ -119,8 +125,8 @@ implementation:
|
|||
``py.js`` types.
|
||||
|
||||
When accessing instance methods, ``py.js`` automatically wraps
|
||||
these in a variant of ``py.def`` automatically, to behave as
|
||||
Python's (bound) methods.
|
||||
these in a variant of ``py.def``, to behave as Python's (bound)
|
||||
methods.
|
||||
|
||||
Why
|
||||
===
|
||||
|
|
|
@ -433,7 +433,8 @@ var py = {};
|
|||
if (this._hash) {
|
||||
return this._hash;
|
||||
}
|
||||
return this._hash = hash_counter++;
|
||||
// tagged counter, to avoid collisions with e.g. number hashes
|
||||
return this._hash = '\0\0\0' + String(hash_counter++);
|
||||
},
|
||||
__eq__: function (other) {
|
||||
return (this === other) ? py.True : py.False;
|
||||
|
@ -597,6 +598,9 @@ var py = {};
|
|||
throw new Error('TypeError: __str__ returned non-string (type ' +
|
||||
v.constructor.name + ')');
|
||||
}, py.object, {
|
||||
__hash__: function () {
|
||||
return '\1\0\1' + this._value;
|
||||
},
|
||||
__eq__: function (other) {
|
||||
if (other instanceof py.str && this._value === other._value) {
|
||||
return py.True;
|
||||
|
@ -654,12 +658,33 @@ var py = {};
|
|||
}
|
||||
});
|
||||
py.list = py.tuple;
|
||||
py.dict = py.type(function dict() {
|
||||
py.dict = py.type(function dict(d) {
|
||||
this._store = {};
|
||||
for (var k in (d || {})) {
|
||||
if (!d.hasOwnProperty(k)) { continue; }
|
||||
var py_k = new py.str(k);
|
||||
var val = PY_ensurepy(d[k]);
|
||||
this._store[py_k.__hash__()] = [py_k, val];
|
||||
}
|
||||
}, py.object, {
|
||||
__getitem__: function (key) {
|
||||
var h = key.__hash__();
|
||||
if (!(h in this._store)) {
|
||||
throw new Error("KeyError: '" + key.toJSON() + "'");
|
||||
}
|
||||
return this._store[h][1];
|
||||
},
|
||||
__setitem__: function (key, value) {
|
||||
this._store[key.__hash__()] = [key, value];
|
||||
},
|
||||
get: function (args) {
|
||||
var h = args[0].__hash__();
|
||||
var def = args.length > 1 ? args[1] : py.None;
|
||||
if (!(h in this._store)) {
|
||||
return def;
|
||||
}
|
||||
return this._store[h][1];
|
||||
},
|
||||
toJSON: function () {
|
||||
var out = {};
|
||||
for(var k in this._store) {
|
||||
|
@ -700,6 +725,7 @@ var py = {};
|
|||
var PY_operators = {
|
||||
'==': ['eq', 'eq', function (a, b) { return a === b; }],
|
||||
'!=': ['ne', 'ne', function (a, b) { return a !== b; }],
|
||||
'<>': ['ne', 'ne', function (a, b) { return a !== b; }],
|
||||
'<': ['lt', 'gt', function (a, b) {return a.constructor.name < b.constructor.name;}],
|
||||
'<=': ['le', 'ge', function (a, b) {return a.constructor.name <= b.constructor.name;}],
|
||||
'>': ['gt', 'lt', function (a, b) {return a.constructor.name > b.constructor.name;}],
|
||||
|
@ -782,7 +808,7 @@ var py = {};
|
|||
return b.__contains__(a);
|
||||
case 'not in':
|
||||
return b.__contains__(a) === py.True ? py.False : py.True;
|
||||
case '==': case '!=':
|
||||
case '==': case '!=': case '<>':
|
||||
case '<': case '<=':
|
||||
case '>': case '>=':
|
||||
return PY_op(a, b, operator);
|
||||
|
|
|
@ -117,6 +117,11 @@ describe('Comparisons', function () {
|
|||
expect(py.eval('foo != bar', {foo: 'qux', bar: 'quux'}))
|
||||
.to.be(true);
|
||||
});
|
||||
it('should accept deprecated form', function () {
|
||||
expect(py.eval('1 <> 2')).to.be(true);
|
||||
expect(py.eval('"foo" <> "foo"')).to.be(false);
|
||||
expect(py.eval('"foo" <> "bar"')).to.be(true);
|
||||
});
|
||||
});
|
||||
describe('rich comparisons', function () {
|
||||
it('should work with numbers', function () {
|
||||
|
@ -377,6 +382,29 @@ describe('numerical protocols', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('dicts', function () {
|
||||
it('should be possible to retrieve their value', function () {
|
||||
var d = new py.dict({foo: 3, bar: 4, baz: 5});
|
||||
expect(py.eval('d["foo"]', {d: d})).to.be(3);
|
||||
expect(py.eval('d["baz"]', {d: d})).to.be(5);
|
||||
});
|
||||
it('should raise KeyError if a key is missing', function () {
|
||||
var d = new py.dict();
|
||||
expect(function () {
|
||||
py.eval('d["foo"]', {d: d});
|
||||
}).to.throwException(/^KeyError/);
|
||||
});
|
||||
it('should have a method to provide a default value', function () {
|
||||
var d = new py.dict({foo: 3});
|
||||
expect(py.eval('d.get("foo")', {d: d})).to.be(3);
|
||||
expect(py.eval('d.get("bar")', {d: d})).to.be(null);
|
||||
expect(py.eval('d.get("bar", 42)', {d: d})).to.be(42);
|
||||
|
||||
var e = new py.dict({foo: null});
|
||||
expect(py.eval('d.get("foo")', {d: e})).to.be(null);
|
||||
expect(py.eval('d.get("bar")', {d: e})).to.be(null);
|
||||
});
|
||||
});
|
||||
describe('Type converter', function () {
|
||||
it('should convert bare objects to objects', function () {
|
||||
expect(py.eval('foo.bar', {foo: {bar: 3}})).to.be(3);
|
||||
|
|
Loading…
Reference in New Issue