Skip to content

Commit

Permalink
migrate add accessors with Lazy intialization
Browse files Browse the repository at this point in the history
  • Loading branch information
Lin777 committed Aug 2, 2021
1 parent e48c5d2 commit b58e141
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Class {
RBAddVariableAccessorsWithLazyInitializationParametrizedTest class >> testParameters [
^ ParametrizedTestMatrix new
addCase: { #rbClass -> RBCreateAccessorsWithLazyInitializationForVariableRefactoring };
addCase: { #rbClass -> RBAddVariableAccessorWithLazyInitializationTransformation };
yourself
]

Expand Down Expand Up @@ -37,31 +38,26 @@ RBAddVariableAccessorsWithLazyInitializationParametrizedTest >> testBadInitializ
{ #category : #tests }
RBAddVariableAccessorsWithLazyInitializationParametrizedTest >> testExistingClassVariableAccessors [
| refactoring class |
refactoring := rbClass
variable: 'Name1'
class: RBLintRuleTestData
classVariable: true.

refactoring := self createRefactoringWithArguments:
{ 'Name1' . RBLintRuleTestData . true . nil }.
class := refactoring model classNamed: #RBLintRuleTestData.
self assert: (class classSide parseTreeFor: #name1)
equals: (self parseMethod: 'name1 ^Name1').
self executeRefactoring: refactoring.
self assert: refactoring getterMethod identicalTo: #name1.
self assert: (class classSide parseTreeFor: #name1)
equals: (self parseMethod: 'name1 ^Name1 ifNil: [Name1 := nil]').
]

{ #category : #tests }
RBAddVariableAccessorsWithLazyInitializationParametrizedTest >> testExistingInstanceVariableAccessors [
| refactoring class |
refactoring := rbClass
variable: 'name'
class: RBLintRuleTestData
classVariable: false.
refactoring := self createRefactoringWithArguments:
{ 'name' . RBLintRuleTestData . false . nil }.
class := refactoring model classNamed: #RBLintRuleTestData.
self assert: (class parseTreeFor: #name)
equals: (self parseMethod: 'name ^name').
self executeRefactoring: refactoring.
self assert: refactoring getterMethod identicalTo: #name.
self assert: (class parseTreeFor: #name)
equals: (self parseMethod: 'name ^name ifNil: [name := nil]').
]
Expand All @@ -74,10 +70,9 @@ RBAddVariableAccessorsWithLazyInitializationParametrizedTest >> testNewClassVari
self executeRefactoring: ref.
class := ref model metaclassNamed: #RBLintRuleTestData.
self denyEmpty: ref changes changes.
self assert: ref setterMethod identicalTo: #foo1:.
self assert: ref getterMethod identicalTo: #foo1.
self assert: (class parseTreeFor: #foo1) equals: (self parseMethod: 'foo1 ^Foo1 ifNil: [ Foo1 := ''someString'' ]').
self assert: (class parseTreeFor: #foo1:) equals: (self parseMethod: 'foo1: anObject ^ Foo1 := anObject')
self assert: (((class parseTreeFor: #foo1:) = (self parseMethod: 'foo1: anObject ^ Foo1 := anObject'))
or: [ (class parseTreeFor: #foo1:) = (self parseMethod: 'foo1: anObject Foo1 := anObject') ])
]

{ #category : #tests }
Expand All @@ -88,21 +83,16 @@ RBAddVariableAccessorsWithLazyInitializationParametrizedTest >> testNewInstanceV
self executeRefactoring: ref.
class := ref model classNamed: #RBLintRuleTestData.
self denyEmpty: ref changes changes.
self assert: ref setterMethod identicalTo: #foo1:.
self assert: ref getterMethod identicalTo: #foo1.
self assert: (class parseTreeFor: #foo1) equals: (self parseMethod: 'foo1 ^foo1 ifNil: [foo1 := 123]').
self assert: (class parseTreeFor: #foo1:) equals: (self parseMethod: 'foo1: anObject foo1 := anObject')
]

{ #category : #'failure tests' }
RBAddVariableAccessorsWithLazyInitializationParametrizedTest >> testNonExistantName [

self
shouldFail: (rbClass
variable: #Foo
class: RBBasicLintRuleTestData
classVariable: true);
shouldFail: (rbClass
variable: 'foo'
class: RBBasicLintRuleTestData
classVariable: true)
shouldFail: (self createRefactoringWithArguments:
{ #Foo . RBBasicLintRuleTestData . true . nil });
shouldFail: (self createRefactoringWithArguments:
{'foo' . RBBasicLintRuleTestData . true . nil })
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"
I am a transformation to create accessors with lazy initialization for variables.
My precondition is that the variable name is defined for this class.
Example
--------
Script
```
(RBAddVariableAccessorWithLazyInitialization
variable: 'foo1'
class: RBLintRuleTestData
classVariable: false
defaultValue: '123') execute
```
After refactoring we get:
```
RBLintRuleTestData >> foo1
^ foo1 ifNil: [foo1 := 123]
RBLintRuleTestData >> foo1: anObject
foo1 := anObject
```
"
Class {
#name : #RBAddVariableAccessorWithLazyInitializationTransformation,
#superclass : #RBAddVariableAccessorTransformation,
#instVars : [
'defaultValue'
],
#category : #'Refactoring2-Transformations-Model'
}

{ #category : #api }
RBAddVariableAccessorWithLazyInitializationTransformation class >> model: aRBSmalltalk variable: aVarName class: aClass classVariable: aBoolean defaultValue: aString [

^(self model: aRBSmalltalk variable: aVarName class: aClass classVariable: aBoolean)
defaultValue: aString;
yourself
]

{ #category : #api }
RBAddVariableAccessorWithLazyInitializationTransformation class >> variable: aVarName class: aClass classVariable: aBoolean defaultValue: aString [

^(self variable: aVarName class: aClass classVariable: aBoolean)
defaultValue: aString;
yourself
]

{ #category : #preconditions }
RBAddVariableAccessorWithLazyInitializationTransformation >> checkVariableReferencesIn: aParseTree [

| searcher |

searcher := self parseTreeSearcher.
searcher
matches: '`var'
do: [ :aNode :answer |
| name |

name := aNode name.
( aNode whoDefines: name ) ifNil: [ self canReferenceVariable: name in: class ]
].
searcher executeTree: aParseTree
]

{ #category : #private }
RBAddVariableAccessorWithLazyInitializationTransformation >> createGetterAccessor [

(self definingClass getterMethodFor: variableName)
ifNil: [ self defineGetterMethod ]
ifNotNil: [ :symbol | self defineGetterCalled: symbol ]
]

{ #category : #accessing }
RBAddVariableAccessorWithLazyInitializationTransformation >> defaultValue [
^ defaultValue ifNil: [ defaultValue := 'nil' ]
]

{ #category : #accessing }
RBAddVariableAccessorWithLazyInitializationTransformation >> defaultValue: aString [
defaultValue := aString
]

{ #category : #transforming }
RBAddVariableAccessorWithLazyInitializationTransformation >> defineGetterCalled: aSymbol [

| selector |
selector := aSymbol.
self definingClass
compile: ('<1s><r><r><t>^ <2s> ifNil: [ <2s> := <3s> ]'
expandMacrosWith: selector
with: variableName
with: self defaultValue)
classified: #(#accessing).
^ selector
]

{ #category : #transforming }
RBAddVariableAccessorWithLazyInitializationTransformation >> defineGetterMethod [

^ self defineGetterCalled: self getterMethod
]

{ #category : #accessing }
RBAddVariableAccessorWithLazyInitializationTransformation >> getterMethod [
^ self safeMethodNameFor: self definingClass basedOn: variableName asString
]

{ #category : #preconditions }
RBAddVariableAccessorWithLazyInitializationTransformation >> preconditions [
^ super preconditions &
(RBCondition withBlock: [
self verifyInitializationExpressionOf: self defaultValue.
true ])
]

{ #category : #preconditions }
RBAddVariableAccessorWithLazyInitializationTransformation >> verifyInitializationExpressionOf: initializer [
| tree |
tree := self parserClass
parseExpression: initializer
onError: [ :msg :index | self refactoringFailure: 'Illegal initialization code because:.', msg ].
tree isValue
ifFalse: [ self refactoringFailure: 'The initialization code cannot be a return node or a list of statements' ].
self checkVariableReferencesIn: tree.
]

0 comments on commit b58e141

Please sign in to comment.