Skip to content

Commit

Permalink
TonelWriter changes, fixes #126
Browse files Browse the repository at this point in the history
  • Loading branch information
eMaringolo committed Dec 5, 2022
1 parent 9931ee8 commit 4fb52f7
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 107 deletions.
62 changes: 4 additions & 58 deletions docs/strategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,65 +321,7 @@ To enable this feature, you can do:

This option is `false` by default.

## TonelWriter options

### Writing sub applications as package tags

If when writing you want to perform the opposite step of the `TonelLoaderSubapplicationsTagMappingStrategy`, then you can configure the _writer_ to flatten sub applications and map them as package tags.

```smalltalk
writer := TonelWriter new.
writer flattenSubApplications: true.
```

NOTES: Since there is no "class category" in VAST classes the package tag is going to be computed based on the root application #tonelPackageName and the SubApplication name.

E.g. For an Application named `GreaseCoreApp` with the `GreaseCoreUtilities` and `GreaseCoreExceptions` sub applications, it will attempt to find remove the application name from the subapplication name (with or without the `App` suffix), and the resulting string is going to be used as the package tag. In this case it will remove `GreaseCore` from `GreaseCoreExceptions` and produce `Exceptions` as the package tag.



### Writing out `Application` and `SubApplications` subclasses

`Applications` and `SubApplication` subclasses have a dual purpose: to work as a "package" that works as container to class definitions and extensions in ENVY, and as a regular class that manage the lifetime of the app/sub app loading, initialization, etc.

So when exporting your `Application` subclass (e.g. `MyApplication`) it will export a class definition for it, with `Application` as its superclass. If your plan is to load it back into VAST, then that's totally fine, and the desired behavior, but if your intention is to export to another dialect you either have to have `Application` and `SubApplication` defined in such dialect (as some dialect compatibility package) or to omit the writing of such classes altogether.

So if you want to omit the write of ENVY app/subapp classes you can do:

```smalltalk
writer := TonelWriter new.
writer writeENVYApps: false.
```

By default the writer is configured to write the ENVY app/subapps, so if that's your intention you don't have to do anything special.

### Identifiers
Tonel, the file format, has a loose specification, and in some dialects it uses Symbols for its identifiers and in others it uses Strings because in not all the dialects aString = aSymbol.

So to avoid having file differences when working on code that share a common repository you can configure the `TonelWriter` to use Symbols or Strings for its identifiers.

```smalltalk
writer := TonelWriter new.
writer identifiersClass: Symbol.
```
### Format convenience settings

#### _"Canonical"_ format

If your objective is to export code to be used in another dialect, you can set different options as a whole like [converting shared pools](sharedpools.md) to `SharedPools` subclasses, not writing ENVY Application classes, using the Monticello extension category (as in `*PackageName` category) and will flatten SubApplications (if any) as package tags.

```smalltalk
writer := TonelWriter new.
writer beCanonical.
```
#### _"VAST Only"_ format

If the purpose of using Tonel Tools in VAST is to export code to files to be loaded back into VAST, then you can optimize a lot of settings by configuring the writer to write the files to be read only by VAST's Tonel Tools.

```smalltalk
writer := TonelWriter new.
writer beVASTOnly.
```


# Common recipes
Expand Down Expand Up @@ -426,3 +368,7 @@ Load applications unattended with a specified version name.
mapTagsToSubapplications; "<-- convenience method"
loadApplicationsForPackagesNamed: #('Package-Core' 'Package-Tests')
```

# Tonel Writer options

Please read the specific [Tonel Writer](writer.md) documentation.
70 changes: 70 additions & 0 deletions docs/writer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
## TonelWriter options

### Writing sub applications as package tags

If when writing you want to perform the opposite step of the `TonelLoaderSubapplicationsTagMappingStrategy`, then you can configure the _writer_ to flatten sub applications and map them as package tags.

```smalltalk
writer := TonelWriter new.
writer flattenSubApplications: true.
```

NOTES: Since there is no "class category" in VAST classes the package tag is going to be computed based on the root application #tonelPackageName and the SubApplication name.

E.g. For an Application named `GreaseCoreApp` with the `GreaseCoreUtilities` and `GreaseCoreExceptions` sub applications, it will attempt to find remove the application name from the subapplication name (with or without the `App` suffix), and the resulting string is going to be used as the package tag. In this case it will remove `GreaseCore` from `GreaseCoreExceptions` and produce `Exceptions` as the package tag.

### Writing out `Application` and `SubApplications` subclasses

`Applications` and `SubApplication` subclasses have a dual purpose: to work as a "package" that works as container to class definitions and extensions in ENVY, and as a regular class that manage the lifetime of the app/sub app loading, initialization, etc.

So when exporting your `Application` subclass (e.g. `MyApplication`) it will export a class definition for it, with `Application` as its superclass. If your plan is to load it back into VAST, then that's totally fine, and the desired behavior, but if your intention is to export to another dialect you either have to have `Application` and `SubApplication` defined in such dialect (as some dialect compatibility package) or to omit the writing of such classes altogether.

So if you want to omit the write of ENVY app/subapp classes you can do:

```smalltalk
writer := TonelWriter new.
writer writeENVYApps: false.
```

By default the writer is configured to write the ENVY app/subapps, so if that's your intention you don't have to do anything special.

### Identifiers
Tonel, the file format, has a loose specification, and in some dialects it uses Symbols for its identifiers and in others it uses Strings because in not all the dialects aString = aSymbol.

So to avoid having file differences when working on code that share a common repository you can configure the `TonelWriter` to use Symbols or Strings for its identifiers.

```smalltalk
writer := TonelWriter new.
writer identifiersClass: Symbol.
```
### _Monticello_ extension methods

Before extension methods had first-class support in other dialects, the Monticello packaging format established a convention to define them using the method category as a hint to the package system. So if you want to extend the class `Object` in the package `MyPackage` you'd do it by adding the extension method to the `*MyPackage`.

So if you want to avoid writing extension methods with such _"weird"_ names, you can disable them, and the `TonelWriter` will write the existing VAST category as the method category, instead of that.

```smalltalk
writer := TonelWriter new.
writer useMonticelloExtensions: false.
```


### Format convenience settings

#### _"Canonical"_ format

If your objective is to export code to be used in another dialect, you can set different options as a whole like [converting shared pools](sharedpools.md) to `SharedPools` subclasses, not writing ENVY Application classes, using the Monticello extension category (as in `*PackageName` category) and will flatten SubApplications (if any) as package tags.

```smalltalk
writer := TonelWriter new.
writer beCanonical.
```
#### _"VAST Only"_ format

If the purpose of using Tonel Tools in VAST is to export code to files to be loaded back into VAST, then you can optimize a lot of settings by configuring the writer to write the files to be read only by VAST's Tonel Tools.

```smalltalk
writer := TonelWriter new.
writer beVASTOnly.
```

24 changes: 12 additions & 12 deletions source/.configmaps
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[
{
#conditions : [ ],
#ts : 3836987643,
#ts : 3847711731,
#comment : '',
#formatVersion : '1.1',
#applications : OrderedCollection [
{
#name : 'TonelBaseApp',
#versionName : '1.4.7',
#ts : 3812608735
#versionName : 'b495 + 68281 b',
#ts : 3812609755
},
{
#name : 'TonelFileSystem',
Expand All @@ -22,8 +22,8 @@
},
{
#name : 'TonelLoaderModel',
#versionName : '1.5.8',
#ts : 3836987670
#versionName : '1.5.9',
#ts : 3846572097
},
{
#name : 'TonelReaderModel',
Expand All @@ -37,16 +37,16 @@
},
{
#name : 'TonelWriterModel',
#versionName : 'f2be7a2-master',
#ts : 3836967967
#versionName : '1.6.0',
#ts : 3847459439
}
],
#name : 'ENVY/Image Tonel',
#versionName : '1.5.8'
#versionName : '1.6.0'
},
{
#conditions : [ ],
#ts : 3812608505,
#ts : 3847711695,
#comment : '',
#formatVersion : '1.1',
#applications : OrderedCollection [
Expand All @@ -67,11 +67,11 @@
},
{
#name : 'TonelWriterTests',
#versionName : 'b495 + 68281 b',
#ts : 3812609757
#versionName : '1.6.0',
#ts : 3847697134
}
],
#name : 'Test ENVY/Image Tonel',
#versionName : 'V 11.0.0 [496]'
#versionName : '1.6.0'
}
]
45 changes: 29 additions & 16 deletions source/TonelWriterModel/TonelMethodWriter.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,32 @@ TonelMethodWriter >> parent [
^parent
]

{ #category : 'testing',
#vaVisibility : 'private' }
TonelMethodWriter >> shouldWriteVACategoriesOf: aMethodDefinition monticelloExtensionsEnabled: aBoolean [

aBoolean | aMethodDefinition hasMultipleCategories ifTrue: [^true].
(aMethodDefinition hasDefaultVACategories and:
[aMethodDefinition isMonticelloExtension
and: [self parent useMonticelloExtensions]])
ifTrue: [^true].
^false
]

{ #category : 'writing',
#vaVisibility : 'private' }
TonelMethodWriter >> splitSourceOf: aMethodDefinition into: aBlock [

^aBlock value: aMethodDefinition methodDeclaration value: aMethodDefinition methodBody
]

{ #category : 'public' }
TonelMethodWriter >> tonelWriter [
"Answer the TonelWriter of receiver."

^self parent
]

{ #category : 'writing' }
TonelMethodWriter >> write: aMethodDefinition on: aWriteStream [

Expand All @@ -90,23 +109,17 @@ TonelMethodWriter >> writeCategoryOf: aMethodDefinition on: aWriteStream [
{ #category : 'writing',
#vaVisibility : 'private' }
TonelMethodWriter >> writeVACategoriesOf: aMethodDefinition on: aWriteStream [

| categories |

((aMethodDefinition hasDefaultVACategories not and: [aMethodDefinition isMonticelloExtension not])
or: [
aMethodDefinition hasDefaultVACategories and: [
aMethodDefinition isMonticelloExtension and: [self parent useMonticelloExtensions]]])
ifTrue: [
aWriteStream << ',' << lineDelimiter << space << '#vaCategories : '.
categories := aMethodDefinition allCategories asSortedCollection.
aWriteStream nextPut: $[.
categories
do: [:each | aWriteStream nextPutAll: (self convertIdentifier: each)]
separatedBy: [aWriteStream nextPut: $,].
aWriteStream nextPut: $]]


(self shouldWriteVACategoriesOf: aMethodDefinition
monticelloExtensionsEnabled: self tonelWriter useMonticelloExtensions)
ifTrue:
[aWriteStream << ',' << lineDelimiter << space << '#vaCategories : '.
categories := aMethodDefinition allCategories asSortedCollection.
aWriteStream nextPut: $[.
categories
do: [:each | aWriteStream nextPutAll: (self convertIdentifier: each)]
separatedBy: [aWriteStream nextPut: $,].
aWriteStream nextPut: $]]
]

{ #category : 'writing',
Expand Down
40 changes: 31 additions & 9 deletions source/TonelWriterModel/TonelWriter.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Class {
'flattenSubApplications',
'writeENVYApps',
'identifiersClass',
'useMonticelloExtensions'
'useMonticelloExtensions',
'ignoresTonelPackageNameMethod'
],
#classVars : [
'LineDelimiter'
Expand Down Expand Up @@ -217,7 +218,8 @@ TonelWriter >> beCanonical [
self convertsSharedPools: true.
self flattenSubApplications: true.
self useMonticelloExtensions: true.
self writeENVYApps: false
self writeENVYApps: false.
self ignoresTonelPackageNameMethod: false
]

{ #category : 'configuring' }
Expand All @@ -227,7 +229,8 @@ TonelWriter >> beVASTOnly [
self convertsSharedPools: false.
self flattenSubApplications: false.
self useMonticelloExtensions: false.
self writeENVYApps: true
self writeENVYApps: true.
self ignoresTonelPackageNameMethod: true.
]

{ #category : 'utility' }
Expand Down Expand Up @@ -341,6 +344,22 @@ TonelWriter >> identifiersClass: aClass [
identifiersClass := aClass
]

{ #category : 'accessing' }
TonelWriter >> ignoresTonelPackageNameMethod [
"Answers whether receiver ignores the _TONEL_packageName method (if defined)
to compute the package name."

^ignoresTonelPackageNameMethod
]

{ #category : 'accessing' }
TonelWriter >> ignoresTonelPackageNameMethod: aBoolean [
"Defines whether receiver will ignore the _TONEL_packageName method (if defined)
to compute the package name."

ignoresTonelPackageNameMethod := aBoolean
]

{ #category : 'initializing',
#vaVisibility : 'private' }
TonelWriter >> initializeOn: aFileSystem [
Expand All @@ -352,7 +371,8 @@ TonelWriter >> initializeOn: aFileSystem [
autoLoad := true.
convertsSharedPools := false.
flattenSubApplications := false.
writeENVYApps := true
writeENVYApps := true.
ignoresTonelPackageNameMethod := false
]

{ #category : 'accessing' }
Expand Down Expand Up @@ -473,11 +493,13 @@ TonelWriter >> writeApplication: anApplication into: aPath rootApp: rootApplicat
| applicationDefinition packageDirectory isRootApp |

isRootApp := anApplication = rootApplication.

applicationDefinition :=
(self flattenSubApplications and: [anApplication isSubApplication])
ifTrue: [TonelWriterSubApplicationDefinition for: anApplication]
ifFalse: [TonelWriterApplicationDefinition for: anApplication].
(self flattenSubApplications and: [anApplication isSubApplication])
ifTrue: [applicationDefinition := TonelWriterSubApplicationDefinition for: anApplication]
ifFalse: [
applicationDefinition := TonelWriterApplicationDefinition for: anApplication.
self ignoresTonelPackageNameMethod
ifTrue: [applicationDefinition setPackageNameFromAppName]
].

packageDirectory :=
self
Expand Down
19 changes: 16 additions & 3 deletions source/TonelWriterModel/TonelWriterApplicationDefinition.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,15 @@ TonelWriterApplicationDefinition >> classDefinitionsOfDefinedClasses [
{ #category : 'initializing',
#vaVisibility : 'private' }
TonelWriterApplicationDefinition >> computeTonelPackageName [

^(application respondsTo: #_TONEL_packageName)
^(application respondsTo: #_TONEL_packageName)
ifTrue: [application _TONEL_packageName]
ifFalse: [application name asString]
ifFalse: [self computeTonelPackageNameFromAppName]
]

{ #category : 'initializing',
#vaVisibility : 'private' }
TonelWriterApplicationDefinition >> computeTonelPackageNameFromAppName [
^application name asString
]

{ #category : 'accessing' }
Expand Down Expand Up @@ -112,6 +117,14 @@ TonelWriterApplicationDefinition >> initializeFor: anApplication [
application := anApplication
]

{ #category : 'initializing',
#vaVisibility : 'private' }
TonelWriterApplicationDefinition >> setPackageNameFromAppName [
"Sets receiver package name from receiver app name."

tonelPackageName := self computeTonelPackageNameFromAppName
]

{ #category : 'accessing' }
TonelWriterApplicationDefinition >> tonelPackageName [

Expand Down
Loading

0 comments on commit 4fb52f7

Please sign in to comment.