Sourcery Tutorial: Generating Swift code for iOS

What if someone could write boilerplate Swift code for you? In this Sourcery tutorial, you’ll learn how to make Sourcery do just that! By Chris Wagner.

Leave a rating/review
Save for later
Share

If you’re like most developers, writing the same thing over and over can get pretty boring. You might find yourself doing the same thing five different ways purely out of a need for variety.

While it’s not a bad idea to find better solutions to the same problem, it is a bad idea to have these solutions littered across your projects. The worst thing you can do to your project is muddle the underlying architecture principles with various ideas.

So where does that leave you? Writing boring boilerplate code? Maybe you can think up some super generic magically dynamic framework to do the work for you. But three months from now, you’ll try to untangle your undocumented magic code and have no idea what is going on.

So, what if there was a way to have someone write the tedious boilerplate code for you, do it to spec with 100% accuracy — and work for free?

Sourcery is an open source tool that generates Swift code from predefined templates. But it’s not simply a dumb macro that spits out source files based on a set of rules. It’s a smart tool that scans your source code and uses that information in your templates, which means you can create very detailed solutions.

This Sourcery tutorial is aimed at intermediate Swift developers. Since you will be writing templates to generate Swift code, you should have a solid understanding of the Swift language, Xcode, and some experience using the command line via Terminal.

Getting Started

First and foremost, install Sourcery. There are a number of ways to do this, and they’re described under the Installing section of the project’s Readme on GitHub.

I opted to install the binary from the project’s Releases page.

Once the binary is downloaded and extracted you can simply copy the contents of the bin directory to /usr/local/bin. Given that /usr/local/bin is on your $PATH you will be able to run Sourcery by typing sourcery from any directory in Terminal.

Once you have Sourcery installed run sourcery --help from Terminal to verify it is working, you should see something like the following:

sourcery --help result

The next step is to download the starter project. Unzip the downloaded file and open Brew Guide.xcodeproj.

This Sourcery tutorial has an example app that lets you browse data from the Brew Guide at brewerydb.com. You’ll require an API key to access the data, but it’s a quick, free, and painless process.

Note: This Sourcery tutorial will get you going writing templates, and generating source code. The sample app is not the main focus of the tutorial; rather, it’s an example to show how Sourcery can be applied to a project. At the end of the Sourcery tutorial you will be sent off on your own to do further studying of provided Sourcery templates and the sample app’s source code.

BreweryDB API Key

To register for an API key, head over to the Developer section of the site. Click Create An Account and fill out the registration form. You will need to agree to their terms of service. After agreeing, you’ll be taken to your account screen where you can switch to the My Apps section and click Register A New App.

Registering an app on BreweryDB

Registering a new app requires you to fill in an App Name, Description, Website and Platform. Enter anything you want for these fields, or use the following:

Registering an app on BreweryDB

Once you complete the registration form, you’ll be taken back to your account screen which will list the newly registered app along with its API Key.

BreweryDB API key location

Copy the API Key to your clipboard and go back to Xcode. Open StylesTableViewController.swift. At the top you will find an instance variable named apiManager initialized inline. Replace YOUR_API_KEY with the key in your clipboard.

At this point you’re all set to continue with the Sourcery tutorial. Running the app won’t yield any interesting results, as you have yet to to the legwork to retrieve data from the BreweryDB API!

Sourcery 101

Before diving in, it’s a good idea to get a handle on the basics of Sourcery. The Sourcery templating system is by and far the most important aspect to understand when using Sourcery.

There are three types of template languages that you can choose from: Stencil, Swift, and JavaScript. For this tutorial, the focus will be on Stencil. While it may seem obvious to go with Swift, I personally felt the Stencil templating language was easier to write and better documented. It simply feels more mature for this task.

To get your feet wet, you’ll write a template that generates the requirements for the Swift Equatable protocol.

Open the playground named AutoEquatable.playground under the appetizer directory in the downloaded starter project. With the playground opened, open the Navigator pane if it is not already by pressing ⌘+0 or going to View, Navigators, Show Navigator. Once the Navigator is visible, twist open the Sources directory and open Person.swift.

Contents of Person.swift

This file defines a basic struct for a Person type. Your goal is to add Equatable conformance using Sourcery.

The first step is to create a new protocol that will be used to effectively annotate the Person type so Sourcery knows which types to make Equatable. Define a new protocol below import Foundation:

protocol AutoEquatable { }

This is a requirement-free protocol. Now mark Person as a conformer of the AutoEquatable protocol:

public struct Person: AutoEquatable {
    public let name: String
    public let age: Int
    public let gender: Gender
    
    public init(name: String, age: Int, gender: Gender) {
        self.name = name
        self.age = age
        self.gender = gender
    }
}

If you’re confused, don’t worry; the reasoning is coming.

Now, using your favorite text editor create an empty text file named AutoEquatable.stencil in the same directory as AutoEquatable.playground. Add the following Stencil template code to the file and save it.

{% for type in types.implementing.AutoEquatable %}
// hello, sourcery!
{% endfor %}

This probably looks foreign if you’ve never used Stencil. This tells Sourcery to search all of the source files you’ve provided for types that implement AutoEquatable. For each type found, it will print // hello, sourcery!. The important thing to note is that anything between {% %} is interpreted as Stencil code; everything in the brackets needs to “compile” and follow the Stencil syntax requirements. Anything outside of the brackets, however, is printed straight to the generated file.

Using Terminal, change to the same directory as the AutoEquatable.playground file and run the following command:

sourcery --sources AutoEquatable.playground/Sources \
--output AutoEquatable.playground/Sources \
--templates . \
--watch

There are a few flags here to tell Sourcery what to do:

  • --sources: Scan for .swift files under AutoEquatable.playground/Sources.
  • --output: Put generated files under AutoEquatable.playground/Sources.
  • --templates: Find all template files in the current directory.
  • --watch: Continue running and generating files anytime a template or source file changes. You must terminate the process when finished using CTRL+C.

Go back to the Xcode Playground, and you should see a new file under Sources named AutoEquatable.generated.swift. Open it up.

Contents of AutoEquatable.generated.swift

Great work! You’ve generated your first file. Now switch back to your text editor with AutoEquatable.stencil open.

If you can, arrange your windows side-by-side so that you’re viewing both the stencil file and AutoEquatable.generated.swift in Xcode Playgrounds. If not, be ready to switch back and forth between the two. As you make changes in the stencil template, you will see updates in the generated file. This is incredibly helpful to catch errors quickly.

Update the stencil template with the following:

{% for type in types.implementing.AutoEquatable %}
extension {{ type.name }}: Equatable {
  
}
{% endfor %}

This tells Sourcery to create an extension for each type implementing AutoEquatable, and mark the type as a conformer of Equatable. What you may notice is that this looks like Swift — and it is! You’re simply writing Swift code inline with the Stencil templating language.

The non-Swift part is {{ type.name }}, which prints out the value of the Stencil property between the brackets; in this case, the type’s name. Save the stencil template and go back to AutoEquatable.generated.swift.

Contents of AutoEquatable.generated.swift

There’s a compilation error, but… wow. Are you feeling powerful yet? Isn’t it awesome how you didn’t tell Sourcery anything about Person, but it was able to pick it up from the AutoEquatable protocol and print its name right there in the generated file? Like magic… err, sorcery!

Get your wand and wizard hat ready, because you’re in for a treat.

Go back to AutoEquatable.stencil and add the following to your template within the brackets of the extension.

  public static func ==(lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool {
    {% for var in type.variables %}
    guard lhs.{{ var.name }} == rhs.{{ var.name }} else { return false }
    {% endfor %}

    return true
  }

Aside from a few places, this is mostly Swift code. {{ type.name }} is used again in a number of places, and another for-loop is defined to iterate over the type’s variables. The syntax of Stencil for-loops is very similar to Swift for-loops.

Jump back to the generated file to see what happened.

Contents of AutoEquatable.generated.swift

Whoa — all that tedious boilerplate code was magically written for you!

Go back to the main playground page by clicking on AutoEquatable in the navigator, and uncomment the equality tests to verify your generated code is working.

If you followed along the Sourcery tutorial correctly, you should see equality tests passing and failing correctly.

Nice work!

Chris Wagner

Contributors

Chris Wagner

Author

Marin Bencevic

Tech Editor

Chris Belanger

Editor

Essan Parto

Final Pass Editor

Andy Obusek

Team Lead

Over 300 content creators. Join our team.