Bugfix in ClassDefinitionChange>>setupFromSource: - extract inst and class vars as well.
"
COPYRIGHT (c) 1993 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
"{ Package: 'stx:libbasic3' }"
ClassChange subclass:#ClassDefinitionChange
instanceVariableNames:'objectType superClassName classType indexedType otherParameters
instanceVariableNames classVariableNames
classInstanceVariableNames poolDictionaries category private
definitionSelector owningClassName'
classVariableNames:''
poolDictionaries:''
category:'System-Changes'
!
!ClassDefinitionChange class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1993 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
instances represent class definition-changes.
They are typically held in a ChangeSet.
[author:]
Claus Gittinger
"
! !
!ClassDefinitionChange class methodsFor:'others'!
version_CVS
^ '§Header: /cvs/stx/stx/libbasic3/ClassDefinitionChange.st,v 1.72 2012/08/10 10:09:30 cg Exp §'
! !
!ClassDefinitionChange methodsFor:'accessing'!
basicSuperClassName
^ superClassName
!
category
category isNil ifTrue:[
self setupFromSource.
].
^ category
"Modified: / 11-10-2006 / 14:12:01 / cg"
!
category:something
category := something.
!
classInstanceVariableNames
^ classInstanceVariableNames
!
classInstanceVariableNames:something
classInstanceVariableNames := something.
!
classVariableNames
^ classVariableNames
!
classVariableNames:something
classVariableNames := something.
!
delta
| class |
class := self changeClass.
class ifNil:[^#+].
^(self class isSource: self source sameSourceAs: class definitionWithoutPackage "definition")
ifTrue:[#=]
ifFalse:[#~]
"Modified: / 31-08-2011 / 09:26:48 / cg"
!
deltaDetail
"Returns a delta to the current state as a ChangeDelta object"
| class mySource imageSource myTree imageTree same |
class := self changeClass.
class isNil ifTrue:[^ ChangeDeltaInformation added ].
class isLoaded ifFalse:[^ ChangeDeltaInformation different ].
mySource := self source.
imageSource := class definitionWithoutPackage "definition".
same := (mySource = imageSource).
same ifFalse:[
same := (self class isSource: mySource sameSourceAs: imageSource ).
same ifFalse:[
"/ care for formatting (tabs, indentation etc.)
myTree := RBParser parseExpression:mySource.
imageTree := RBParser parseExpression:imageSource.
same := (myTree = imageTree).
same ifFalse:[
"/ some classDefinition strings contain sn
"/ instVarName string like 'foo bar ' instead of 'foo bar' (i.e. added a space)...
((myTree receiver = imageTree receiver)
and:[ (myTree selector = imageTree selector)
and:[ ('*ubclass:instanceVariableNames:classVariableNames:poolDictionaries:category:' match: myTree selector)
and:[ (myTree arguments at:1) = (imageTree arguments at:1)
and:[ (2 to:5) conform:[:i |
((myTree arguments at:i) isLiteral
and:[ (imageTree arguments at:i) isLiteral
and:[ (myTree arguments at:i) value asString withoutSeparators
= (imageTree arguments at:i) value asString withoutSeparators ]]) ]
]]]])
ifTrue:[
same := true
]
].
]
].
^ same
ifTrue:[ ChangeDeltaInformation identical ]
ifFalse:[ ChangeDeltaInformation different ]
"Created: / 31-08-2011 / 10:26:42 / cg"
"Modified: / 24-01-2012 / 22:13:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
instanceVariableNames
^ instanceVariableNames
!
instanceVariableNames:something
instanceVariableNames := something.
!
nameSpaceName
objectType == #variable ifTrue:[
^ nil
].
^ self cutNameSpaceOf:(self nameSpaceOverride ? super nameSpaceName)
"Modified: / 07-09-2011 / 20:47:14 / cg"
!
nameSpaceName: aNameSpaceName classType: aClassType otherParameters:otherParametersArg
"this instance setup message is used when reading from a VW-xml change file.
Support for this is not yet complete."
|indexedType imports|
nameSpaceOverride := aNameSpaceName.
classType := aClassType.
otherParameters := Dictionary new addAll:otherParametersArg; yourself.
superClassName := otherParameters at:#superclass: ifAbsent:nil.
superClassName notNil ifTrue:[
superClassName := superClassName pathString.
].
indexedType := otherParameters at:#indexedType: ifAbsent:nil.
private := otherParameters at:#private: ifAbsent:nil.
instanceVariableNames := otherParameters at:#instanceVariableNames: ifAbsent:nil.
classInstanceVariableNames := otherParameters at:#classInstanceVariableNames: ifAbsent:nil.
imports := otherParameters at:#imports: ifAbsent:nil.
category := otherParameters at:#category: ifAbsent:nil.
"Modified: / 15-06-2010 / 14:50:35 / cg"
!
objectType
"return the value of the instance variable 'objectType' (automatically generated)"
^ objectType
!
objectType:something
"set the value of the instance variable 'objectType' (automatically generated)"
objectType := something.
!
poolDictionaries
poolDictionaries isNil ifTrue:[
self setupFromSource.
].
^ poolDictionaries
"Modified: / 13-06-2012 / 12:23:41 / cg"
!
poolDictionaries:something
poolDictionaries := something.
!
private:aBoolean
private := aBoolean.
"Created: / 30-08-2010 / 13:56:11 / cg"
!
source
"return the source of the change"
|src ns|
(src := source) isNil ifTrue:[
src := self definitionString
].
"/ ouch - already done in definitionString !!!!!!
"/ (ns := self nameSpaceOverride) notNil ifTrue:[
"/ (className startsWith:(ns,'::')) ifFalse:[
"/ ^ '"{ NameSpace: ' , ns , ' }"' ,
"/ Character cr, Character cr ,
"/ src string
"/ ].
"/ ].
^ src
"Modified: / 10-08-2012 / 11:53:54 / cg"
!
superClassName
|nm|
nm := superClassName.
nm notNil ifTrue:[
(nm includes:$.) ifTrue:[
^ nm copyReplaceAll:$. withAll:'::'.
]
].
^ nm
!
superClassName:something
superClassName := something.
self invalidateSource.
!
superClassNameWithoutMyNamespace
|nm|
superClassName isNil ifTrue:[^ 'nil'].
nm := self cutMyNameSpaceOf:superClassName.
(nm includes:$.) ifTrue:[
^ nm copyReplaceAll:$. withAll:'::'.
].
^ nm
"Modified: / 03-03-2007 / 13:09:07 / cg"
!
superClassNameWithoutNamespace
|nm|
nm := self cutNameSpaceOf:superClassName.
(nm includes:$.) ifTrue:[
^ nm copyReplaceAll:$. withAll:'::'.
].
^ nm
! !
!ClassDefinitionChange methodsFor:'applying'!
apply
superClassName isNil ifTrue:[
self setupFromSource
].
superClassName isNil ifTrue:[
self error:'Should not happen'
].
(Smalltalk classNamed:superClassName) isNil ifTrue:[
Class undeclared:superClassName
].
Parser evaluate:(self source).
package notNil ifTrue:[
self changeClass setPackage:package.
].
"
(ClassDefinitionChange className: #TestB source: 'TestA subclass: #TestB
instanceVariableNames:''''
classVariableNames:''''
poolDictionaries:''''
category:''* remove me *''')
apply
"
"Modified: / 08-11-2010 / 16:10:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 06-10-2011 / 17:01:58 / cg"
! !
!ClassDefinitionChange methodsFor:'comparing'!
isForSameAs:changeB
"return true, if the given change represents a change for the same
thingy as the receiver (i.e. same method, same definition etc.)."
changeB isClassDefinitionChange ifFalse:[^ false].
className ~= changeB className ifTrue:[^ false].
^ true
!
sameAs:changeB
"return true, if the given change represents the same change as the receiver."
(self isForSameAs:changeB) ifFalse:[^ false].
^ self sameSourceAs:changeB
! !
!ClassDefinitionChange methodsFor:'converting'!
asAntiChange
^ClassRemoveChange className: self className
"Created: / 02-11-2009 / 11:11:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!ClassDefinitionChange methodsFor:'printing & storing'!
definitionString
|ns classNameUsed superClassNameUsed selPart|
ns := self nameSpaceOverride.
objectType == #variable ifTrue:[
^ String streamContents:[:stream |
ns notNil ifTrue:[
stream nextPutAll:((ns asCollectionOfSubstringsSeparatedBy:$.) asStringWith:'::')
] ifFalse:[
self halt:'can this happen ?'.
stream nextPutAll:'Smalltalk'
].
stream
nextPutAll:' addClassVarName:';
nextPutAll:className asString storeString
].
].
superClassNameUsed := self superClassName.
classNameUsed := self className.
selPart := (self definitionSelector ? #'subclass:instanceVariableNames:classVariableNames:poolDictionaries:category:')
keywords first.
^ String streamContents:[:stream |
stream
nextPutAll:superClassNameUsed;
nextPutAll:' ',selPart;
nextPutAll: classNameUsed asSymbol storeString;
cr;
spaces:4;
nextPutAll:'instanceVariableNames: ';
nextPutAll:(instanceVariableNames ? '') storeString;
cr;
spaces:4;
nextPutAll:'classVariableNames: ';
nextPutAll:(classVariableNames ? '') storeString;
cr;
spaces:4;
nextPutAll:'poolDictionaries: ';
nextPutAll:(poolDictionaries ? '') storeString;
cr.
private == true ifTrue:[
stream
spaces:4;
nextPutAll:'privateIn: ';
nextPutAll:(self owningClassName)
] ifFalse:[
stream
spaces:4;
nextPutAll:'category: ';
nextPutAll:(category ? '') storeString
].
]
"Modified: / 13-06-2012 / 13:01:58 / cg"
!
definitionStringInNamespace: ns
| classNameUsed superClassNameUsed |
objectType == #variable ifTrue:[
^ String streamContents:[:stream |
ns notNil ifTrue:[
stream
nextPutAll:((ns asCollectionOfSubstringsSeparatedBy:$.) asStringWith:'::')
] ifFalse:[
self halt:'can this happen ?'.
stream
nextPutAll:'Smalltalk'
].
stream
nextPutAll:' addClassVarName:';
nextPutAll:className asString storeString
].
].
superClassNameUsed := self superClassName.
classNameUsed := self classNameWithoutNamespace.
^ String streamContents:[:stream |
self isPrivateClassDefinitionChange ifFalse:[
stream
nextPutAll:(superClassNameUsed ? 'nil');
nextPutAll:' subclass:';
nextPutAll: classNameUsed asSymbol storeString
;
cr;
tab;
nextPutAll:'instanceVariableNames:';
nextPutAll:(instanceVariableNames ? '') storeString;
cr;
tab;
nextPutAll:'classVariableNames:';
nextPutAll:(classVariableNames ? '') storeString;
cr;
tab;
nextPutAll:'poolDictionaries:';
nextPutAll:(poolDictionaries ? '') storeString;
cr;
tab;
nextPutAll:'category:';
nextPutAll:(category ? '') storeString;
cr
] ifTrue:[
stream
nextPutAll:superClassNameUsed;
nextPutAll:' subclass:';
nextPutAll: (self className copyFrom: owningClassName size + 3) asSymbol storeString
;
cr;
tab;
nextPutAll:'instanceVariableNames:';
nextPutAll:(instanceVariableNames ? '') storeString;
cr;
tab;
nextPutAll:'classVariableNames:';
nextPutAll:(classVariableNames ? '') storeString;
cr;
tab;
nextPutAll:'poolDictionaries:';
nextPutAll:(poolDictionaries ? '') storeString;
cr;
tab;
nextPutAll:'privateIn:';
nextPutAll:
(ns isNil
ifTrue:[owningClassName]
ifFalse:[owningClassName copyFrom: ns size + 3]);
cr
]
]
"Modified: / 06-10-2011 / 17:02:05 / cg"
"Created: / 20-03-2012 / 19:40:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
definitionStringWithoutNamespace
|ns classNameUsed superClassNameUsed|
ns := self nameSpaceOverride.
objectType == #variable ifTrue:[
^ String streamContents:[:stream |
ns notNil ifTrue:[
stream
nextPutAll:((ns asCollectionOfSubstringsSeparatedBy:$.) asStringWith:'::')
] ifFalse:[
self halt:'can this happen ?'.
stream
nextPutAll:'Smalltalk'
].
stream
nextPutAll:' addClassVarName:';
nextPutAll:className asString storeString
].
].
superClassNameUsed := self superClassName.
classNameUsed := self classNameWithoutNamespace.
^ String streamContents:[:stream |
self isPrivateClassDefinitionChange ifFalse:[
stream
nextPutAll:superClassNameUsed;
nextPutAll:' subclass:';
nextPutAll: classNameUsed asSymbol storeString
;
cr;
tab;
nextPutAll:'instanceVariableNames:';
nextPutAll:(instanceVariableNames ? '') storeString;
cr;
tab;
nextPutAll:'classVariableNames:';
nextPutAll:(classVariableNames ? '') storeString;
cr;
tab;
nextPutAll:'poolDictionaries:';
nextPutAll:(poolDictionaries ? '') storeString;
cr;
tab;
nextPutAll:'category:';
nextPutAll:(category ? '') storeString;
cr
] ifTrue:[
stream
nextPutAll:superClassNameUsed;
nextPutAll:' subclass:';
nextPutAll: (self className copyFrom: owningClassName size + 3) asSymbol storeString
;
cr;
tab;
nextPutAll:'instanceVariableNames:';
nextPutAll:(instanceVariableNames ? '') storeString;
cr;
tab;
nextPutAll:'classVariableNames:';
nextPutAll:(classVariableNames ? '') storeString;
cr;
tab;
nextPutAll:'poolDictionaries:';
nextPutAll:(poolDictionaries ? '') storeString;
cr;
tab;
nextPutAll:'privateIn:';
nextPutAll:
((ns := self nameSpaceName) isNil
ifTrue:[owningClassName]
ifFalse:[owningClassName copyFrom: ns size + 3]);
cr
]
]
"Modified: / 06-10-2011 / 17:02:05 / cg"
"Created: / 20-03-2012 / 16:37:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
printOn:aStream
aStream
nextPutAll:className; nextPutAll:' {definition}'
"Modified: / 12-10-2006 / 17:48:28 / cg"
!
printWithoutClassNameOn:aStream
aStream nextPutAll:('definition of ' , className)
! !
!ClassDefinitionChange methodsFor:'queries'!
definitionSelector
definitionSelector isNil ifTrue:[
self setupFromSource.
].
^ definitionSelector
"Modified: / 11-10-2006 / 14:11:44 / cg"
!
definitionSelector:aSelector
definitionSelector := aSelector
"Created: / 13-06-2012 / 12:45:02 / cg"
!
isClassDefinitionChange
^ true
!
isPrivateClassDefinitionChange
private isNil ifTrue:[
(className includes:$:) ifFalse:[
"/ cannot be private
private := false
] ifTrue:[
source isNil ifTrue:[^ false ].
(source includesString:'private') ifFalse:[
private := false.
] ifTrue:[
"/ (self changeClass notNil
"/ and:[self changeClass isLoaded not]) ifTrue:[
"/ "/ cannot be private
"/ private := false
"/ ] ifTrue:[
self setupFromSource.
"/ ].
].
].
].
^ private
"Created: / 11-10-2006 / 14:19:03 / cg"
"Modified: / 16-11-2006 / 16:34:19 / cg"
!
owningClassName
self isPrivateClassDefinitionChange ifTrue:[
owningClassName isNil ifTrue:[
self setupFromSource.
].
].
^ owningClassName
"Created: / 12-10-2006 / 23:07:25 / cg"
!
owningClassName:aStringOrSymbol
owningClassName := aStringOrSymbol
"Created: / 30-08-2010 / 13:55:37 / cg"
! !
!ClassDefinitionChange methodsFor:'special'!
installAsAutoloadedClassIfPublicWithFilename:aFilenameString
"install the class defined by this change as autoloaded.
Skip private classes.
Enter class file name as abbreviation"
|parseTree sel cat clsName cls catIdx pkg|
private == true ifTrue:[^ self].
parseTree := Parser parseExpression:self source.
parseTree isMessage ifFalse:[
self error:'bad change source'.
].
sel := parseTree selector.
(sel endsWith:':privateIn:') ifTrue:[^ self].
catIdx := sel asSymbol keywords indexOf:'category:'.
catIdx ~~ 0 ifTrue:[
cat := (parseTree args at:catIdx) evaluate.
].
clsName := self className asSymbol.
cls := Smalltalk at:clsName.
pkg := package ? Project current package.
(cls isNil
or:[cls isBehavior not
or:[cls isLoaded not]]) ifTrue:[
|autoloadedClass|
autoloadedClass := Smalltalk
installAutoloadedClassNamed:clsName
category:cat
package:pkg
revision:nil.
aFilenameString notNil ifTrue:[
autoloadedClass setClassFilename:aFilenameString.
"/ Smalltalk setFilename:aFilenameString forClass:clsName package:pkg.
]
] ifFalse:[
cls notNil ifTrue:[
cls isBehavior ifTrue:[
cls package ~= pkg ifTrue:[
Transcript showCR:('Autoloaded class: %1 not installed (package would change from %2 to %3)'
bindWith:clsName with:cls package with:pkg).
]
].
].
].
"Modified: / 03-07-2011 / 18:34:05 / cg"
!
invalidateSource
"internal - flush the sourceString if it got invalidated due to a
className, superclassName, etc... change"
source := nil.
!
setupFromSource
"Extract data from class definition string in source.
WARNING: This overwrites values in instvars!!"
|parseTree catIdx poolIdx instVarIdx classVarIdx |
source notNil ifTrue:[
parseTree := Parser parseExpression:source.
(parseTree notNil and:[parseTree isMessage]) ifFalse:[
self error:'bad change source' mayProceed:true.
^ self
].
definitionSelector := parseTree selector.
private := (definitionSelector endsWith:':privateIn:').
private ifTrue:[
owningClassName := parseTree args last name.
].
catIdx := definitionSelector keywords indexOf:'category:'.
catIdx ~~ 0 ifTrue:[
category := (parseTree args at:catIdx) evaluate.
].
poolIdx := definitionSelector keywords indexOf:'poolDictionaries:'.
poolIdx ~~ 0 ifTrue:[
poolDictionaries := (parseTree args at:poolIdx) evaluate.
].
instVarIdx := definitionSelector keywords indexOf:'instanceVariableNames:'.
instVarIdx ~~ 0 ifTrue:[
instanceVariableNames := (parseTree args at:instVarIdx) value.
].
classVarIdx := definitionSelector keywords indexOf:'classVariableNames:'.
classVarIdx ~~ 0 ifTrue:[
classVariableNames := (parseTree args at:classVarIdx) value.
].
superClassName := parseTree receiver name.
].
"Created: / 11-10-2006 / 14:10:02 / cg"
"Modified: / 13-06-2012 / 12:25:10 / cg"
"Modified: / 30-01-2013 / 12:01:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!ClassDefinitionChange methodsFor:'visiting'!
acceptChangeVisitor:aVisitor
^ aVisitor visitClassDefinitionChange:self.
"Created: / 25-11-2011 / 17:13:13 / cg"
! !
!ClassDefinitionChange class methodsFor:'documentation'!
version
^ '$Header: ClassDefinitionChange.st 1961 2012-09-07 17:29:20Z vranyj1 $'
!
version_HG
^ '$Changeset: <not expanded> $'
!
version_SVN
^ '§Id:: ClassDefinitionChange.st 1961 2012-09-07 17:29:20Z vranyj1 §'
! !