A Swift macro that generates a convenient enumName
method for enum types, returning the case name as a string with optional associated values.
Add this package to your project using Swift Package Manager. In Xcode, go to File > Add Package Dependencies and enter:
https://github.com/idolize/enum-names-macro.git
Or add it to your Package.swift
:
dependencies: [
.package(url: "https://github.com/idolize/enum-names-macro.git", from: "1.0.1")
]
Import the module and apply the @NamedEnum
macro to your enum:
import EnumNames
@NamedEnum
enum NetworkError {
case timeout
case invalidURL(String)
case serverError(code: Int, message: String)
}
This generates an enumName
method that returns the case name as a string:
let error1 = NetworkError.timeout
let error2 = NetworkError.invalidURL("https://example.com")
let error3 = NetworkError.serverError(code: 404, message: "Not Found")
// Without values (default)
print(error1.enumName()) // ".timeout"
print(error2.enumName()) // ".invalidURL"
print(error3.enumName()) // ".serverError"
// With all associated values included
print(error2.enumName(includeValues: .all)) // ".invalidURL(\"https://example.com\")"
print(error3.enumName(includeValues: .all)) // ".serverError(404, \"Not Found\")"
// With only enum-named values included (useful for nested enums)
print(error2.enumName(includeValues: .enumNamesOnly)) // ".invalidURL" (string isn't an enum)
print(error3.enumName(includeValues: .enumNamesOnly)) // ".serverError" (numbers aren't enums)
- ✅ Works with simple enum cases (no associated values)
- ✅ Works with enum cases that have associated values
- ✅ Optional
includeValues
parameter to control output format - ✅ Handles multiple associated values
- ✅ Preserves parameter labels in the output
- ✅ Automatic protocol conformance for polymorphic usage
- ✅ Zero runtime dependencies
Enums with the @NamedEnum
macro automatically conform to the EnumNameProviding
protocol, allowing for polymorphic usage:
@NamedEnum
enum UserAction {
case login
case logout
}
@NamedEnum
enum NetworkError {
case timeout
case serverError(Int)
}
// Use different enum types polymorphically
let actions: [EnumNameProviding] = [
UserAction.login,
NetworkError.serverError(500)
]
for action in actions {
print(action.enumName(includeValues: .all))
}
// Output:
// .login
// .serverError(500)
The macro generates:
-
An
enumName
method with this signature:func enumName(includeValues: EnumNameIncludeValues = .none) -> String
-
An extension that adds
EnumNameProviding
protocol conformance:extension YourEnum: EnumNameProviding { }
The includeValues
parameter controls what gets included:
.none
(default): Returns just the case name like".caseName"
.all
: Includes all associated values like".caseName(value1, value2)"
.enumNamesOnly
: Only includes associated values that conform toEnumNameProviding
(useful for nested enums)
@NamedEnum
enum UserAction {
case login(String)
case logout
}
@NamedEnum
enum AppEvent {
case userAction(UserAction)
case networkRequest(String, Int)
}
let event = AppEvent.userAction(.login("username")
print(event.enumName(includeValues: .none)) // ".userAction"
print(event.enumName(includeValues: .enumNamesOnly)) // ".userAction(.login)"
print(event.enumName(includeValues: .all)) // ".userAction(.login(\"username\"))"
let networkEvent = AppEvent.networkRequest("api", 443)
print(networkEvent.enumName(includeValues: .none)) // ".networkRequest"
print(networkEvent.enumName(includeValues: .enumNamesOnly)) // ".networkRequest"
print(networkEvent.enumName(includeValues: .all)) // ".networkRequest(api, 443)"
- Swift 5.9+
- Xcode 15.0+
This project is available under the MIT license.