Browse Source

Collection >> single

Herbert Vojčík 7 years ago
parent
commit
bd03da9a06
4 changed files with 178 additions and 10 deletions
  1. 91 1
      src/Kernel-Collections.js
  2. 30 9
      src/Kernel-Collections.st
  3. 51 0
      src/Kernel-Tests.js
  4. 6 0
      src/Kernel-Tests.st

+ 91 - 1
src/Kernel-Collections.js

@@ -549,7 +549,7 @@ $globals.Collection);
 $core.addMethod(
 $core.method({
 selector: "anyOne",
-protocol: 'adding/removing',
+protocol: 'accessing',
 fn: function (){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1628,6 +1628,46 @@ messageSends: ["collect:"]
 }),
 $globals.Collection);
 
+$core.addMethod(
+$core.method({
+selector: "single",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+self._ifEmpty_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return self._error_("Collection is empty");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["error:"]=1;
+//>>excludeEnd("ctx");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+$1=$recv(self._size()).__gt((1));
+if($core.assert($1)){
+self._error_("Collection holds more than one element");
+};
+return self._anyOne();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"single",{},$globals.Collection)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "single\x0a\x09\x22Answer a single element.\x0a\x09Raise an error if collection holds less or more than one element.\x22\x0a\x0a\x09self ifEmpty: [ self error: 'Collection is empty' ].\x0a\x09self size > 1 ifTrue: [ self error: 'Collection holds more than one element' ].\x0a\x09^ self anyOne",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["ifEmpty:", "error:", "ifTrue:", ">", "size", "anyOne"]
+}),
+$globals.Collection);
+
 $core.addMethod(
 $core.method({
 selector: "size",
@@ -3866,6 +3906,29 @@ messageSends: ["copyFrom:to:", "-", "size"]
 }),
 $globals.SequenceableCollection);
 
+$core.addMethod(
+$core.method({
+selector: "anyOne",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return self._at_((1));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"anyOne",{},$globals.SequenceableCollection)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "anyOne\x0a\x09^ self at: 1",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["at:"]
+}),
+$globals.SequenceableCollection);
+
 $core.addMethod(
 $core.method({
 selector: "atRandom",
@@ -4431,6 +4494,33 @@ messageSends: ["at:"]
 }),
 $globals.SequenceableCollection);
 
+$core.addMethod(
+$core.method({
+selector: "single",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+
+	if (self.length == 0) throw new Error("Collection is empty");
+	if (self.length > 1) throw new Error("Collection holds more than one element.");
+	return self[0];;
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"single",{},$globals.SequenceableCollection)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "single\x0a<\x0a\x09if (self.length == 0) throw new Error(\x22Collection is empty\x22);\x0a\x09if (self.length >> 1) throw new Error(\x22Collection holds more than one element.\x22);\x0a\x09return self[0];\x0a>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.SequenceableCollection);
+
 $core.addMethod(
 $core.method({
 selector: "stream",

+ 30 - 9
src/Kernel-Collections.st

@@ -148,6 +148,15 @@ I provide a set of useful methods to the Collection hierarchy such as enumeratin
 
 !Collection methodsFor: 'accessing'!
 
+anyOne
+	"Answer a representative sample of the receiver. This method can
+	be helpful when needing to preinfer the nature of the contents of 
+	semi-homogeneous collections."
+
+	self ifEmpty: [ self error: 'Collection is empty' ].
+	self do: [ :each | ^ each ]
+!
+
 occurrencesOf: anObject
 	"Answer how many of the receiver's elements are equal to anObject."
 
@@ -157,6 +166,15 @@ occurrencesOf: anObject
 	^ tally
 !
 
+single
+	"Answer a single element.
+	Raise an error if collection holds less or more than one element."
+
+	self ifEmpty: [ self error: 'Collection is empty' ].
+	self size > 1 ifTrue: [ self error: 'Collection holds more than one element' ].
+	^ self anyOne
+!
+
 size
 	self subclassResponsibility
 ! !
@@ -173,15 +191,6 @@ addAll: aCollection
 	^ aCollection
 !
 
-anyOne
-	"Answer a representative sample of the receiver. This method can
-	be helpful when needing to preinfer the nature of the contents of 
-	semi-homogeneous collections."
-
-	self ifEmpty: [ self error: 'Collection is empty' ].
-	self do: [ :each | ^ each ]
-!
-
 remove: anObject
 	^ self remove: anObject ifAbsent: [ self errorNotFound ]
 !
@@ -939,6 +948,10 @@ allButLast
 	^ self copyFrom: 1 to: self size - 1
 !
 
+anyOne
+	^ self at: 1
+!
+
 atRandom
 	^ self at: self size atRandom
 !
@@ -1004,6 +1017,14 @@ second
 	^ self at: 2
 !
 
+single
+<
+	if (self.length == 0) throw new Error("Collection is empty");
+	if (self.length >> 1) throw new Error("Collection holds more than one element.");
+	return self[0];
+>
+!
+
 third
 	^ self at: 3
 ! !

+ 51 - 0
src/Kernel-Tests.js

@@ -4601,6 +4601,57 @@ messageSends: ["assert:equals:", "select:", "collection", "new", "collectionClas
 }),
 $globals.CollectionTest);
 
+$core.addMethod(
+$core.method({
+selector: "testSingle",
+protocol: 'tests',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv($recv(self._collectionClass())._new())._single();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["single"]=1;
+//>>excludeEnd("ctx");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}),$globals.Error);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["should:raise:"]=1;
+//>>excludeEnd("ctx");
+self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(self._collection())._single();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["single"]=2;
+//>>excludeEnd("ctx");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
+//>>excludeEnd("ctx");
+}),$globals.Error);
+self._assert_equals_($recv(self._sampleNewValueAsCollection())._single(),self._sampleNewValue());
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testSingle",{},$globals.CollectionTest)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testSingle\x0a\x09self should: [ self collectionClass new single ] raise: Error.\x0a\x09self should: [ self collection single ] raise: Error.\x0a\x09self assert: self sampleNewValueAsCollection single equals: self sampleNewValue",
+referencedClasses: ["Error"],
+//>>excludeEnd("ide");
+messageSends: ["should:raise:", "single", "new", "collectionClass", "collection", "assert:equals:", "sampleNewValueAsCollection", "sampleNewValue"]
+}),
+$globals.CollectionTest);
+
 $core.addMethod(
 $core.method({
 selector: "testSize",

+ 6 - 0
src/Kernel-Tests.st

@@ -779,6 +779,12 @@ testSelect
 	self assert: (self collectionWithNewValue select: [ :each | each ~= self sampleNewValue ]) equals: self collection
 !
 
+testSingle
+	self should: [ self collectionClass new single ] raise: Error.
+	self should: [ self collection single ] raise: Error.
+	self assert: self sampleNewValueAsCollection single equals: self sampleNewValue
+!
+
 testSize
 	self assert: self collectionClass new size equals: 0.
 	self assert: self sampleNewValueAsCollection size equals: 1.