RJSwiftMacros is a Swift package that provides macros.
Tip
All macros are used in SwiftUIDemo project. see the LINK.
Warning
MockBuilder macro doesn't work at SwiftUI #Preview macro. Here is a solution.
MockBuilder(numberOfItems: Int): Generates a mock instance and an array of mock data based on your model.MockBuilderhasMockBuilderPropertymember macro, with which you can set the initial value to the desired property.
- Default Usage:
@MockBuilder()generates a one single mock instance. - Customizable: You can also specify parameter like
numberOfItemsif you need to have array of mock items.
MockBuilderProperty<T: Any>(value: T): Sets an initial value to a property within a struct or class.
CodingKeys(codingKeyType: CodingKeyType): Automatically generatesCodingKeysfor a struct based on the specifiedCodingKeyTypewhich has two cases:.camelCaseand.snakeCase.CodingKeyProperty(:_): Allows you to adjust the coding key for a specific property.CodingKeyIgnored(): Allows you to exclude specific properties from the coding process when using theCodingKeysmacro.
Swift Package Manager
To depend on RJSwiftMacros in a SwiftPM package, add the following to your Package.swift.
dependencies: [
.package(url: "https://github.com/rezojoglidze/RJSwiftMacros", from: "<#latest RJSwiftMacros tag#>"),
],To add RJSwiftMacros as a dependency of your Xcode project, go to the Package Dependencies tab of your Xcode project, click the plus button and search for https://github.com/rezojoglidze/RJSwiftMacros
Import the RJSwiftMacros module and apply the macros to your structs and properties:
Usage of MockBuilder:
Macro generates two static properties: mock and mockArray. mockArray count equals numberOfItems value. If you want to set a custom value to the desired property, use @MockBuilderProperty macro. If the custom value granted is prohibited you will get a swift standard warning error. 
To generate only .mock value, you can use @MockBuilder() without any param passing.
Important
Type which participating in the mock building should have @MockBuilder() itself. Below example, we want to have let type: VehicleType mocked version, so VehicleType should have @MockBuilder()
import RJSwiftMacros
@MockBuilder(numberOfItems: 2)
enum VehicleType: String, Decodable {
case car
case bus
case motorcycle
}
@MockBuilder()
struct ExampleAllSupportedTypes {
let intVariable: Int
let int8Variable: Int8
let int16Variable: Int16
let int32Variable: Int32
let int64Variable: Int64
let uintVariable: UInt
let uint8Variable: UInt8
let uint16Variable: UInt16
let uint32Variable: UInt32
let uint64Variable: UInt64
let floatVariable: Float
let float32Variable: Float32
let float64Variable: Float64
let doubleVariable: Double
let decimalVariable: Decimal
let nsDecimalNumberVariable: NSDecimalNumber
let stringVariable: String
let boolVariable: Bool
let dateVariable: Date
let uuidVariable: UUID
let cgPointVariable: CGPoint
let cgRectVariable: CGRect
let cgSizeVariable: CGSize
let cgVectorVariable: CGVector
let cgFloatVariable: CGFloat
let urlVariable: URL
let imageVariable: Image
let colorVariable: Color
let vehicle: VehicleType
let availableTimeSlot: Set<String>
let arrayOfString: [String]
let closureVariable: () -> Void
let tuples: ((String, String, Int), Bool?)
let passthroughSubject: PassthroughSubject<Bool, Never>
let currentValueSubject: CurrentValueSubject<Void, Never>
}
#if DEBUG
public static var mock: ExampleAllSupportedTypes {
.init(
intVariable: 54248,
int8Variable: 92,
int16Variable: 17693,
int32Variable: 1748550107,
int64Variable: 85105,
uintVariable: 75340,
uint8Variable: 221,
uint16Variable: 6060,
uint32Variable: 34678,
uint64Variable: 4145,
floatVariable: 38105.523,
float32Variable: 99252.86,
float64Variable: 57161.44399989151,
doubleVariable: 45860.372174783995,
decimalVariable: 80414.91669166147584,
nsDecimalNumberVariable: 57109.7344805794816,
stringVariable: "Lorem ipsum dolor sit amet",
boolVariable: false,
dateVariable: Date(timeInterval: 77349, since: Date()),
uuidVariable: UUID(),
cgPointVariable: CGPoint(),
cgRectVariable: CGRect(),
cgSizeVariable: CGSize(),
cgVectorVariable: CGVector(),
cgFloatVariable: CGFloat(),
urlVariable: URL(string: "https://www.tiktok.com")!,
imageVariable: Image(systemName: "swift"),
colorVariable: Color.primary.opacity(0.6),
vehicle: VehicleType.mock,
availableTimeSlot: Set<String>(),
arrayOfString: ["in voluptate velit esse cillum dolore"]
"Duis aute irure dolor in reprehenderit",
"Excepteur sint occaecat cupidatat non proident",
"sed do eiusmod tempor incididunt",
],
closureVariable: {},
tuples: (("Duis ac tellus et risus vulputate vehicula", "Duis aute irure dolor in reprehenderit", 42372),false),
passthroughSubject: PassthroughSubject<Bool, Never>(),
currentValueSubject: CurrentValueSubject<Void, Never>(())
)
}
#endif
}To generate both .mock and .mockArray properties use @MockBuilder(numberOfItems: 2). numberOfItems is equal to the count of mock array.
import RJSwiftMacros
@MockBuilder(numberOfItems: 2)
struct Person {
let name: String?
let surname: [String]?
@MockBuilderProperty(value: Color.blue) let color: Color?
@MockBuilderProperty(value: Image(systemName: "swift")) let image: Image?
@MockBuilderProperty(value: "k") let character: Character
#if DEBUG
static var mock: Person {
.init(
name: "Lorna,
surname: ["Clare"],
color: Color.blue.opacity(0.6),
image: Image(systemName: "swift"),
character: "k"
)
}
static var mockArray: [Person ] {
[
.init(
name: "Valentina,
surname: ["Queenie"],
color: Color.blue.opacity(0.6),
image: Image(systemName: "swift"),
character: "k"
),
.init(
name: "Lorna,
surname: ["Bettye"],
color: Color.blue.opacity(0.6),
image: Image(systemName: "swift"),
character: "k"
)
]
}
#endif
}Usage of CodingKeys without codingKeyType param passing generates CodingKeys with .camelCase. CodingKeys macro works only with stored property types. If you want to set custom coding key to the desired param, use @CodingKeyProperty(desired_value). To ignore desired param from CodingKeys enum, use @CodingKeyIgnored().
import RJSwiftMacros
@CodingKeys()
class Car {
let modelColor: String
@CodingKeyProperty("car_model") let model: String
@CodingKeyIgnored() let speed: Int
init(modelColor: String, model: String, speed: Int) {
self.modelColor = modelColor
self.model = model
self.speed = speed
}
enum CodingKeys: String, CodingKey {
case modelColor
case model = "car_model"
}
}CodingKeys generation with .snakeCase.
import RJSwiftMacros
@CodingKeys(codingKeyType: .snakeCase)
struct University {
let name: String
let studentCapacity: Int
let cars: [String]?
var closure: (() -> ())?
static var students: [String] = []
var oldName: String {
"Tbilisi"
}
enum CodingKeys: String, CodingKey {
case name = "name"
case studentCapacity = "student_capacity"
case cars = "cars"
}
}- Swift 5.10 or later
- macOS 10.15 or later
- iOS 15 or later
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
For questions or feedback, feel free to reach out to rezojoglidze7@gmail.com.