Browse Source

Fixes issue #792

- Moves comparison methods to ProtoObject
- Adds `#=` to JSObjectProxy
- Adds comparison tests to JSObjectProxyTest
Nicolas Petton 10 years ago
parent
commit
be47f76ad9
6 changed files with 179 additions and 93 deletions
  1. 40 0
      js/Kernel-Infrastructure.js
  2. 75 75
      js/Kernel-Objects.js
  3. 26 0
      js/Kernel-Tests.js
  4. 13 0
      st/Kernel-Infrastructure.st
  5. 18 18
      st/Kernel-Objects.st
  6. 7 0
      st/Kernel-Tests.st

+ 40 - 0
js/Kernel-Infrastructure.js

@@ -800,6 +800,30 @@ smalltalk.Environment);
 
 smalltalk.addClass('JSObjectProxy', smalltalk.ProtoObject, ['jsObject'], 'Kernel-Infrastructure');
 smalltalk.JSObjectProxy.comment="I handle sending messages to JavaScript objects, making  JavaScript object accessing from Amber fully transparent.\x0aMy instances make intensive use of `#doesNotUnderstand:`.\x0a\x0aMy instances are automatically created by Amber whenever a message is sent to a JavaScript object.\x0a\x0a## Usage examples\x0a\x0aJSObjectProxy objects are instanciated by Amber when a Smalltalk message is sent to a JavaScript object.\x0a\x0a\x09window alert: 'hello world'.\x0a\x09window inspect.\x0a\x09(window jQuery: 'body') append: 'hello world'\x0a\x0aAmber messages sends are converted to JavaScript function calls or object property access _(in this order)_. If n one of them match, a `MessageNotUnderstood` error will be thrown.\x0a\x0a## Message conversion rules\x0a\x0a- `someUser name` becomes `someUser.name`\x0a- `someUser name: 'John'` becomes `someUser name = \x22John\x22`\x0a- `console log: 'hello world'` becomes `console.log('hello world')`\x0a- `(window jQuery: 'foo') css: 'background' color: 'red'` becomes `window.jQuery('foo').css('background', 'red')`\x0a\x0a__Note:__ For keyword-based messages, only the first keyword is kept: `window foo: 1 bar: 2` is equivalent to `window foo: 1 baz: 2`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "=",
+protocol: 'comparing',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3;
+$2=_st(anObject)._class();
+$ctx1.sendIdx["class"]=1;
+$1=_st($2).__eq_eq(self._class());
+if(! smalltalk.assert($1)){
+return false;
+};
+$3=self._compareJSObjectWith_(_st(anObject)._jsObject());
+return $3;
+}, function($ctx1) {$ctx1.fill(self,"=",{anObject:anObject},smalltalk.JSObjectProxy)})},
+args: ["anObject"],
+source: "= anObject\x0a\x09anObject class == self class ifFalse: [ ^ false ].\x0a\x09^ self compareJSObjectWith: anObject jsObject",
+messageSends: ["ifFalse:", "==", "class", "compareJSObjectWith:", "jsObject"],
+referencedClasses: []
+}),
+smalltalk.JSObjectProxy);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "addObjectVariablesTo:",
@@ -927,6 +951,22 @@ referencedClasses: []
 }),
 smalltalk.JSObjectProxy);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "compareJSObjectWith:",
+protocol: 'private',
+fn: function (aJSObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self["@jsObject"] === aJSObject;
+return self}, function($ctx1) {$ctx1.fill(self,"compareJSObjectWith:",{aJSObject:aJSObject},smalltalk.JSObjectProxy)})},
+args: ["aJSObject"],
+source: " compareJSObjectWith: aJSObject\x0a \x09<return self[\x22@jsObject\x22] === aJSObject>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.JSObjectProxy);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "doesNotUnderstand:",

+ 75 - 75
js/Kernel-Objects.js

@@ -4,6 +4,44 @@ smalltalk.packages["Kernel-Objects"].transport = {"type":"amd","amdNamespace":"a
 
 smalltalk.addClass('ProtoObject', smalltalk.nil, [], 'Kernel-Objects');
 smalltalk.ProtoObject.comment="I implement the basic behavior required for any object in Amber.\x0a\x0aIn most cases, subclassing `ProtoObject` is wrong and `Object` should be used instead. However subclassing `ProtoObject` can be useful in some special cases like proxy implementations. ";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "=",
+protocol: 'comparing',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self.__eq_eq(anObject);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"=",{anObject:anObject},smalltalk.ProtoObject)})},
+args: ["anObject"],
+source: "= anObject\x0a\x09^ self == anObject",
+messageSends: ["=="],
+referencedClasses: []
+}),
+smalltalk.ProtoObject);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "==",
+protocol: 'comparing',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self._identityHash();
+$ctx1.sendIdx["identityHash"]=1;
+$1=_st($2).__eq(_st(anObject)._identityHash());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"==",{anObject:anObject},smalltalk.ProtoObject)})},
+args: ["anObject"],
+source: "== anObject\x0a\x09^ self identityHash = anObject identityHash",
+messageSends: ["=", "identityHash"],
+referencedClasses: []
+}),
+smalltalk.ProtoObject);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asString",
@@ -262,6 +300,43 @@ referencedClasses: []
 }),
 smalltalk.ProtoObject);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "~=",
+protocol: 'comparing',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self.__eq(anObject)).__eq(false);
+$ctx1.sendIdx["="]=1;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"~=",{anObject:anObject},smalltalk.ProtoObject)})},
+args: ["anObject"],
+source: "~= anObject\x0a\x09^ (self = anObject) = false",
+messageSends: ["="],
+referencedClasses: []
+}),
+smalltalk.ProtoObject);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "~~",
+protocol: 'comparing',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self.__eq_eq(anObject)).__eq(false);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"~~",{anObject:anObject},smalltalk.ProtoObject)})},
+args: ["anObject"],
+source: "~~ anObject\x0a\x09^ (self == anObject) = false",
+messageSends: ["=", "=="],
+referencedClasses: []
+}),
+smalltalk.ProtoObject);
+
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -316,44 +391,6 @@ referencedClasses: ["Association"]
 }),
 smalltalk.Object);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "=",
-protocol: 'comparing',
-fn: function (anObject){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self.__eq_eq(anObject);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"=",{anObject:anObject},smalltalk.Object)})},
-args: ["anObject"],
-source: "= anObject\x0a\x09^ self == anObject",
-messageSends: ["=="],
-referencedClasses: []
-}),
-smalltalk.Object);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "==",
-protocol: 'comparing',
-fn: function (anObject){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self._identityHash();
-$ctx1.sendIdx["identityHash"]=1;
-$1=_st($2).__eq(_st(anObject)._identityHash());
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"==",{anObject:anObject},smalltalk.Object)})},
-args: ["anObject"],
-source: "== anObject\x0a\x09^ self identityHash = anObject identityHash",
-messageSends: ["=", "identityHash"],
-referencedClasses: []
-}),
-smalltalk.Object);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asJSON",
@@ -1120,43 +1157,6 @@ referencedClasses: []
 }),
 smalltalk.Object);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "~=",
-protocol: 'comparing',
-fn: function (anObject){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(self.__eq(anObject)).__eq(false);
-$ctx1.sendIdx["="]=1;
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"~=",{anObject:anObject},smalltalk.Object)})},
-args: ["anObject"],
-source: "~= anObject\x0a\x09^ (self = anObject) = false",
-messageSends: ["="],
-referencedClasses: []
-}),
-smalltalk.Object);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "~~",
-protocol: 'comparing',
-fn: function (anObject){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(self.__eq_eq(anObject)).__eq(false);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"~~",{anObject:anObject},smalltalk.Object)})},
-args: ["anObject"],
-source: "~~ anObject\x0a\x09^ (self == anObject) = false",
-messageSends: ["=", "=="],
-referencedClasses: []
-}),
-smalltalk.Object);
-
 
 smalltalk.addMethod(
 smalltalk.method({

+ 26 - 0
js/Kernel-Tests.js

@@ -6017,6 +6017,32 @@ referencedClasses: []
 }),
 smalltalk.JSObjectProxyTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testComparison",
+protocol: 'tests',
+fn: function (){
+var self=this;
+function $Object(){return smalltalk.Object||(typeof Object=="undefined"?nil:Object)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+self._assert_equals_(_st([console,(2)])._indexOf_(console),(1));
+$1=_st(console).__eq(console);
+$ctx1.sendIdx["="]=1;
+self._assert_($1);
+$2=_st(console).__eq(_st($Object())._new());
+$ctx1.sendIdx["="]=2;
+self._deny_($2);
+$ctx1.sendIdx["deny:"]=1;
+self._deny_(_st(console).__eq(self._jsObject()));
+return self}, function($ctx1) {$ctx1.fill(self,"testComparison",{},smalltalk.JSObjectProxyTest)})},
+args: [],
+source: "testComparison\x0a\x09self assert: ({ console. 2 } indexOf: console) equals: 1.\x0a\x09self assert: console = console.\x0a\x09self deny: console = Object new.\x0a\x09self deny: console = self jsObject",
+messageSends: ["assert:equals:", "indexOf:", "assert:", "=", "deny:", "new", "jsObject"],
+referencedClasses: ["Object"]
+}),
+smalltalk.JSObjectProxyTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testDNU",

+ 13 - 0
st/Kernel-Infrastructure.st

@@ -326,6 +326,13 @@ lookupProperty: aString
 	<return aString in self._jsObject() ? aString : nil>
 ! !
 
+!JSObjectProxy methodsFor: 'comparing'!
+
+= anObject
+	anObject class == self class ifFalse: [ ^ false ].
+	^ self compareJSObjectWith: anObject jsObject
+! !
+
 !JSObjectProxy methodsFor: 'enumerating'!
 
 asJSON
@@ -358,6 +365,12 @@ printString
 	>
 ! !
 
+!JSObjectProxy methodsFor: 'private'!
+
+compareJSObjectWith: aJSObject
+ 	<return self["@jsObject"] === aJSObject>
+! !
+
 !JSObjectProxy methodsFor: 'proxy'!
 
 addObjectVariablesTo: aDictionary

+ 18 - 18
st/Kernel-Objects.st

@@ -35,6 +35,24 @@ yourself
 	^ self
 ! !
 
+!ProtoObject methodsFor: 'comparing'!
+
+= anObject
+	^ self == anObject
+!
+
+== anObject
+	^ self identityHash = anObject identityHash
+!
+
+~= anObject
+	^ (self = anObject) = false
+!
+
+~~ anObject
+	^ (self == anObject) = false
+! !
+
 !ProtoObject methodsFor: 'converting'!
 
 asString
@@ -164,24 +182,6 @@ value
 	<return self.valueOf()>
 ! !
 
-!Object methodsFor: 'comparing'!
-
-= anObject
-	^ self == anObject
-!
-
-== anObject
-	^ self identityHash = anObject identityHash
-!
-
-~= anObject
-	^ (self = anObject) = false
-!
-
-~~ anObject
-	^ (self == anObject) = false
-! !
-
 !Object methodsFor: 'converting'!
 
 -> anObject

+ 7 - 0
st/Kernel-Tests.st

@@ -1687,6 +1687,13 @@ testAtPut
 	self assert: (testObject at: 'abc') equals: 'xyz'
 !
 
+testComparison
+	self assert: ({ console. 2 } indexOf: console) equals: 1.
+	self assert: console = console.
+	self deny: console = Object new.
+	self deny: console = self jsObject
+!
+
 testDNU
 	self should: [ self jsObject foo ] raise: MessageNotUnderstood
 !