{"id":19272656,"url":"https://github.com/grype/magritte-swift","last_synced_at":"2026-05-14T08:41:39.136Z","repository":{"id":77659496,"uuid":"147638043","full_name":"grype/Magritte-Swift","owner":"grype","description":"Extends Magritte with ability to generate Swift class declarations from Smalltalk classes","archived":false,"fork":false,"pushed_at":"2020-10-05T05:15:33.000Z","size":78,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-05T13:42:33.434Z","etag":null,"topics":["code-generator","magritte","metamodeling","pharo","pharo-smalltalk","realmswift","smalltalk","swift"],"latest_commit_sha":null,"homepage":null,"language":"Smalltalk","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grype.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-06T07:55:20.000Z","updated_at":"2020-10-05T05:15:35.000Z","dependencies_parsed_at":"2023-03-22T02:33:07.918Z","dependency_job_id":null,"html_url":"https://github.com/grype/Magritte-Swift","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grype%2FMagritte-Swift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grype%2FMagritte-Swift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grype%2FMagritte-Swift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grype%2FMagritte-Swift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grype","download_url":"https://codeload.github.com/grype/Magritte-Swift/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240378874,"owners_count":19792038,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generator","magritte","metamodeling","pharo","pharo-smalltalk","realmswift","smalltalk","swift"],"created_at":"2024-11-09T20:37:31.315Z","updated_at":"2026-05-14T08:41:34.101Z","avatar_url":"https://github.com/grype.png","language":"Smalltalk","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Magritte-Swift\n\nExtends Magritte with ability to generate Swift class declarations from Smalltalk classes.\n\n## Installing\n\n```smalltalk\nMetacello new\n\tbaseline: 'MagritteSwift';\n\trepository: 'github://grype/Magritte-Swift';\n\tonConflictUseLoaded;\n\tload.\n```\n\nMagritte-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...\n\n## Using\n\nAs an example, let's start with a simple class that defines a few basic types of properties:\n\n```smalltalk\nGRObject subclass: #She\n  uses: TMASwiftDescribing\n  instanceVariableNames: 'name balance seashore shells'\n  classVariableNames: ''\n  poolDictionaries: ''\n  category: 'SheSellsSeashellsByTheSeashore'!\n```\n\nAfter generating accessors for the ivars, let's add magritte descriptions for those properties:\n\n```smalltalk\nShe class\u003e\u003enameDescription\n  \u003cmagritteDescription\u003e\n  ^ MAStringDescription new\n    label: 'Name';\n    accessor: #name;\n    beSwiftCodable;    \"\u003c- makes this property Codable\"\n    swiftName: #name;  \"\u003c- swift name of the property\"\n    yourself.\n    \nShe class\u003e\u003ebalanceDescription\n  \u003cmagritteDescription\u003e\n  ^ MANumberDescription new\n    label: 'Balance';\n    accessor: #balance;\n    beSwiftCodable;\n    swiftName: #balance;\n    yourself.\n    \nShe class\u003e\u003eseashoreDescription\n  \u003cmagritteDescription\u003e\n  ^ MAToOneRelationDescription new\n    label: 'Seashore';\n    accessor: #seashore;\n    classes: { Seashore };\n    beSwiftCodable;\n    swiftName: #seashore;\n    yourself.\n    \nShe class\u003e\u003eshells\n  \u003cmagritteDescription\u003e\n  ^ MAToManyRelationDescription new\n    label: 'Shells';\n    accessor: #shells;\n    classes: { Shell };\n    beSwiftCodable;\n    swiftName: #shells;\n    yourself.\n```\n\nTo retrieve the string declaration of that class in Swift:\n\n```smalltalk\nShe asSwift.\n```\n\nwhich should produce:\n\n```swift\nimport Foundation\n\nclass She : Codable {\n\tvar seashore: Seashore?\n\tvar shells: [Shell]?\n\tvar name: String?\n\tvar balance: NSNumber?\n\n\tenum CodingKeys : String, CodingKey {\n\t\tcase seashore\n\t\tcase shells\n\t\tcase name\n\t\tcase balance\n\t}\n}\n```\n\n### Required attributes\n\nNow let's say that the #name is a required attribute:\n\n```smalltalk\nShe class\u003e\u003enameDescription\n  \u003cmagritteDescription\u003e\n  ^ MAStringDescription new\n    label: 'Name';\n    accessor: #name;\n    required: true; \"\u003c-- Adding required field\"\n    beSwiftCodable;\n    swiftName: #name;\n    yourself.\n```\n\nThat would produce a slightly different swift declaration of the class:\n\n```swift\nclass She : Codable {\n\tvar seashore: Seashore?\n\tvar shells: [Shell]?\n\tvar name: String\n\tvar balance: NSNumber?\n\n\tinit(name aName: String) {\n\t\tname = aName\n\t}\n\n\tenum CodingKeys : String, CodingKey {\n\t\tcase seashore\n\t\tcase shells\n\t\tcase name\n\t\tcase balance\n\t}\n}\n```\n\nNotice that the property is no longer optional and an init() method declaration was added...\n\n### Numbers\n\nBy 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:\n\n```smalltalk\nbalanceDescription\n  \u003cmagritteDescription\u003e\n  ^ MANumberDescription new\n    label: 'Balance';\n    accessor: #balance;\n    beSwiftCodable;\n    swiftName: #balance;\n    swiftType: #Double;    \"\u003c- Specify name of swift type\"\n    beRequired;            \"\u003c- Required\"\n    swiftDefaultValue: 0;  \"\u003c- Initial value\"\n    swiftDeclarationModifiers: #(#'private(set)'). \"\u003c- declaration modifiers is just a collection of swift source strings\"\n    yourself\n```\n\nThe resulting swift declaration should now look like this:\n\n```swift\nclass She : Codable {\n\tvar seashore: Seashore?\n\tvar shells: [Shell]?\n\tvar name: String\n\tprivate(set) var balance: Double = 0\n\n\tinit(name aName: String) {\n\t\tname = aName\n\t}\n\n\tenum CodingKeys : String, CodingKey {\n\t\tcase seashore\n\t\tcase shells\n\t\tcase name\n\t\tcase balance\n\t}\n}\n```\n\nA more fine-grained declaration can be seen here:\n\n```smalltalk\nMyClass class\u003e\u003emyPropertyDescription\n  ^ MANumberDescription new\n    swiftName: #foo;\n    \"let foo = ... as opposed to: let foo: SomeType = ...\"\n    swiftType: SwiftInferredType;\n    \" let foo = ?\"\n    swiftDefaultValue:\n      \"create initialization expression MyType\u003cGeneric\u003e()\"\n      (MASwiftInitializingExpression new\n        type: (MASwiftType new\n\t  name: #MyType;\n\t  genericParameters: #(#Generic);\n\t  yourself);\n\tyourself);\n    \"let as opposed to var\"\n    beSwiftConstant;\n    yourself\n```\n\nThat should produce:\n\n```swift\nlet foo = MyType\u003cGeneric\u003e()\n```\n\n### How do I make this generate [Realm](https://realm.io) models?\n\nGeneration 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`:\n\n```smalltalk\nGRObject subclass: #MyModel\n  uses: TMASwiftRealmDescribing\n  instanceVariableNames: ''\n  classVariableNames: ''\n  package: 'MyPackage'\n```\n\nBetter 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:\n\n```smalltalk\nMyModel subclass: #MyFriend\n\tinstanceVariableNames: 'nickname'\n\tclassVariableNames: ''\n\tpackage: 'MyPackage'\n\t\nMyFriend class\u003e\u003enicknameDescription\n  \u003cmagritteDescription\u003e\n  ^ MAStringDescription new\n    label: 'Nickname';\n    accessor: #nickname;\n    beSwiftCodable;\n    swiftName: #nickname;\n    swiftDeclarationModifiers: #(#'@objc' #dynamic);\n    yourself\n```\n\n`MyModel asSwift`:\n\n```swift\nimport Foundation\nimport RealmSwift\n\nclass MyModel : Object {\n\n}\n```\n\n`MyFriend asSwift`:\n\n```swift\nimport Foundation\nimport RealmSwift\n\nclass MyFriend : MyModel, Codable {\n  @objc dynamic var nickname: String?\n\n  enum CodingKeys : String, CodingKey {\n    case nickname\n  }\n}\n```\n\nThat's it...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrype%2Fmagritte-swift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrype%2Fmagritte-swift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrype%2Fmagritte-swift/lists"}