Skip to content

Commit

Permalink
Fix metaclass of a class after removing its traits
Browse files Browse the repository at this point in the history
If you have a class using traits, its metaclass will be TraitedMetaclass. Now, if you remove its traits, its class should be Metaclass. The problem is that if you use #fillFor: it will not be the case.

The origin of the problem comes from the fact that #fillFor: will set the metaclass class to TraitedMetaclass and this will not be updated if you set the trait composition to be empty.

I provided a fix that is not so good in my opinion, but I'll try to change the way the class builder deals with metaclass class later to simplify this system and remove the need of this fix.

Finally I moved a test from shift class builder tests to traits tests since it uses a trait
  • Loading branch information
jecisc committed May 30, 2024
1 parent eb2e68c commit 7e65c53
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 21 deletions.
21 changes: 0 additions & 21 deletions src/Shift-ClassBuilder-Tests/ShClassInstallerTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -232,27 +232,6 @@ ShClassInstallerTest >> testCreatedClassWithAllElements [
self assert: newClass packageTag name equals: 'boring'
]

{ #category : 'tests' }
ShClassInstallerTest >> testCreatingFullTraitHasAllElements [

newClass := ShiftClassInstaller make: [ :builder |
builder
beTrait;
name: #TSHClass;
slots: { #a. #b };
traits: { TViewModelMock };
tag: 'boring';
package: self generatedClassesPackageName ].

self assert: newClass name equals: #TSHClass.
self assert: newClass slots size equals: 2.
self assert: newClass slotNames equals: #( a b ).
self assert: newClass traitComposition equals: { TViewModelMock } asTraitComposition.
self assert: newClass class traitComposition equals: { TViewModelMock classSide } asTraitComposition.
self assert: newClass package name equals: self generatedClassesPackageName.
self assert: newClass packageTag name equals: 'boring'
]

{ #category : 'tests' }
ShClassInstallerTest >> testDuplicateClassError [

Expand Down
79 changes: 79 additions & 0 deletions src/Traits-Tests/ShTraitInstallerTest.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
Class {
#name : 'ShTraitInstallerTest',
#superclass : 'ShClassInstallerTest',
#category : 'Traits-Tests-ShiftClassInstaller',
#package : 'Traits-Tests',
#tag : 'ShiftClassInstaller'
}

{ #category : 'tests' }
ShTraitInstallerTest >> testCreatingFullTraitHasAllElements [

newClass := ShiftClassInstaller make: [ :builder |
builder
beTrait;
name: #TSHClass;
slots: { #a. #b };
traits: { TViewModelMock };
tag: 'boring';
package: self generatedClassesPackageName ].

self assert: newClass name equals: #TSHClass.
self assert: newClass slots size equals: 2.
self assert: newClass slotNames equals: #( a b ).
self assert: newClass traitComposition equals: { TViewModelMock } asTraitComposition.
self assert: newClass class traitComposition equals: { TViewModelMock classSide } asTraitComposition.
self assert: newClass package name equals: self generatedClassesPackageName.
self assert: newClass packageTag name equals: 'boring'
]

{ #category : 'tests' }
ShTraitInstallerTest >> testRemovingTraitCompositionOfAClassAfterFillForShouldUpdateItsMetaclass [

| t1 |
t1 := ShiftClassInstaller make: [ :builder |
builder
name: #TShCITestClass;
beTrait;
package: self generatedClassesPackageName ].

newClass := ShiftClassInstaller make: [ :builder |
builder
name: #ShCITestClass;
traits: t1;
package: self generatedClassesPackageName ].

self assert: newClass class class equals: TraitedMetaclass.

newClass := ShiftClassInstaller make: [ :builder |
builder
fillFor: newClass;
traits: { } ].

self assert: newClass class class equals: Metaclass
]

{ #category : 'tests' }
ShTraitInstallerTest >> testRemovingTraitCompositionOfAClassShouldUpdateItsMetaclass [

| t1 |
t1 := ShiftClassInstaller make: [ :builder |
builder
name: #TShCITestClass;
beTrait;
package: self generatedClassesPackageName ].
newClass := ShiftClassInstaller make: [ :builder |
builder
name: #ShCITestClass;
traits: t1;
package: self generatedClassesPackageName ].

self assert: newClass class class equals: TraitedMetaclass.

newClass := ShiftClassInstaller make: [ :builder |
builder
name: #ShCITestClass;
package: self generatedClassesPackageName ].

self assert: newClass class class equals: Metaclass
]
3 changes: 3 additions & 0 deletions src/Traits/ShiftClassBuilder.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ ShiftClassBuilder >> traitComposition [
ShiftClassBuilder >> traitComposition: aValue [

self classTraitComposition: aValue asTraitComposition classComposition.
"Cyril: The next line is for the case where we update a class that had a trait and we remove the used traits. The metaclass should be updated also.
But, IMO we could do better. Instead of having a state for the metaclassClass we should resolve it via the enhancer during the building. And someone could set its own using its own enhancer."
(aValue isEmpty and: [ metaclassClass = TraitedMetaclass ]) ifTrue: [ metaclassClass := Metaclass ].
^ self privateTraitComposition: aValue
]

Expand Down

0 comments on commit 7e65c53

Please sign in to comment.