-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
701 additions
and
208 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# `@JsonMockable` | ||
|
||
The `@JsonMockable` macro is used to generate mockable data from a JSON file, making it easier to decode JSON into Swift models for testing purposes. This macro simplifies the process of decoding JSON data by providing automatic conformance to mockable behavior based on a JSON file, using customizable decoding strategies and bundles. | ||
|
||
## Parameters | ||
* `keyDecodingStrategy`: JSONDecoder.KeyDecodingStrategy: Specifies the strategy to use when decoding keys in the JSON file. The available options are: | ||
|
||
* `.useDefaultKeys`: Use the keys in the JSON as-is. | ||
|
||
* `.convertFromSnakeCase`: Convert keys from snake\_case to camelCase when decoding. | ||
|
||
* `bundle`: Bundle: Specifies the Bundle from which the JSON file will be loaded. This could be the app's main bundle or a test bundle, depending on where the mock data resides. | ||
|
||
* `jsonFile`: String? _(optional)_: An optional string representing the name of the JSON file that contains mock data. If nil, the macro will look for a JSON file that matches the name of the type to which the macro is applied. | ||
|
||
## Usage Example | ||
Assume you have a `User` struct that conforms to Decodable and you want to generate mockable data from a JSON file with the same name: | ||
|
||
``` swift | ||
@JsonMockable( | ||
keyDecodingStrategy: .convertFromSnakeCase, | ||
bundle: .main | ||
) | ||
struct User: Decodable { | ||
... | ||
} | ||
``` | ||
|
||
In case the JSON file has different name from your class / struct: | ||
|
||
``` swift | ||
@JsonMockable( | ||
keyDecodingStrategy: .convertFromSnakeCase, | ||
bundle: .main, | ||
jsonFile: "FILE_NAME" | ||
) | ||
struct User: Decodable { | ||
... | ||
} | ||
``` | ||
## Methods | ||
`@JsonMockable` expose a method to your entity that you can use to create other | ||
|
||
``` swift | ||
private static func getMock(bundle: Bundle, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy, fileName: String?) throws -> Self | ||
|
||
``` | ||
|
||
### Usage | ||
``` swift | ||
@JsonMockable( | ||
keyDecodingStrategy: .convertFromSnakeCase, | ||
bundle: .main | ||
) | ||
struct User: Decodable { | ||
var example: String | ||
|
||
static var mockA: Self { | ||
get throws { | ||
try getMock(bundle: .main, keyDecodingStrategy: .convertFromSnakeCase, fileName: "fileA") | ||
} | ||
} | ||
|
||
static var mockB: Self { | ||
get throws { | ||
try getMock(bundle: .main, keyDecodingStrategy: .convertFromSnakeCase, fileName: "fileB") | ||
} | ||
} | ||
} | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
# Documentation | ||
|
||
## Table of Contents | ||
- [General Macros](#general-macros) | ||
- [Codable Macros](#codable-macros) | ||
- [JsonMockable](/Documentation/JsonMockable/README.md) | ||
|
||
## General Macros | ||
|
||
#### Wip Macro | ||
Mark work in progress code and convert it into an XCode warning. | ||
|
||
wip(feature: String, todo: String) | ||
|
||
Example: | ||
|
||
#wip(feature: "New login workflow", todo: "API connection") | ||
|
||
|
||
#### Debug print | ||
Print while debugging safely. It will just add #if DEBUG. | ||
|
||
debug_print(_ description: String) | ||
|
||
|
||
#### Default init | ||
Provide init func to a struct. | ||
Example: | ||
|
||
@DefaultInit | ||
struct Vehicle { | ||
let wheels: Int | ||
let maxSpeed: Int | ||
let name: String | ||
} | ||
|
||
will be expanded to | ||
|
||
struct Vehicle { | ||
let wheels: Int | ||
let maxSpeed: Int | ||
let name: String | ||
func init(wheels: Int, maxSpeed: Int, name: String) { | ||
self.wheels = wheels | ||
self.maxSpeed = maxSpeed | ||
self.name = name | ||
} | ||
} | ||
|
||
## Codable Macros | ||
A set of macros for workinf easily with Codable, reducing the code needed. | ||
As a requirement, any of the macros will need to add the macro @CustomCodable on the object. | ||
You also need to add conformance to Codable in an extension of the object without any implementation. | ||
|
||
#### Custom Codable Key - CustomCodableKey(String) | ||
Allows you to create a custom key for decoding. | ||
|
||
Example: | ||
|
||
@CustomCodable | ||
struct Vehicle { | ||
let wheels: Int | ||
@CustomCodableKey("speedAllowed") | ||
let maxSpeed: Int | ||
let name: String | ||
} | ||
|
||
extension Vehicle: Codable {} | ||
|
||
#### Custom Default Value - CustomDefault(Any) | ||
Allows you to add a default value in case there is no value founded while decoding | ||
|
||
Example: | ||
|
||
@CustomCodable | ||
struct Vehicle { | ||
let wheels: Int | ||
@CustomDefault(150) | ||
let maxSpeed: Int | ||
let name: String | ||
} | ||
|
||
extension Vehicle: Codable {} | ||
|
||
#### Custom Date - CustomDate(dateFormat: String, defaultValue: Date? = nil) | ||
Allows you to decode Strings into Dates with default values | ||
|
||
Example: | ||
|
||
@CustomCodable | ||
struct Vehicle { | ||
let wheels: Int | ||
@CustomDate(dateFormat: "YYYYY-mm-dd", defaultValue: Date()) | ||
let designed: Date | ||
let maxSpeed: Int | ||
let name: String | ||
} | ||
|
||
extension Vehicle: Codable {} | ||
|
||
#### Custom Date - CustomDate(dateFormat: String, defaultValue: Date? = nil) | ||
Allows you to decode Strings into Dates with default values | ||
|
||
Example: | ||
|
||
@CustomCodable | ||
struct Vehicle { | ||
let wheels: Int | ||
@CustomDate(dateFormat: "YYYYY-mm-dd", defaultValue: Date()) | ||
let designed: Date | ||
let maxSpeed: Int | ||
let name: String | ||
} | ||
|
||
extension Vehicle: Codable {} | ||
|
||
#### Custom Hashable - CustomHashable(parameters: [String]) | ||
Allows you to add Hashable conformance providing the properties you want to use. | ||
|
||
Example: | ||
|
||
@CustomCodable | ||
CustomHashable(parameters: ["wheels", "name"]) | ||
struct Vehicle { | ||
let wheels: Int | ||
let designed: Date | ||
let maxSpeed: Int | ||
let name: String | ||
} | ||
|
||
extension Vehicle: Codable {} | ||
|
||
will expand to: | ||
|
||
extension Vehicle: Hashable { | ||
public func hash(into hasher: inout Hasher) { | ||
hasher.combine(wheels) | ||
hasher.combine(name) | ||
} | ||
} | ||
|
||
#### Custom Equatable - CustomEquatable(parameters: [String]) | ||
Allows you to add Equatable conformance providing the properties you want to use. | ||
|
||
Example: | ||
|
||
@CustomCodable | ||
CustomEquatable(parameters: ["wheels", "maxSpeed"]) | ||
struct Vehicle { | ||
let wheels: Int | ||
let designed: Date | ||
let maxSpeed: Int | ||
let name: String | ||
} | ||
|
||
extension Vehicle: Codable {} | ||
|
||
will expand to: | ||
|
||
extension Vehicle: Equatable { | ||
public static func == (lhs: Vehicle, rhs: Vehicle) -> Bool { | ||
lhs.wheels == rhs.wheel && lhs.maxSpeed == rhs.maxSpeed | ||
} | ||
} | ||
|
||
#### Custom URL - CustomDate(dateFormat: String, defaultValue: Date? = nil) | ||
Allows you to decode Strings into optional URL | ||
|
||
Example: | ||
|
||
@CustomCodable | ||
struct Vehicle { | ||
let wheels: Int | ||
let designed: Date | ||
let maxSpeed: Int | ||
let name: String | ||
@CustomURL | ||
let website: URL? | ||
} | ||
|
||
extension Vehicle: Codable {} | ||
|
||
Of course you can combine all of them: | ||
|
||
@CustomCodable | ||
@DefaultInit | ||
@CustomHashable(["wheels", "name"]) | ||
@CustomEquatable(["wheels", "designed"]) | ||
struct Vehicle { | ||
@CustomCodableKey("number_of_wheels") | ||
let wheels: Int | ||
@CustomDate(dateFormat: "YYYYY-mm-dd", defaultValue: Date()) | ||
let designed: Date | ||
@CustomDefault(150) | ||
let maxSpeed: Int | ||
let name: String | ||
@CustomURL | ||
let website: URL? | ||
} | ||
extension Vehicle: Codable {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.