core/MetacelloProjectSpec.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Tue, 18 Sep 2012 18:24:44 +0000
changeset 16 25ac697dc747
parent 14 f01fe37493e9
child 19 28c344380944
permissions -rw-r--r--
- Updated from branch master

"{ Package: 'stx:goodies/metacello/core' }"

MetacelloSpec subclass:#MetacelloProjectSpec
	instanceVariableNames:'name className versionString operator loads preLoadDoIt
		postLoadDoIt'
	classVariableNames:''
	poolDictionaries:''
	category:'Metacello-Core-Specs'
!


!MetacelloProjectSpec methodsFor:'accessing'!

className: aString
    self shouldBeMutable.
    className := aString
!

file
    ^ nil
!

getClassName
    "raw access to iv"

    ^ className
!

getFile
    "raw access to iv"

    ^ nil
!

getOperator

	^operator
!

getRepositories
    "raw access to iv"

    ^ nil
!

loads: aCollection

	aCollection setLoadsInMetacelloProject: self
!

name: aString
    ((aString at: 1) isSeparator or: [ (aString at: aString size) isSeparator ])
        ifTrue: [ self error: 'Names are not allowed to have leading or trailing blanks: ' , aString printString ].
    self shouldBeMutable.
    name := aString
!

operator: anObject
    " #= #~= #> #< #>= #<= #~> "

    self shouldBeMutable.
    operator := anObject
!

postLoadDoIt: anObject

	anObject setPostLoadDoItInMetacelloSpec: self
!

preLoadDoIt: anObject

	anObject setPreLoadDoItInMetacelloSpec: self
!

setPostLoadDoIt: aSymbol
    self shouldBeMutable.
    postLoadDoIt := aSymbol
!

setPreLoadDoIt: aSymbol
    self shouldBeMutable.
    preLoadDoIt := aSymbol
!

versionString: anObject
    self shouldBeMutable.
    versionString := anObject
! !

!MetacelloProjectSpec methodsFor:'adding'!

addToMetacelloPackages: aMetacelloPackagesSpec

	| spec |
	spec := (aMetacelloPackagesSpec project projectReferenceSpec)
			name: self name;
			projectReference: self copy;
			yourself.
	aMetacelloPackagesSpec addMember: 
		(aMetacelloPackagesSpec addMember 
			name: spec name;
			spec: spec;
			yourself)
			
! !

!MetacelloProjectSpec methodsFor:'construction'!

className: aString constructor: aVersionConstructor
    aVersionConstructor classNameForProject: aString
!

loads: anObject constructor: aVersionConstructor
    aVersionConstructor loadsForProject: anObject
!

name: aString constructor: aVersionConstructor
    aVersionConstructor nameForProject: aString
!

operator: anObject constructor: aVersionConstructor
    aVersionConstructor operatorForProject: anObject
!

postLoadDoIt: aSymbol constructor: aVersionConstructor
    aVersionConstructor postLoadDoItForProject: aSymbol
!

preLoadDoIt: aSymbol constructor: aVersionConstructor
    aVersionConstructor preLoadDoItForProject: aSymbol
!

version: anObject constructor: aVersionConstructor
    aVersionConstructor versionForProject: anObject
!

versionString: anObject constructor: aVersionConstructor
    aVersionConstructor versionStringForProject: anObject
! !

!MetacelloProjectSpec methodsFor:'loading'!

load

	self subclassResponsibility
! !

!MetacelloProjectSpec methodsFor:'merging'!

mergeMap

	| map |
	map := super mergeMap.
	map at: #name put: name.
	map at: #className put: className.
	map at: #versionString put: versionString.
	map at: #operator put: operator.
	map at: #loads put: loads.
	map at: #preLoadDoIt put: preLoadDoIt.
	map at: #postLoadDoIt put: postLoadDoIt.
	^map
! !

!MetacelloProjectSpec methodsFor:'printing'!

configMethodBodyOn: aStream indent: indent
    | hasVersionString hasOperator hasProjectPackage hasLoads hasClassName hasPreLoadDoIt hasPostLoadDoIt |
    hasClassName := self hasClassName.
    hasVersionString := self versionString ~~ nil.
    hasOperator := operator ~~ nil.
    hasProjectPackage := self hasRepository or: [ hasClassName & (self getFile ~~ nil or: [ className ~= self name ]) ].
    hasLoads := self loads ~~ nil.
    hasPreLoadDoIt := self getPreLoadDoIt ~~ nil.
    hasPostLoadDoIt := self getPostLoadDoIt ~~ nil.
    hasClassName
        ifTrue: [ 
            hasVersionString | hasOperator | hasProjectPackage | hasLoads
                ifTrue: [ 
                    aStream
                        cr;
                        tab: indent + 1 ]
                ifFalse: [ aStream space ].
            aStream nextPutAll: 'className: ' , self className printString.
            hasVersionString | hasPreLoadDoIt | hasPostLoadDoIt | hasOperator | hasLoads | hasProjectPackage
                ifTrue: [ aStream nextPut: $; ] ].
    hasVersionString
        ifTrue: [ 
            | vs |
            hasClassName | hasOperator | hasProjectPackage | hasLoads | hasPreLoadDoIt | hasPostLoadDoIt
                ifTrue: [ 
                    aStream
                        cr;
                        tab: indent + 1 ]
                ifFalse: [ aStream space ].
            vs := self versionString.
            aStream nextPutAll: 'versionString: '.
            vs isSymbol
                ifTrue: [ aStream nextPut: $# ].
            aStream nextPutAll: vs asString printString.
            hasPreLoadDoIt | hasPostLoadDoIt | hasOperator | hasProjectPackage | hasLoads
                ifTrue: [ aStream nextPut: $; ] ].
    hasPreLoadDoIt
        ifTrue: [ 
            hasClassName | hasOperator | hasProjectPackage | hasLoads | hasPreLoadDoIt
                ifTrue: [ 
                    aStream
                        cr;
                        tab: indent + 1 ]
                ifFalse: [ aStream space ].
            aStream nextPutAll: 'preLoadDoIt: '.
            self preLoadDoIt value isSymbol
                ifTrue: [ 
                    aStream
                        nextPut: $#;
                        nextPutAll: self preLoadDoIt value asString printString ]
                ifFalse: [ aStream nextPutAll: self preLoadDoIt value asString ].
            hasPostLoadDoIt | hasOperator | hasProjectPackage | hasLoads
                ifTrue: [ aStream nextPut: $; ] ].
    hasPostLoadDoIt
        ifTrue: [ 
            hasClassName | hasOperator | hasProjectPackage | hasLoads | hasPostLoadDoIt
                ifTrue: [ 
                    aStream
                        cr;
                        tab: indent + 1 ]
                ifFalse: [ aStream space ].
            aStream nextPutAll: 'postLoadDoIt: '.
            self postLoadDoIt value isSymbol
                ifTrue: [ 
                    aStream
                        nextPut: $#;
                        nextPutAll: self postLoadDoIt value asString printString ]
                ifFalse: [ aStream nextPutAll: self postLoadDoIt value asString ].
            hasOperator | hasProjectPackage | hasLoads
                ifTrue: [ aStream nextPut: $; ] ].
    hasOperator
        ifTrue: [ 
            hasClassName | hasVersionString | hasProjectPackage | hasLoads | hasPreLoadDoIt | hasPostLoadDoIt
                ifTrue: [ 
                    aStream
                        cr;
                        tab: indent + 1 ]
                ifFalse: [ aStream space ].
            aStream nextPutAll: 'operator: #' , self operator asString printString.
            hasProjectPackage | hasLoads
                ifTrue: [ aStream nextPut: $; ] ].
    hasLoads
        ifTrue: [ 
            hasClassName | hasVersionString | hasOperator | hasProjectPackage | hasPreLoadDoIt | hasPostLoadDoIt
                ifTrue: [ 
                    aStream
                        cr;
                        tab: indent + 1 ]
                ifFalse: [ aStream space ].
            aStream nextPutAll: 'loads: #('.
            self loads do: [ :str | aStream nextPutAll: str printString , ' ' ].
            aStream nextPut: $).
            hasProjectPackage
                ifTrue: [ aStream nextPut: $; ] ].
    hasProjectPackage
        ifTrue: [ 
            | hasName hasRepo |
            hasRepo := self hasRepository.
            hasName := self file ~= self className.
            hasName
                ifTrue: [ 
                    hasClassName | hasVersionString | hasOperator | hasLoads | hasPreLoadDoIt | hasPostLoadDoIt
                        ifTrue: [ 
                            aStream
                                cr;
                                tab: indent + 1 ]
                        ifFalse: [ aStream space ].
                    aStream nextPutAll: 'file: ' , self file printString.
                    hasRepo
                        ifTrue: [ aStream nextPut: $; ] ].
            hasRepo
                ifTrue: [ 
                    | repos |
                    repos := self repositories map values.
                    repos size = 1
                        ifTrue: [ 
                            hasClassName | hasVersionString | hasOperator | hasLoads | hasPreLoadDoIt | hasPostLoadDoIt | hasName
                                ifTrue: [ 
                                    aStream
                                        cr;
                                        tab: indent + 1 ]
                                ifFalse: [ aStream space ].
                            repos first configMethodCascadeOn: aStream lastCascade: true ]
                        ifFalse: [ 
                            aStream cr.
                            self repositories configMethodCascadeOn: aStream indent: indent ] ] ]
!

configMethodOn: aStream indent: indent

	aStream 
		tab: indent;
		nextPutAll: 'spec '; cr;
		tab: indent + 1;
		nextPutAll: 'name: ', self name printString, ';'.
	self configMethodBodyOn: aStream indent: indent.
	aStream nextPut: $.
!

configShortCutMethodOn: aStream member: aMember indent: indent
    | hasVersionString hasOperator hasProjectPackage hasLoads hasClassName hasPreLoadDoIt hasPostLoadDoIt |
    hasClassName := self hasClassName.
    hasVersionString := self versionString ~~ nil.
    hasOperator := operator ~~ nil.
    hasProjectPackage := self hasRepository or: [ hasClassName & (self getFile ~~ nil or: [ className ~= self name ]) ].
    hasLoads := self loads ~~ nil.
    hasPreLoadDoIt := self getPreLoadDoIt ~~ nil.
    hasPostLoadDoIt := self getPostLoadDoIt ~~ nil.
    hasClassName | hasOperator | hasProjectPackage | hasLoads | hasPreLoadDoIt | hasPostLoadDoIt
        ifTrue: [ 
            (aMember methodUpdateSelector == #'copy:' or: [ aMember methodUpdateSelector == #'with:' ])
                ifTrue: [ 
                    aStream
                        nextPutAll: 'with: [';
                        cr ]
                ifFalse: [ 
                    aStream
                        nextPutAll: 'overrides: [';
                        cr ].
            aStream
                tab: indent;
                nextPutAll: 'spec'.
            self configMethodBodyOn: aStream indent: indent.
            aStream nextPutAll: ' ]'.
            ^ self ].
    hasVersionString
        ifTrue: [ 
            | vs |
            vs := self versionString.
            aStream nextPutAll: 'with: '.
            vs isSymbol
                ifTrue: [ aStream nextPut: $# ].
            aStream nextPutAll: vs asString printString ]
!

hasClassName
    ^ className ~~ nil
!

label

	^self name
!

projectLabel
    ^ 'project'
! !

!MetacelloProjectSpec methodsFor:'private'!

constructClassName
    ^ nil
!

loadListForVersion: vrsn 

	^ (self loads == nil
			or: [self loads isEmpty])
		ifTrue: [vrsn spec defaultPackageNames]
		ifFalse: [self loads]
!

setLoads: aCollection
    self shouldBeMutable.
    loads := aCollection
!

setName: aStringOrNil
    self shouldBeMutable.
    name := aStringOrNil
! !

!MetacelloProjectSpec methodsFor:'querying'!

className
    className ifNil: [ self name ifNotNil: [ self className: self constructClassName ] ].
    ^ className
!

currentlyLoadedClassesInVersion
    self versionOrNil ifNotNil: [ :vrsn | ^ vrsn currentlyLoadedClassesInVersion ].
    ^ #()
!

getPostLoadDoIt

	^postLoadDoIt
!

getPreLoadDoIt

	^preLoadDoIt
!

loads
	^ loads
!

name

	^name
!

operator

	operator == nil ifTrue: [ ^#>= ].
	^ operator
!

postLoadDoIt

	^postLoadDoIt
!

preLoadDoIt

	^preLoadDoIt
!

projectPackage

	^nil
!

version
    self subclassResponsibility
!

versionKey
	"suitable for using as a unique key for the receiver's version in a dictionary"

	^ self version versionKey
!

versionOrNil

	^[ self version ] on: MetacelloVersionDoesNotExistError do: [:ex | ^nil ].
!

versionString
	^ versionString
! !

!MetacelloProjectSpec methodsFor:'scripting'!

asProjectRegistration
    ^ MetacelloProjectRegistration fromProjectSpec: self
!

canDowngradeTo: aMetacelloProjectSpec
    (self className = aMetacelloProjectSpec className and: [ self operator == aMetacelloProjectSpec operator ])
        ifFalse: [ ^ false ].
    ^ (aMetacelloProjectSpec version perform: self operator with: self version) not
!

canUpgradeTo: aMetacelloProjectSpec
    (self className = aMetacelloProjectSpec className and: [ self operator == aMetacelloProjectSpec operator ])
        ifFalse: [ ^ false ].
    ^ aMetacelloProjectSpec version perform: self operator with: self version
!

compareEqual: aMetacelloProjectSpec
    "name className versionString operator loads preLoadDoIt postLoadDoIt"

    ^ self className = aMetacelloProjectSpec className
        and: [ 
            self versionString = aMetacelloProjectSpec versionString
                and: [ 
                    self operator == aMetacelloProjectSpec operator
                        and: [ 
                            self loads = aMetacelloProjectSpec loads
                                and: [ self preLoadDoIt == aMetacelloProjectSpec preLoadDoIt and: [ self postLoadDoIt == aMetacelloProjectSpec postLoadDoIt ] ] ] ] ]
!

mergeScriptLoads: aSpec
    self shouldBeMutable.
    aSpec loads
        ifNotNil: [ :otherLoads | self loads ifNil: [ loads := otherLoads ] ifNotNil: [ loads := (loads , otherLoads) asSet asArray ] ].
    self loader: aSpec loader
!

metacelloRegistrationHash
    "name className versionString operator loads preLoadDoIt postLoadDoIt"

    | hash |
    hash := String stringHash: name initialHash: 0.
    hash := String stringHash: self className initialHash: hash.
    hash := String stringHash: self versionString initialHash: hash.
    hash := String stringHash: self operator asString initialHash: hash.
    hash := String stringHash: self preLoadDoIt asString initialHash: hash.
    hash := String stringHash: self postLoadDoIt asString initialHash: hash.
    ^ hash bitXor: loads hash
!

registration
    ^ MetacelloProjectRegistration
        registrationForProjectSpec: self
        ifAbsent: [ :ignored |  ]
        ifPresent: [ :existing :new | existing ]
!

registrationsCompareEqual: aMetacelloProjectSpec
    "name className versionString operator loads preLoadDoIt postLoadDoIt"

    ^ self className = aMetacelloProjectSpec className
        and: [ self versionString = aMetacelloProjectSpec versionString and: [ self operator == aMetacelloProjectSpec operator ] ]
!

unregisterProject
    ^ MetacelloProjectRegistration
        registrationForProjectSpec: self
        ifAbsent: [  ]
        ifPresent: [ :existing :new | existing unregisterProject ]
! !

!MetacelloProjectSpec methodsFor:'visiting'!

projectDo: projectBlock packageDo: packageBlock groupDo: groupBlock
    projectBlock value: self
! !

!MetacelloProjectSpec class methodsFor:'documentation'!

version_SVN
    ^ '$Id::                                                                                                                        $'
! !