Przeglądaj źródła

- Fix Object>>try:catch: and BlockClosure>>on:do: to answer the result of the block evaluation
- New methods TestCase>>should: and TestCase>>should:raise
- New tests for String

Nicolas Petton 12 lat temu
rodzic
commit
4ecba95fd9

+ 1 - 12
js/Kernel-Collections.deploy.js

@@ -673,17 +673,6 @@ return self;}
 }),
 smalltalk.String);
 
-smalltalk.addMethod(
-'_at_',
-smalltalk.method({
-selector: 'at:',
-fn: function (anIndex){
-var self=this;
-return self[anIndex - 1];
-return self;}
-}),
-smalltalk.String);
-
 smalltalk.addMethod(
 '_at_put_',
 smalltalk.method({
@@ -701,7 +690,7 @@ smalltalk.method({
 selector: 'at:ifAbsent:',
 fn: function (anIndex, aBlock){
 var self=this;
-(($receiver = smalltalk.send(self, "_at_", [anIndex])) == nil || $receiver == undefined) ? (function(){return aBlock;})() : $receiver;
+return self[anIndex - 1] || aBlock();
 return self;}
 }),
 smalltalk.String);

+ 3 - 19
js/Kernel-Collections.js

@@ -958,22 +958,6 @@ referencedClasses: []
 }),
 smalltalk.String);
 
-smalltalk.addMethod(
-unescape('_at_'),
-smalltalk.method({
-selector: unescape('at%3A'),
-category: 'accessing',
-fn: function (anIndex){
-var self=this;
-return self[anIndex - 1];
-return self;},
-args: ["anIndex"],
-source: unescape('at%3A%20anIndex%0A%09%3Creturn%20self%5BanIndex%20-%201%5D%3E'),
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.String);
-
 smalltalk.addMethod(
 unescape('_at_put_'),
 smalltalk.method({
@@ -997,11 +981,11 @@ selector: unescape('at%3AifAbsent%3A'),
 category: 'accessing',
 fn: function (anIndex, aBlock){
 var self=this;
-(($receiver = smalltalk.send(self, "_at_", [anIndex])) == nil || $receiver == undefined) ? (function(){return aBlock;})() : $receiver;
+return self[anIndex - 1] || aBlock();
 return self;},
 args: ["anIndex", "aBlock"],
-source: unescape('at%3A%20anIndex%20ifAbsent%3A%20aBlock%0A%09%28self%20at%3A%20anIndex%29%20ifNil%3A%20%5BaBlock%5D'),
-messageSends: ["ifNil:", "at:"],
+source: unescape('at%3A%20anIndex%20ifAbsent%3A%20aBlock%0A%09%3Creturn%20self%5BanIndex%20-%201%5D%20%7C%7C%20aBlock%28%29%3E'),
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.String);

+ 1 - 1
js/Kernel-Methods.deploy.js

@@ -229,7 +229,7 @@ smalltalk.method({
 selector: 'on:do:',
 fn: function (anErrorClass, aBlock){
 var self=this;
-smalltalk.send(self, "_try_catch_", [self, (function(error){return ((($receiver = smalltalk.send(error, "_isKindOf_", [anErrorClass])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aBlock, "_value_", [error]);})() : (function(){return smalltalk.send(error, "_signal", []);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(aBlock, "_value_", [error]);}), (function(){return smalltalk.send(error, "_signal", []);})]));})]);
+return smalltalk.send(self, "_try_catch_", [self, (function(error){return ((($receiver = smalltalk.send(error, "_isKindOf_", [anErrorClass])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aBlock, "_value_", [error]);})() : (function(){return smalltalk.send(error, "_signal", []);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(aBlock, "_value_", [error]);}), (function(){return smalltalk.send(error, "_signal", []);})]));})]);
 return self;}
 }),
 smalltalk.BlockClosure);

+ 2 - 2
js/Kernel-Methods.js

@@ -330,10 +330,10 @@ selector: unescape('on%3Ado%3A'),
 category: 'error handling',
 fn: function (anErrorClass, aBlock){
 var self=this;
-smalltalk.send(self, "_try_catch_", [self, (function(error){return ((($receiver = smalltalk.send(error, "_isKindOf_", [anErrorClass])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aBlock, "_value_", [error]);})() : (function(){return smalltalk.send(error, "_signal", []);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(aBlock, "_value_", [error]);}), (function(){return smalltalk.send(error, "_signal", []);})]));})]);
+return smalltalk.send(self, "_try_catch_", [self, (function(error){return ((($receiver = smalltalk.send(error, "_isKindOf_", [anErrorClass])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aBlock, "_value_", [error]);})() : (function(){return smalltalk.send(error, "_signal", []);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(aBlock, "_value_", [error]);}), (function(){return smalltalk.send(error, "_signal", []);})]));})]);
 return self;},
 args: ["anErrorClass", "aBlock"],
-source: unescape('on%3A%20anErrorClass%20do%3A%20aBlock%0A%09self%20try%3A%20self%20catch%3A%20%5B%3Aerror%20%7C%0A%09%20%20%20%20%28error%20isKindOf%3A%20anErrorClass%29%20%0A%09%20%20%20%20%20ifTrue%3A%20%5BaBlock%20value%3A%20error%5D%0A%09%20%20%20%20%20ifFalse%3A%20%5Berror%20signal%5D%5D'),
+source: unescape('on%3A%20anErrorClass%20do%3A%20aBlock%0A%09%5Eself%20try%3A%20self%20catch%3A%20%5B%3Aerror%20%7C%0A%09%20%20%20%20%28error%20isKindOf%3A%20anErrorClass%29%20%0A%09%20%20%20%20%20ifTrue%3A%20%5BaBlock%20value%3A%20error%5D%0A%09%20%20%20%20%20ifFalse%3A%20%5Berror%20signal%5D%5D'),
 messageSends: ["try:catch:", "ifTrue:ifFalse:", "isKindOf:", "value:", "signal"],
 referencedClasses: []
 }),

+ 2 - 1
js/Kernel-Objects.deploy.js

@@ -264,7 +264,8 @@ smalltalk.method({
 selector: 'try:catch:',
 fn: function (aBlock, anotherBlock){
 var self=this;
-try{aBlock()} catch(e) {anotherBlock(e)};
+try{result = aBlock()} catch(e) {result = anotherBlock(e)};
+	return result;;
 return self;}
 }),
 smalltalk.Object);

+ 3 - 2
js/Kernel-Objects.js

@@ -375,10 +375,11 @@ selector: unescape('try%3Acatch%3A'),
 category: 'error handling',
 fn: function (aBlock, anotherBlock){
 var self=this;
-try{aBlock()} catch(e) {anotherBlock(e)};
+try{result = aBlock()} catch(e) {result = anotherBlock(e)};
+	return result;;
 return self;},
 args: ["aBlock", "anotherBlock"],
-source: unescape('try%3A%20aBlock%20catch%3A%20anotherBlock%0A%09%3Ctry%7BaBlock%28%29%7D%20catch%28e%29%20%7BanotherBlock%28e%29%7D%3E'),
+source: unescape('try%3A%20aBlock%20catch%3A%20anotherBlock%0A%09%3Ctry%7Bresult%20%3D%20aBlock%28%29%7D%20catch%28e%29%20%7Bresult%20%3D%20anotherBlock%28e%29%7D%3B%0A%09return%20result%3B%3E'),
 messageSends: [],
 referencedClasses: []
 }),

+ 24 - 0
js/Kernel-Tests.deploy.js

@@ -60,6 +60,30 @@ return self;}
 }),
 smalltalk.StringTest);
 
+smalltalk.addMethod(
+'_testAt',
+smalltalk.method({
+selector: 'testAt',
+fn: function (){
+var self=this;
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send("hello", "_at_", [(1)]), "__eq", ["h"])]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send("hello", "_at_", [(5)]), "__eq", ["o"])]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send("hello", "_at_ifAbsent_", [(6), (function(){return nil;})]), "__eq", [nil])]);
+return self;}
+}),
+smalltalk.StringTest);
+
+smalltalk.addMethod(
+'_testAtPut',
+smalltalk.method({
+selector: 'testAtPut',
+fn: function (){
+var self=this;
+smalltalk.send(self, "_should_raise_", [(function(){return smalltalk.send("hello", "_at_put_", [(1), "a"]);}), (smalltalk.Error || Error)]);
+return self;}
+}),
+smalltalk.StringTest);
+
 
 
 smalltalk.addClass('DictionaryTest', smalltalk.TestCase, [], 'Kernel-Tests');

+ 34 - 0
js/Kernel-Tests.js

@@ -85,6 +85,40 @@ referencedClasses: []
 }),
 smalltalk.StringTest);
 
+smalltalk.addMethod(
+unescape('_testAt'),
+smalltalk.method({
+selector: unescape('testAt'),
+category: 'tests',
+fn: function (){
+var self=this;
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send("hello", "_at_", [(1)]), "__eq", ["h"])]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send("hello", "_at_", [(5)]), "__eq", ["o"])]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send("hello", "_at_ifAbsent_", [(6), (function(){return nil;})]), "__eq", [nil])]);
+return self;},
+args: [],
+source: unescape('testAt%0A%09self%20assert%3A%20%28%27hello%27%20at%3A%201%29%20%3D%20%27h%27.%0A%09self%20assert%3A%20%28%27hello%27%20at%3A%205%29%20%3D%20%27o%27.%0A%09self%20assert%3A%20%28%27hello%27%20at%3A%206%20ifAbsent%3A%20%5Bnil%5D%29%20%3D%20nil'),
+messageSends: ["assert:", unescape("%3D"), "at:", "at:ifAbsent:"],
+referencedClasses: []
+}),
+smalltalk.StringTest);
+
+smalltalk.addMethod(
+unescape('_testAtPut'),
+smalltalk.method({
+selector: unescape('testAtPut'),
+category: 'tests',
+fn: function (){
+var self=this;
+smalltalk.send(self, "_should_raise_", [(function(){return smalltalk.send("hello", "_at_put_", [(1), "a"]);}), (smalltalk.Error || Error)]);
+return self;},
+args: [],
+source: unescape('testAtPut%0A%09%22String%20instances%20are%20read-only%22%0A%09self%20should%3A%20%5B%27hello%27%20at%3A%201%20put%3A%20%27a%27%5D%20raise%3A%20Error'),
+messageSends: ["should:raise:", "at:put:"],
+referencedClasses: ["Error"]
+}),
+smalltalk.StringTest);
+
 
 
 smalltalk.addClass('DictionaryTest', smalltalk.TestCase, [], 'Kernel-Tests');

+ 22 - 0
js/SUnit.deploy.js

@@ -124,6 +124,28 @@ return self;}
 }),
 smalltalk.TestCase);
 
+smalltalk.addMethod(
+'_should_',
+smalltalk.method({
+selector: 'should:',
+fn: function (aBlock){
+var self=this;
+smalltalk.send(self, "_assert_", [smalltalk.send(aBlock, "_value", [])]);
+return self;}
+}),
+smalltalk.TestCase);
+
+smalltalk.addMethod(
+'_should_raise_',
+smalltalk.method({
+selector: 'should:raise:',
+fn: function (aBlock, anExceptionClass){
+var self=this;
+smalltalk.send(self, "_assert_", [smalltalk.send((function(){smalltalk.send(aBlock, "_value", []);return false;}), "_on_do_", [anExceptionClass, (function(ex){return true;})])]);
+return self;}
+}),
+smalltalk.TestCase);
+
 
 smalltalk.addMethod(
 '_testSelectors',

+ 32 - 0
js/SUnit.js

@@ -179,6 +179,38 @@ referencedClasses: []
 }),
 smalltalk.TestCase);
 
+smalltalk.addMethod(
+unescape('_should_'),
+smalltalk.method({
+selector: unescape('should%3A'),
+category: 'testing',
+fn: function (aBlock){
+var self=this;
+smalltalk.send(self, "_assert_", [smalltalk.send(aBlock, "_value", [])]);
+return self;},
+args: ["aBlock"],
+source: unescape('should%3A%20aBlock%0A%09self%20assert%3A%20aBlock%20value'),
+messageSends: ["assert:", "value"],
+referencedClasses: []
+}),
+smalltalk.TestCase);
+
+smalltalk.addMethod(
+unescape('_should_raise_'),
+smalltalk.method({
+selector: unescape('should%3Araise%3A'),
+category: 'testing',
+fn: function (aBlock, anExceptionClass){
+var self=this;
+smalltalk.send(self, "_assert_", [smalltalk.send((function(){smalltalk.send(aBlock, "_value", []);return false;}), "_on_do_", [anExceptionClass, (function(ex){return true;})])]);
+return self;},
+args: ["aBlock", "anExceptionClass"],
+source: unescape('should%3A%20aBlock%20raise%3A%20anExceptionClass%0A%09self%20assert%3A%20%28%5BaBlock%20value.%20false%5D%20%0A%09%09on%3A%20anExceptionClass%20%0A%09%09do%3A%20%5B%3Aex%20%7C%20true%5D%29'),
+messageSends: ["assert:", "on:do:", "value"],
+referencedClasses: []
+}),
+smalltalk.TestCase);
+
 
 smalltalk.addMethod(
 unescape('_testSelectors'),

+ 1 - 5
st/Kernel-Collections.st

@@ -333,16 +333,12 @@ size
 	<return self.length>
 !
 
-at: anIndex
-	<return self[anIndex - 1]>
-!
-
 at: anIndex put: anObject
 	self errorReadOnly
 !
 
 at: anIndex ifAbsent: aBlock
-	(self at: anIndex) ifNil: [aBlock]
+	<return self[anIndex - 1] || aBlock()>
 !
 
 escaped

+ 1 - 1
st/Kernel-Methods.st

@@ -92,7 +92,7 @@ whileTrue
 !BlockClosure methodsFor: 'error handling'!
 
 on: anErrorClass do: aBlock
-	self try: self catch: [:error |
+	^self try: self catch: [:error |
 	    (error isKindOf: anErrorClass) 
 	     ifTrue: [aBlock value: error]
 	     ifFalse: [error signal]]

+ 2 - 1
st/Kernel-Objects.st

@@ -125,7 +125,8 @@ shouldNotImplement
 !
 
 try: aBlock catch: anotherBlock
-	<try{aBlock()} catch(e) {anotherBlock(e)}>
+	<try{result = aBlock()} catch(e) {result = anotherBlock(e)};
+	return result;>
 !
 
 doesNotUnderstand: aMessage

+ 11 - 0
st/Kernel-Tests.st

@@ -37,6 +37,17 @@ testCopyWithoutAll
 	self 
 		assert: 'hello world' 
 		equals: ('*hello* *world*' copyWithoutAll: '*')
+!
+
+testAt
+	self assert: ('hello' at: 1) = 'h'.
+	self assert: ('hello' at: 5) = 'o'.
+	self assert: ('hello' at: 6 ifAbsent: [nil]) = nil
+!
+
+testAtPut
+	"String instances are read-only"
+	self should: ['hello' at: 1 put: 'a'] raise: Error
 ! !
 
 TestCase subclass: #DictionaryTest

+ 10 - 0
st/SUnit.st

@@ -58,6 +58,16 @@ assert: expected equals: actual
 
 assert: aBoolean description: aString
 	aBoolean ifFalse: [self signalFailure: aString]
+!
+
+should: aBlock
+	self assert: aBlock value
+!
+
+should: aBlock raise: anExceptionClass
+	self assert: ([aBlock value. false] 
+		on: anExceptionClass 
+		do: [:ex | true])
 ! !
 
 !TestCase class methodsFor: 'accessing'!