Skip to content

Instantly share code, notes, and snippets.

@AliSoftware
Last active May 17, 2017 20:46
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save AliSoftware/c2e1bf8c7fb0f5e742609c9516780123 to your computer and use it in GitHub Desktop.
Save AliSoftware/c2e1bf8c7fb0f5e742609c9516780123 to your computer and use it in GitHub Desktop.
UIKonf talk - CodeGeneration in Swift - Links & Snippets

This is a reference of all the useful links to follow my UIKonf'17 talk on Code Generation in Swift

label.font =
FontFamily.Avenir.blackOblique.font(size: 18)
label.text =
L10n.homeGreetings("UIKonf", 1, "Berlin").string
swiftgen fonts "…/Fonts" …
swiftgen strings "…/Localizable.strings" …
swiftgen images "…/Assets.xcassets" …
swiftgen storyboards "$PROJECT_DIR" …
swiftgen colors "…/colors.xml" …
enum FontFamily {
enum Avenir: String {
case black = "Avenir-Black"
case blackOblique = "Avenir-BlackOblique"
case oblique = "Avenir-Oblique"
case roman = "Avenir-Roman"
func font(size: CGFloat) -> UIFont! {
return Font(font: self.rawValue, size: size)
}
}
}
enum L10n {
/// Welcome to %@, the #%d iOS conference in %@!
case homeGreetings(String, Int, String)
/// Dismiss changes?
case editAlertTitle
/// Changes have been made to the image « %@ »
case editAlertMessage(String)
/// Save
case editAlertSave
/// Dismiss
case editAlertDismiss
}
enum Assets {
static let apple = UIImage(named: "Apple")
static let banana = UIImage(named: "Banana")
static let orange = UIImage(named: "Orange")
static let somePears = UIImage(named: "Some-Pears")
}
// vs
enum Assets: String {
case apple = "Apple"
case banana = "Banana"
case orange = "Orange"
case somePears = "Some-Pears"
var image: UIImage {
return UIImage(named: self.rawValue)
}
}
enum Assets {
{% for image in images %}
static let {{image|swiftIdentifier}}
 = UIImage(named: "{{image}}")
{% endfor %}
}
enum Assets: String {
{% for image in images %}
case {{image|swiftIdentifier|lowerFirstWord}} = "{{image}}"
{% endfor %}
var image: UIImage {
return UIImage(asset: self)
}
}
extension UIImage {
convenience init!(asset: Assets) {
self.init(named: asset.rawValue)
}
}
struct ImageInfo: Equatable {
let title: String
let author: String
let date: Date
}
func == (lhs: ImageInfo, rhs: ImageInfo) -> Bool {
guard lhs.title == rhs.title else { return false }
guard lhs.author == rhs.author else { return false }
guard lhs.date == rhs.date else { return false }
return true
}
struct ImageInfo: Equatable {
let title: String
let author: String
let date: Date
let cameraModel: String
let kind: ImageKind
}
func == (lhs: ImageInfo, rhs: ImageInfo) -> Bool {
guard lhs.title == rhs.title else { return false }
guard lhs.author == rhs.author else { return false }
guard lhs.date == rhs.date else { return false }
return true
}
// Template:
There are {{types.all.count}} types in this code, including:
- {{types.enums.count}} enums
- {{types.structs.count}} structs
- {{types.classes.count}} classes
// Generated Code:
There are 22 types in this code, including:
- 11 enums
- 1 structs
- 6 classes
struct ImageInfo {
let title: String
let author: String
let date: Date
}
extension ImageInfo: Equatable {}
func == (lhs: ImageInfo, rhs: ImageInfo) -> Bool {
guard lhs.title == rhs.title
else { return false }
guard lhs.author == rhs.author
else { return false }
guard lhs.date == rhs.date
else { return false }
return true
}
{% for type in types.implementing.AutoEquatable %}
extension {{ type.name }}: Equatable {}
func == (lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool {
{% for variable in type.storedVariables %}
 guard lhs.{{ variable.name }} == rhs.{{ variable.name }}
 else { return false }
{% endfor %}
return true
}
{% endfor %}
struct ImageInfo : AutoEquatable {
let title: String
let author: String
let date: Date
}
// + `sourcery/bin/sourcery`
// = Magic
struct Contact {
let id: String
let firstName: String
let lastName: String
}
extension Contact: JSONDeserializable {
init?(json: [String: Any]) {
self.id = json["id"] as? String
self.firstName = json["first_name"] as? String
self.lastName = json["last_name"] as? String
self.dateOfBirth = (json["dob"] as? String)
.flatMap(JSONDateFormatter.date(from:))
self.avatar = (json["avatar"] as? [String: Any])
.flatMap(Avatar.init(json:))
}
}
{% for type in types.implementing.AutoJSONDeserializable %}
extension {{ type.name }}: JSONDeserializable {
init?(json: [String: Any]) {
{% for prop in type.storedVariables %}
// ?
{% endfor %}
}
}
{% endfor %}
// daemon mode to write your templates live:
$ sourcery/bin/sourcery --watch
// Template (extract)
{% for prop in type.storedVariables %}
self.{{prop.name}} = json["{{prop.name}}"] as? {{prop.typeName}}
{% endfor %}
// Generated code
self.id = json["id"] as? String
self.firstName = json["firstName"] as? String
self.lastName = json["lastName"] as? String
// Your code
struct Contact {
let id: String
// sourcery: JSONKey = "first_name"
let firstName: String
// sourcery: JSONKey = "last_name"
let lastName: String
}
// How to reference that in your template:
{% for prop in type.storedVariables %}
json["{{ prop.annotations.JSONKey |default:prop.name }}"]
{% endfor %}
// Template
{% for prop in type.storedVariables %}
self.{{prop.name}} = json["{{ prop.annotations.JSONKey |default:prop.name }}"] as? {{prop.typeName}}
{% endfor %}
// Generated Code
self.id = json["id"] as? String
self.firstName = json["first_name"] as? String
self.lastName = json["last_name"] as? String
struct Customer: AutoEquatable, AutoJSONDeserializable {
… // 15 properties
}
struct Product: AutoEquatable, AutoJSONDeserializable {
… // 28 properties
}
struct Cart: AutoEquatable, AutoJSONDeserializable {
… // 12 properties
}
struct Order: AutoEquatable, AutoJSONDeserializable {
… // 17 properties
}
enum ShippingOption: AutoCases {
… // 9 cases
}
// sourcery: TypeErase = PokemonType
protocol Pokemon {
associatedtype PokemonType
func attack(move: PokemonType)
}
// + github.com/AliSoftware/SourceryTemplates
// =
let list: [AnyPokemon<Thunder>] = …
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment