Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GS64: Add Collections packages #86

Merged
merged 24 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a53f24e
Move collection extensions to extensions package
gcotelli Aug 7, 2023
eabda81
Add collection packages to rowan spec
gcotelli Aug 7, 2023
c8f9466
Add NotFound and SubscriptOutOfBounds to GS64 extensions package
gcotelli Aug 7, 2023
c237187
Move copyLast: to package under Buoy control
gcotelli Aug 7, 2023
81b8372
Remove preload script
gcotelli Aug 7, 2023
8cedce2
Move extension already present in GS64 to a Pharo package
gcotelli Aug 7, 2023
84b1e31
Add missing extensions
gcotelli Aug 7, 2023
b2f810d
Remove SubscriptOutOfBounds from GS64 compatibility package
gcotelli Aug 8, 2023
31eeff4
Alias SubscriptOutOfBounds with OffsetError in GS
gcotelli Aug 8, 2023
3ce24e8
Remove NotFound from GS654 compatibility package
gcotelli Aug 8, 2023
1fd3007
Alias NotFound exception
gcotelli Aug 8, 2023
fcb3160
Fix with:with: and variants for GS64
gcotelli Aug 8, 2023
3af0e9d
Move OrderedSet>>#with:with: and variants to main package
gcotelli Aug 8, 2023
c82aa2a
Add TestAsserter>>#assert:identicalTo: and #deny:identicalTo:
gcotelli Aug 8, 2023
870b43a
Add Collection>>#collect:as: to GS package
gcotelli Aug 8, 2023
0106ed8
Add Array>>#fillFrom:with:
gcotelli Aug 8, 2023
2f6d27a
Add Integer>>#hashMultiply
gcotelli Aug 8, 2023
e8786e8
Add Collection>>#as: and SequenceableCollection>>#writeStream
gcotelli Aug 8, 2023
6cf4285
Add extensions to collections
gcotelli Aug 8, 2023
4ec2a3a
Add OrderedSet>>#first and #last
gcotelli Aug 8, 2023
f450ca7
Add OrderedSet>>#reverse
gcotelli Aug 8, 2023
a62027d
Fix OrderedSet tests in GS64
gcotelli Aug 8, 2023
713d70b
Fix tests for GS64
gcotelli Aug 8, 2023
a2b8aa2
Add test case for OrderedSet>>#with:with:with:with:
gcotelli Aug 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rowan/components/Deployment.ston
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
RwSimpleProjectLoadComponentV2 {
#name : 'Deployment',
#preloadDoitName : 'scripts/defineExceptionAliases',
#projectNames : [ ],
#componentNames : [ ],
#packageNames : [
'Buoy-Assertions',
'Buoy-Assertions-Extensions',
'Buoy-Collections',
'Buoy-Collections-Extensions',
'Buoy-Collections-GS64-Extensions',
'Buoy-Comparison',
Expand Down
1 change: 1 addition & 0 deletions rowan/components/Tests.ston
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ RwSimpleProjectLoadComponentV2 {
],
#packageNames : [
'Buoy-Assertions-Tests',
'Buoy-Collections-Tests',
'Buoy-Comparison-Tests',
'Buoy-Conditions-Tests',
'Buoy-Dynamic-Binding-Tests',
Expand Down
10 changes: 10 additions & 0 deletions rowan/components/scripts/defineExceptionAliases.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
| symbolDictionary |
symbolDictionary := Rowan image
symbolDictNamed:'Buoy'
ifAbsent: [
Rowan image symbolList createDictionaryNamed: 'Buoy' at: 1.
Rowan image symbolDictNamed:'Buoy'
].
symbolDictionary at: #SubscriptOutOfBounds put: OffsetError.
symbolDictionary at: #NotFound put: LookupError.

4 changes: 4 additions & 0 deletions source/BaselineOfBuoy/BaselineOfBuoy.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,12 @@ BaselineOfBuoy >> baselineCollections: spec [
package: 'Buoy-Collections-Extensions'
with: [ spec requires: 'Buoy-Collections' ];
group: 'Deployment' with: 'Buoy-Collections-Extensions';
package: 'Buoy-Collections-Pharo-Extensions'
with: [ spec requires: 'Buoy-Collections' ];
group: 'Deployment' with: 'Buoy-Collections-Pharo-Extensions';
package: 'Buoy-Collections-Tests' with: [
spec requires: #( 'Buoy-Collections' 'Buoy-Collections-Extensions'
'Buoy-Collections-Pharo-Extensions'
'Dependent-SUnit-Extensions' ) ];
group: 'Tests' with: 'Buoy-Collections-Tests'
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
Extension { #name : #Collection }

{ #category : #'*Buoy-Collections' }
{ #category : #'*Buoy-Collections-Extensions' }
Collection >> asOrderedSet [

^ self as: OrderedSet
]

{ #category : #'*Buoy-Collections' }
{ #category : #'*Buoy-Collections-Extensions' }
Collection >> maxUsing: aBlock [

^ self maxUsing: aBlock ifEmpty: [ self errorEmptyCollection ]
]

{ #category : #'*Buoy-Collections' }
{ #category : #'*Buoy-Collections-Extensions' }
Collection >> maxUsing: aBlock ifEmpty: ifEmptyBlock [

^ self ifEmpty: ifEmptyBlock ifNotEmpty: [ self inject: ( aBlock value: self anyOne ) into: [ :max :each | max max: ( aBlock value: each ) ] ]
]

{ #category : #'*Buoy-Collections' }
{ #category : #'*Buoy-Collections-Extensions' }
Collection >> minUsing: aBlock [

^ self minUsing: aBlock ifEmpty: [ self errorEmptyCollection ]
]

{ #category : #'*Buoy-Collections' }
{ #category : #'*Buoy-Collections-Extensions' }
Collection >> minUsing: aBlock ifEmpty: ifEmptyBlock [

^ self ifEmpty: ifEmptyBlock ifNotEmpty: [ self inject: ( aBlock value: self anyOne ) into: [ :max :each | max min: ( aBlock value: each ) ] ]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
Extension { #name : #SequenceableCollection }

{ #category : #'*Buoy-Collections-Extensions' }
SequenceableCollection >> copyFirst: n [

^ [ self copyFrom: 1 to: n ] unless: n = 0 inWhichCase: [ self species new ]
]

{ #category : #'*Buoy-Collections-Extensions' }
SequenceableCollection >> copyNoMoreThanFirst: n [

^ self copyFirst: ( self size min: n )
]

{ #category : #'*Buoy-Collections-Extensions' }
SequenceableCollection >> copyNoMoreThanLast: n [

^ self copyLast: ( n min: self size )
]

{ #category : #'*Buoy-Collections-Extensions' }
SequenceableCollection >> equalityChecker [

Expand Down
21 changes: 21 additions & 0 deletions source/Buoy-Collections-GS64-Extensions/Array.extension.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Extension { #name : #Array }

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Array >> fillFrom: aCollection with: aBlock [

| index |
index := 0.
aCollection do: [ :each |
self at: (index := index + 1) put: (aBlock value: each) ]
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Array class >> newFrom: aCollection [
"Answer an instance of me containing the same elements as aCollection."

| newArray |
newArray := self new: aCollection size.
1 to: aCollection size do: [ :i |
newArray at: i put: (aCollection at: i) ].
^ newArray
]
84 changes: 84 additions & 0 deletions source/Buoy-Collections-GS64-Extensions/Collection.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,70 @@ Collection >> anyOne [
^ self any
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> as: aSimilarClass [
"Create an object of class aSimilarClass that has similar contents to the receiver if the object is not already an instance of this class."

aSimilarClass == self class ifTrue: [ ^ self ].

^ aSimilarClass newFrom: self
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> collect: aBlock as: aClass [
"Evaluate aBlock with each of the receiver's elements as the argument.
Collect the resulting values into an instance of aClass. Answer the resulting collection."

^(aClass new: self size) fillFrom: self with: aBlock
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> count: aBlock [
"Evaluate aBlock with each of the receiver's elements as the argument.
Answer the number of elements that answered true."

| sum |
sum := 0.
self do: [ :each | (aBlock value: each) ifTrue: [ sum := sum + 1 ] ].
^ sum
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> detect: aBlock ifFound: foundBlock [
"Evaluate aBlock with each of the receiver's elements as the argument.
If some element evaluates aBlock to true, then cull this element into
foundBlock.
If no element matches the criteria then do nothing.
Always returns self to avoid misuse and a potential isNil check on the sender."

self
detect: aBlock
ifFound: foundBlock
ifNone: [ "Do nothing on purpose" ]
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> detect: aBlock ifFound: foundBlock ifNone: exceptionBlock [
"Evaluate aBlock with each of the receiver's elements as the argument.
If some element evaluates aBlock to true, then cull this element into
foundBlock and answer the result of this evaluation.
If none evaluate to true, then evaluate exceptionBlock."

self do: [ :each |
(aBlock value: each) ifTrue: [ ^ foundBlock cull: each ] ].
^ exceptionBlock value
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> fillFrom: aCollection with: aBlock [
"Private.
Evaluate aBlock with each of aCollections's elements as the argument.
Collect the resulting values into self. Answer self."

aCollection do: [ :each |
self add: (aBlock value: each) ]
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> ifEmpty: emptyBlock ifNotEmpty: notEmptyBlock [

Expand All @@ -20,6 +84,26 @@ Collection >> isSequenceable [
^ false
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection class >> newFrom: aCollection [
"Answer an instance of me containing the same elements as aCollection."

| newCollection |
newCollection := self new: aCollection size.
newCollection addAll: aCollection.
^ newCollection
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> removeAll [
"Remove each element from the receiver and leave it empty.
There are two good reasons why a subclass should override this message:
1) the subclass does not support being modified while being iterated
2) the subclass provides a much faster way than iterating through each element"

self do: [ :each | self remove: each ]
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
Collection >> select: selectBlock thenCollect: collectBlock [

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,45 @@
Extension { #name : #SequenceableCollection }

{ #category : #'*Buoy-Collections-GS64-Extensions' }
SequenceableCollection >> anyOne [

^ self first
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
SequenceableCollection >> copyAfter: anElement [
"Answer a copy of the receiver from after the first occurrence
of anElement up to the end. If no such element exists, answer
an empty copy."

^ self allButFirst: (self indexOf: anElement ifAbsent: [^ self copyEmpty])
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
SequenceableCollection >> endsWith: aSequenceableCollection [
"Answer true if the receiver ends with the argument collection"

| start |
aSequenceableCollection ifEmpty: [ ^true ].
(self size < aSequenceableCollection size) ifTrue: [^false].
start := self size - aSequenceableCollection size.
aSequenceableCollection withIndexDo: [:each :index | (self at: start + index) ~= each ifTrue: [^false]].
^true
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
SequenceableCollection >> isSequenceable [

^ true
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
SequenceableCollection >> removeAll [

self ifNotEmpty: [ self removeFrom: 1 to: self size ]
]

{ #category : #'*Buoy-Collections-GS64-Extensions' }
SequenceableCollection >> writeStream [
^ WriteStream on: self
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Extension { #name : #SequenceableCollection }

{ #category : #'*Buoy-Collections-Pharo-Extensions' }
SequenceableCollection >> copyLast: n [

^ [ self copyFrom: self size - n + 1 to: self size ] unless: n = 0 inWhichCase: [ self species new ]
]
1 change: 1 addition & 0 deletions source/Buoy-Collections-Pharo-Extensions/package.st
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Package { #name : #'Buoy-Collections-Pharo-Extensions' }
33 changes: 22 additions & 11 deletions source/Buoy-Collections-Tests/OrderedSetTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ OrderedSetTest >> testCopyReplaceFromToWithInsertingAtEnd [

original := self abcSet.

copy := original copyReplaceFrom: 4 to: 4 with: 'f'.
copy := original copyReplaceFrom: 4 to: 3 with: 'f'.

self
assert: copy size equals: 4;
Expand Down Expand Up @@ -1073,6 +1073,17 @@ OrderedSetTest >> testWithDo [
self assert: count equals: 3
]

{ #category : #'tests - instance creation' }
OrderedSetTest >> testWithWithWithWith [

| set |

set := OrderedSet with: #a with: #c with: #b with: #a .
self assert: set hasTheSameElementsInTheSameOrderThat: #( a c b ).


]

{ #category : #'tests - copying' }
OrderedSetTest >> testWithoutFirst [

Expand Down Expand Up @@ -1106,20 +1117,20 @@ OrderedSetTest >> testWriteStream [
nextPut: $d;
nextPut: $e;
nextPut: $f.

"According to ANSI standard it is unspecified whether or not the
returned collection is the same object as the backing store collection.

Se we just test over the stream contents"

self
assert: set size equals: 3;
assert: set first equals: $d;
assert: set second equals: $e;
assert: set last equals: $f.
assert: stream contents size equals: 3;
assert: stream contents first equals: $d;
assert: stream contents second equals: $e;
assert: stream contents last equals: $f.

stream nextPut: $g.

self
assert: set size equals: 3;
assert: set first equals: $d;
assert: set second equals: $e;
assert: set last equals: $f.

self
assert: stream contents size equals: 4;
assert: stream contents first equals: $d;
Expand Down
Loading