What is Sourcery?Sourcery is one of the most popular Swift code generation tools. It uses SwiftSyntax[1] and aims to save developers time by automatically generating boilerplate code. Sourcery scans a set of input files and then, with the help of templates, automatically generates the Swift code defined in the templates. ExampleConsider a protocol that provides a public API for a camera session service: protocol Camera { When unit testing this new Camera service, we want to make sure that the AVCaptureSession is not actually created. We just want to confirm that the camera service is called correctly by the system under test (SUT), rather than testing the camera service itself. Therefore, it makes sense to create a mock implementation of the protocol with empty methods and a set of variables to help us with unit testing and assert that the correct calls were made. This is a very common scenario in software development and can also be a bit tedious if you have ever maintained a large code base with a lot of unit tests. Well, don’t worry! Sourcery has you covered! ⭐️ It has a template called AutoMockable[2] that will generate mock implementations for any protocol that conforms to the AutoMockable protocol in the input file.
Now, we make Camera conform to AutoMockable. The only purpose of this interface is to act as a target for Sourcery to find and generate code from. import UIKit At this point, you can run the Sourcery command on the above input file, specifying the path to the AutoMockable template: sourcery -- sources Camera . swift -- templates AutoMockable . stencil -- output . This article configures the Sourcery plugin by providing a .sourcery.yml file. If a configuration file is provided or Sourcery can find one, any command line arguments that conflict with its values will be ignored. If you want to learn more about configuration files, the Sourcery repo has a section on the topic [4]. After the command is executed, a file with the template name plus .generated.swift as the suffix will be generated in the output directory. In this example, it is ./AutoMockable.generated.swift: // Generated using Sourcery 1.8.2 — https://github.com/krzysztofzablocki/Sourcery The file above (AutoMockable.generated.swift) contains what you would expect from a mock: empty methods to implement conformance to the target protocol, and a set of variables to check if those protocol methods were called. And the best part is… Sourcery wrote it all for you! 🎉 How to run Sourcery?How to run Sourcery with Swift package? At this point you might be wondering how and what to run Sourcery from within a Swift package. You can do it manually and drag the files into the package, or run the script from the command line in the package directory. But there are two built-in ways to run executables from a Swift package:
In this article, I'll introduce the Sourcery command-line plugin, but I'm already working on a second part where I'll create a build tool plugin, which presents a number of interesting challenges. Creating a plugin package Let's first create an empty package and get rid of the test and other folders we don't need right now. Then we can create a new plugin In order for consumers to use this plugin, it also needs to be defined as a product: // swift-tools-version: 5.6 Let's look at the code above step by step:
I know I didn’t cover some of the concepts above in detail, but if you want to learn more about command plugins, here’s a great article by Tibor Bödecs⭐. If you also want to learn more about binary targets (files) in Swift Packages, I also have a post Binary Targets in Swift Packages Today. Writing pluginsNow that the package is created, it’s time to write some code! We start by creating a file called SourceryCommand.swift under Plugins/SourceryCommand and then adding a struct of the CommandPlugin protocol, which will serve as the entry point for the plugin: import PackagePlugin Then we write the implementation for the command: func performCommand ( context : PluginContext , arguments : [ String ]) async throws { Let's take a closer look at the code above:
That's it! Now let's use it Using the (plugin) packageConsider a user who is using a plugin that pulls in a dependency into their Package.swift file: // swift-tools-version: 5.6 Note that unlike build tool plugins, command plugins do not need to be applied to any target, as they need to be run manually. The user simply used the AutoMockable template above (which can be found under Sources/SourceryPluginSample/SourceryTemplates ), matching the example shown earlier in this article: protocol AutoMockable {} As required by the plugin, the user also provides a .sourcery.yml configuration file located in the SourceryPluginSample directory: sources : Run CommandThe user is all set up, but how do they run the package now? 🤔 There are two ways: Command LineOne way to run plugins is from the command line. A list of available plugins for a particular package can be retrieved by running swift package plugin --list from the package directory. A package can then be selected from the list and executed by running swift package <command's verb> , in this particular case, running: swift package sourcery-code-generation . Note that because this package requires special permissions, --allow-writing-to-package-directory must be used with the command. At this point, you might be thinking, why would I bother writing a plugin that I still have to run from the command line when I can do the same job in a few lines of bash with a simple script? Well, let’s take a look at what’s coming in Xcode 14 and you’ll see why I’m an advocate for writing plugins 📦. XcodeThis is the most exciting way to run the command plugin, but unfortunately, it is only available in Xcode 14. So if you need to run commands but are not using Xcode 14 yet, see the Command Line section. If you happen to be using Xcode 14, you can execute any command of a package by right-clicking the package in File Explorer, finding the plugin you want to execute from the list, and clicking it. Next stepThis is the initial implementation of the plugin. I will be looking into how to improve it and make it more robust. As always, I am very committed to building publicly and making everything in my articles open source so anyone can submit issues or create PRs with any improvements or fixes. This is no different 😀, here is the link to the public repository. Also, if you liked this post, stay tuned for the upcoming Part 2, where I will make a Sourcery build tool plugin. I know it doesn’t sound like much, but it’s not an easy task! References[1] SwiftSyntax: https://github.com/apple/swift-syntax. [2] AutoMockable: https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/AutoMockable.stencil. [3] Double test: https://en.wikipedia.org/wiki/Test_double. [4] repo: https://github.com/krzysztofzablocki/Sourcery/blob/master/guides/Usage.md#configuration-file. |
<<: Apple iOS 16.2 / iPadOS 16.2 Developer Preview Beta Released: New Borderless Notes App
>>: Let's talk about the three new font width styles in iOS 16
The richness of Guangxi More than you think You m...
The Chongqing Meteorological Bureau predicts that...
It’s the Lantern Festival again. Have you thought...
After the Double Eleven “100 billion” shopping ca...
Have you ever seen this kind of Yin-Yang grapefru...
[[171480]] In addition to script style files, mos...
Looking at the development history of the daily c...
Optimizing your website must start from the basic...
Today, we have specially compiled this article fo...
China Science and Technology News Network, Decemb...
In fact, there are many small businesses in rural...
After nearly two years of release and various twis...
When companies are doing brand marketing , it is ...
Compiled by Zhou Shuyi Can Alzheimer's diseas...
The name and domain name of the website cannot be...