Giter VIP home page Giter VIP logo

magritte-swift's Introduction

Magritte-Swift

Extends Magritte with ability to generate Swift class declarations from Smalltalk classes.

Installing

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:

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:

She class>>nameDescription
  <magritteDescription>
  ^ MAStringDescription new
    label: 'Name';
    accessor: #name;
    beSwiftCodable;    "<- makes this property Codable"
    swiftName: #name;  "<- swift name of the property"
    yourself.
    
She class>>balanceDescription
  <magritteDescription>
  ^ MANumberDescription new
    label: 'Balance';
    accessor: #balance;
    beSwiftCodable;
    swiftName: #balance;
    yourself.
    
She class>>seashoreDescription
  <magritteDescription>
  ^ MAToOneRelationDescription new
    label: 'Seashore';
    accessor: #seashore;
    classes: { Seashore };
    beSwiftCodable;
    swiftName: #seashore;
    yourself.
    
She class>>shells
  <magritteDescription>
  ^ MAToManyRelationDescription new
    label: 'Shells';
    accessor: #shells;
    classes: { Shell };
    beSwiftCodable;
    swiftName: #shells;
    yourself.

To retrieve the string declaration of that class in Swift:

She asSwift.

which should produce:

import Foundation

class 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:

She class>>nameDescription
  <magritteDescription>
  ^ 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:

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:

balanceDescription
  <magritteDescription>
  ^ 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:

class She : Codable {
	var seashore: Seashore?
	var shells: [Shell]?
	var name: String
	private(set) var balance: Double = 0

	init(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:

MyClass class>>myPropertyDescription
  ^ MANumberDescription new
    swiftName: #foo;
    "let foo = ... as opposed to: let foo: SomeType = ..."
    swiftType: SwiftInferredType;
    " let foo = ?"
    swiftDefaultValue:
      "create initialization expression MyType<Generic>()"
      (MASwiftInitializingExpression new
        type: (MASwiftType new
	  name: #MyType;
	  genericParameters: #(#Generic);
	  yourself);
	yourself);
    "let as opposed to var"
    beSwiftConstant;
    yourself

That should produce:

let foo = MyType<Generic>()

How do I make this generate Realm 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:

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:

MyModel subclass: #MyFriend
	instanceVariableNames: 'nickname'
	classVariableNames: ''
	package: 'MyPackage'
	
MyFriend class>>nicknameDescription
  <magritteDescription>
  ^ MAStringDescription new
    label: 'Nickname';
    accessor: #nickname;
    beSwiftCodable;
    swiftName: #nickname;
    swiftDeclarationModifiers: #(#'@objc' #dynamic);
    yourself

MyModel asSwift:

import Foundation
import RealmSwift

class MyModel : Object {

}

MyFriend asSwift:

import Foundation
import RealmSwift

class MyFriend : MyModel, Codable {
  @objc dynamic var nickname: String?

  enum CodingKeys : String, CodingKey {
    case nickname
  }
}

That's it...

magritte-swift's People

Contributors

grype avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.