CustomNamespace.st
author Jakub Nesveda <jakubnesveda@seznam.cz>
Sun, 19 Oct 2014 14:55:14 +0200
changeset 704 340954b48789
parent 700 55a8d014066f
child 705 1eb0878dc85c
permissions -rw-r--r--
better comment in CustomNamespace >> execute fix replace on wrong code selection ( replace only if found match ) in CustomRefactoryBuilder

"{ Package: 'jn:refactoring_custom' }"

RBNamespace subclass:#CustomNamespace
	instanceVariableNames:'changeManager formatter defaultValues defaultReplacements package
		classModelClass methodModelClass sourceCodeGeneratorClass'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Refactoring-Custom'
!


!CustomNamespace methodsFor:'accessing'!

changeManager
    ^ changeManager
!

changeManager:something
    changeManager := something.
!

classModelClass
    "Returns class which represents Class in model in which we make changes (add class, rename class ...)."

    ^ classModelClass

    "Modified (comment): / 09-10-2014 / 11:14:51 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

classModelClass: aClass
    "see classModelClass"

    classModelClass := aClass.

    "Modified (comment): / 09-10-2014 / 11:15:18 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

formatter
    ^ formatter

    "Created: / 28-08-2014 / 23:19:02 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

formatter: aFormatter
    formatter := aFormatter

    "Created: / 28-08-2014 / 23:19:26 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

methodModelClass
    "Returns class which represents Method in model in which we make changes (add method, change method source ...)."

    ^ methodModelClass

    "Modified (comment): / 09-10-2014 / 11:17:09 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

methodModelClass: aClass
    "see methodModelClass"

    methodModelClass := aClass.

    "Modified (comment): / 09-10-2014 / 11:16:02 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

sourceCodeGenerator
    "Returns initialized source code generator"
    | sourceCodeGenerator |

    sourceCodeGenerator := self sourceCodeGeneratorClass new.
    sourceCodeGenerator formatter: formatter.
    ^ sourceCodeGenerator.

    "Created: / 19-09-2014 / 20:56:22 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 09-10-2014 / 11:35:24 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

sourceCodeGeneratorClass
    "Returns code generator class which supports search & replace in method source code and formatting"

    ^ sourceCodeGeneratorClass

    "Modified (comment): / 09-10-2014 / 11:34:34 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

sourceCodeGeneratorClass: aClass
    "see sourceCodeGeneratorClass"

    sourceCodeGeneratorClass := aClass.

    "Modified (comment): / 09-10-2014 / 11:34:56 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomNamespace methodsFor:'code creation'!

createClass
    "Much like createMethod, but for class"
    | class |

    class := self classModelClass new
        model: self;
        superclass: (self classNamed: #Object);
        instanceVariableNames: #();
        classVariableNames: #();
        poolDictionaryNames: #();
        yourself.

    self fillDefaultValuesTo: class.  
    self storeDefaultClassWhenNoneStored: class.

    ^ class

    "Created: / 09-04-2014 / 21:38:20 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 09-10-2014 / 11:18:17 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

createMethod
    "
    Creates, returns method representation
    so code changes can be created withing this class as one undo change
    "
    | method |

    method := self methodModelClass new
        model: self;
        sourceCodeGenerator: self sourceCodeGenerator;
        yourself.

    self fillDefaultValuesTo: method.

    ^ method

    "Created: / 09-04-2014 / 23:54:03 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 09-10-2014 / 11:25:43 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomNamespace methodsFor:'code creation - immediate'!

createClassImmediate: aClassName
    "Creates class immediately and returns the real class"

    ^ self createClassImmediate: aClassName superClassName: 'Object'

    "Created: / 27-07-2014 / 12:40:55 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

createClassImmediate: aClassName instanceVariableNames: instVarNames
    "Creates class immediately and returns the real class"

    ^ self 
        createClassImmediate: aClassName 
        superClassName: 'Object' 
        instanceVariableNames: instVarNames 
        classVariableNames: ''

    "Created: / 23-08-2014 / 22:25:08 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

createClassImmediate: aClassName superClassName: aSuperClassName
    "Creates class immediately and returns the real class"

    ^ self 
        createClassImmediate: aClassName 
        superClassName: aSuperClassName 
        instanceVariableNames: '' 
        classVariableNames: ''

    "Created: / 15-06-2014 / 15:59:21 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 23-08-2014 / 22:18:58 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

createClassImmediate: aClassName superClassName: aSuperClassName instanceVariableNames: instVarNames classVariableNames: classVarNames
    "Creates class immediately and returns the real class"

    changes addChange: (InteractiveAddClassChange definition:
        aSuperClassName, ' subclass:#', aClassName, '
            instanceVariableNames:''', instVarNames, '''
            classVariableNames:''', classVarNames, '''
            poolDictionaries:''''
            category:''''
    ').

    self execute.

    ^ Smalltalk classNamed: aClassName

    "Created: / 23-08-2014 / 22:18:07 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 21-09-2014 / 22:39:33 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

createMethodImmediate: aClass protocol: aProtocol source: aSource
    "Much like createClassImmediate:superClassName:, but for method"

    ^ self createMethodImmediate: aClass protocol: aProtocol source: aSource package: nil

    "Created: / 15-06-2014 / 16:06:00 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 17-10-2014 / 09:58:17 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

createMethodImmediate: aClass protocol: aProtocol source: aSource package: aPackageId
    "Much like createClassImmediate:superClassName:, but for method"

    | selector change |

    change := InteractiveAddMethodChange compile: aSource in: aClass classified: aProtocol.

    (aPackageId notNil and: [ (change class canUnderstand: #package:) ]) ifTrue: [ 
        change package: aPackageId  
    ].

    changes addChange: change.

    self execute.

    selector := (Parser parseMethodSpecification: aSource) selector.
    ^ aClass compiledMethodAt: selector

    "Created: / 17-10-2014 / 09:53:45 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

createMethodImmediate: aClass source: aSource
    "Much like createClassImmediate:superClassName:, but for method"

    ^ self createMethodImmediate: aClass protocol: 'protocol' source: aSource

    "Created: / 23-08-2014 / 20:17:22 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomNamespace methodsFor:'compiling'!

execute
    "Performs code changes ( add method, add class, rename class... )
    so they take in effect ( method is added, class is renamed, ... )
    with respect to current change manager implementatin - see CustomChangeManager subclasses."

    changeManager performChange: changes

    "Created: / 27-04-2014 / 16:30:05 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 21-09-2014 / 22:34:58 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified (comment): / 19-10-2014 / 14:30:45 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

redoChanges
    "redo all changes made by execute method"

    changeManager redoChanges

    "Created: / 27-04-2014 / 17:07:52 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 31-05-2014 / 19:47:02 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomNamespace methodsFor:'default values'!

category:aString

    self storeDefaultValue: #category: value: aString

    "Created: / 29-04-2014 / 19:51:45 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

class:aClass

    self storeDefaultValue: #classes: value: (Array with: aClass)

    "Created: / 29-04-2014 / 19:55:50 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 31-08-2014 / 17:01:22 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

className:something

    self storeDefaultValue: #className: value: something

    "Created: / 29-04-2014 / 19:42:23 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

classVariableNames:something

    self storeDefaultValue: #classVariableNames: value: something

    "Created: / 29-04-2014 / 19:43:22 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

classes: aClassCollection

    self storeDefaultValue: #classes: value: aClassCollection

    "Created: / 29-04-2014 / 19:50:07 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

fillDefaultValuesTo: aCodeElement
    "Initializes new code element (class, method) and fills default values from this model"
    | builderClass |

    builderClass := aCodeElement class. 

    defaultValues keysAndValuesDo: [ :selector :value |
        ((builderClass includesSelector: selector) or: [self isSharedAttribute: selector]) ifTrue: [
            aCodeElement perform: selector with: value.
        ]
    ].

    defaultReplacements keysAndValuesDo: [ :placeholder :code |
        aCodeElement replace: placeholder with: code 
    ].

    "Created: / 29-04-2014 / 20:21:57 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 09-10-2014 / 10:47:07 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

forgetReplacements

    defaultReplacements removeAll

    "Created: / 29-04-2014 / 20:19:15 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

instanceVariableNames:something

    self storeDefaultValue: #instanceVariableNames: value: something

    "Created: / 29-04-2014 / 19:44:37 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

isDefaultValueStored: aSelector

    ^ defaultValues includesKey: aSelector

    "Created: / 31-08-2014 / 16:43:52 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

isMeta:aBoolean

    self storeDefaultValue: #isMeta: value: aBoolean

    "Created: / 29-04-2014 / 19:47:47 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

package:aPackage

    ((self class) == CustomNamespace) ifTrue: [
        self storeDefaultValue: #package: value: aPackage
    ] ifFalse: [
        package := aPackage
    ]

    "Created: / 30-08-2014 / 18:32:01 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 09-10-2014 / 09:18:16 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

poolDictionaryNames:something

    self storeDefaultValue: #poolDictionaryNames: value: something

    "Created: / 29-04-2014 / 19:48:37 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

protocol:aString

    self storeDefaultValue: #protocol: value: aString

    "Created: / 29-04-2014 / 20:01:08 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

replace: placeholder with: code

    ((self class) == CustomNamespace) ifTrue: [
        defaultReplacements 
            at: placeholder 
            put: code
    ]
    ifFalse: [
        "replacements 
            at: placeholder
            put: (self replacementFromCode: code)"
    ]

    "Created: / 29-04-2014 / 20:02:45 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 09-10-2014 / 09:18:22 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

source:aString

    self storeDefaultValue: #source: value: aString

    "Created: / 29-04-2014 / 20:12:20 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

storeDefaultClassWhenNoneStored:aClass
    "Save class as default class when none class is actually set as default class"

    (self isDefaultValueStored: #classes:) ifFalse: [
        self storeDefaultValue: #classes: value: (Array with: aClass)
    ]

    "Created: / 31-08-2014 / 16:23:38 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

storeDefaultValue: aSelector value: aValue

    ((self class) == CustomNamespace) ifTrue: [
        defaultValues 
            at: aSelector 
            put: aValue    
    ]
    ifFalse: [
        self error: 'Selector ', aSelector, ' has to be overwritten by class: ', self className.
        "
        | superclass |

        superclass := self class superclass.
        superclass superclass isNil ifFalse: [
            superclass := superclass superclass
        ].

        (superclass canUnderstand: aSelector) ifTrue: [
            self assert: (superclass == CustomSourceCodeBuilder) not.
            self perform: aSelector with: aValue   
        ]
        "
    ]

    "Created: / 28-04-2014 / 19:08:17 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 09-10-2014 / 09:34:39 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

superclassName:something

    self storeDefaultValue: #superclassName: value: something

    "Created: / 29-04-2014 / 19:49:02 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomNamespace methodsFor:'initialization'!

initialize
    "Invoked when a new instance is created."

    super initialize.
    changeManager := CustomLocalChangeManager new.
    defaultValues := Dictionary new.
    defaultReplacements := Dictionary new.
    formatter := CustomRBLocalSourceCodeFormatter new.
    classModelClass := RBClass.
    methodModelClass := RBMethod.
    sourceCodeGeneratorClass := CustomSourceCodeGenerator.

    "Created: / 09-04-2014 / 23:44:04 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 09-10-2014 / 11:30:42 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomNamespace methodsFor:'private'!

isSharedAttribute: aSelector
    "Tells if given selector is shared attribute setter for subclasses"

    ^ (aSelector = #package:)

    "Created: / 30-08-2014 / 21:38:21 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomNamespace class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
! !