Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/grype/magritte-swift
Extends Magritte with ability to generate Swift class declarations from Smalltalk classes
https://github.com/grype/magritte-swift
code-generator magritte metamodeling pharo pharo-smalltalk realmswift smalltalk swift
Last synced: 19 days ago
JSON representation
Extends Magritte with ability to generate Swift class declarations from Smalltalk classes
- Host: GitHub
- URL: https://github.com/grype/magritte-swift
- Owner: grype
- License: mit
- Created: 2018-09-06T07:55:20.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2020-10-05T05:15:33.000Z (over 4 years ago)
- Last Synced: 2024-11-09T20:41:20.456Z (3 months ago)
- Topics: code-generator, magritte, metamodeling, pharo, pharo-smalltalk, realmswift, smalltalk, swift
- Language: Smalltalk
- Size: 76.2 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Magritte-Swift
Extends Magritte with ability to generate Swift class declarations from Smalltalk classes.
## Installing
```smalltalk
Metacello new
baseline: 'MagritteSwift';
repository: 'github://grype/Magritte-Swift';
onConflictUseLoaded;
load.
```Magritte-Swift depends on Magritte3, which is still tied to Seaside on smalltalkhub. So if you've loaded Seaside from GitHub, be sure to include #onConflictUseLoaded, as indicated above...
## Using
As an example, let's start with a simple class that defines a few basic types of properties:
```smalltalk
GRObject subclass: #She
uses: TMASwiftDescribing
instanceVariableNames: 'name balance seashore shells'
classVariableNames: ''
poolDictionaries: ''
category: 'SheSellsSeashellsByTheSeashore'!
```After generating accessors for the ivars, let's add magritte descriptions for those properties:
```smalltalk
She class>>nameDescription
^ MAStringDescription new
label: 'Name';
accessor: #name;
beSwiftCodable; "<- makes this property Codable"
swiftName: #name; "<- swift name of the property"
yourself.
She class>>balanceDescription
^ MANumberDescription new
label: 'Balance';
accessor: #balance;
beSwiftCodable;
swiftName: #balance;
yourself.
She class>>seashoreDescription
^ MAToOneRelationDescription new
label: 'Seashore';
accessor: #seashore;
classes: { Seashore };
beSwiftCodable;
swiftName: #seashore;
yourself.
She class>>shells
^ MAToManyRelationDescription new
label: 'Shells';
accessor: #shells;
classes: { Shell };
beSwiftCodable;
swiftName: #shells;
yourself.
```To retrieve the string declaration of that class in Swift:
```smalltalk
She asSwift.
```which should produce:
```swift
import Foundationclass She : Codable {
var seashore: Seashore?
var shells: [Shell]?
var name: String?
var balance: NSNumber?enum CodingKeys : String, CodingKey {
case seashore
case shells
case name
case balance
}
}
```### Required attributes
Now let's say that the #name is a required attribute:
```smalltalk
She class>>nameDescription
^ MAStringDescription new
label: 'Name';
accessor: #name;
required: true; "<-- Adding required field"
beSwiftCodable;
swiftName: #name;
yourself.
```That would produce a slightly different swift declaration of the class:
```swift
class She : Codable {
var seashore: Seashore?
var shells: [Shell]?
var name: String
var balance: NSNumber?init(name aName: String) {
name = aName
}enum CodingKeys : String, CodingKey {
case seashore
case shells
case name
case balance
}
}
```Notice that the property is no longer optional and an init() method declaration was added...
### Numbers
By default, MagritteSwift will use NSNumber as the numeric type. Let's try change that to a Double, making it required and initialized to a value:
```smalltalk
balanceDescription
^ MANumberDescription new
label: 'Balance';
accessor: #balance;
beSwiftCodable;
swiftName: #balance;
swiftType: #Double; "<- Specify name of swift type"
beRequired; "<- Required"
swiftDefaultValue: 0; "<- Initial value"
swiftDeclarationModifiers: #(#'private(set)'). "<- declaration modifiers is just a collection of swift source strings"
yourself
```The resulting swift declaration should now look like this:
```swift
class She : Codable {
var seashore: Seashore?
var shells: [Shell]?
var name: String
private(set) var balance: Double = 0init(name aName: String) {
name = aName
}enum CodingKeys : String, CodingKey {
case seashore
case shells
case name
case balance
}
}
```A more fine-grained declaration can be seen here:
```smalltalk
MyClass class>>myPropertyDescription
^ MANumberDescription new
swiftName: #foo;
"let foo = ... as opposed to: let foo: SomeType = ..."
swiftType: SwiftInferredType;
" let foo = ?"
swiftDefaultValue:
"create initialization expression MyType()"
(MASwiftInitializingExpression new
type: (MASwiftType new
name: #MyType;
genericParameters: #(#Generic);
yourself);
yourself);
"let as opposed to var"
beSwiftConstant;
yourself
```That should produce:
```swift
let foo = MyType()
```### How do I make this generate [Realm](https://realm.io) models?
Generation of class description for Realm models requires a few tweaks, and the easiest way to accomplish that is to use `TMASwiftRealmDescribing` trait, as opposed to `TMASwiftDescribing`:
```smalltalk
GRObject subclass: #MyModel
uses: TMASwiftRealmDescribing
instanceVariableNames: ''
classVariableNames: ''
package: 'MyPackage'
```Better yet, let's use that as the base class for all of our models, which allows us to create extensions in Swift, that are applicable to all models:
```smalltalk
MyModel subclass: #MyFriend
instanceVariableNames: 'nickname'
classVariableNames: ''
package: 'MyPackage'
MyFriend class>>nicknameDescription
^ MAStringDescription new
label: 'Nickname';
accessor: #nickname;
beSwiftCodable;
swiftName: #nickname;
swiftDeclarationModifiers: #(#'@objc' #dynamic);
yourself
````MyModel asSwift`:
```swift
import Foundation
import RealmSwiftclass MyModel : Object {
}
````MyFriend asSwift`:
```swift
import Foundation
import RealmSwiftclass MyFriend : MyModel, Codable {
@objc dynamic var nickname: String?enum CodingKeys : String, CodingKey {
case nickname
}
}
```That's it...