Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set default values ​​for mutable variables via initialization syntax. #74

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/PluginCore/Attributes/CodedBy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ package struct CodedBy: PropertyAttribute {
extension Registration
where
Decl: AttributableDeclSyntax, Var: DefaultPropertyVariable,
Var.Initialization == RequiredInitialization
Var.Initialization: RequiredVariableInitialization
{
/// The optional variable data with helper expression
/// that output registration will have.
Expand Down
27 changes: 25 additions & 2 deletions Sources/PluginCore/Attributes/Default.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ package struct Default: PropertyAttribute {
extension Registration
where
Decl: AttributableDeclSyntax, Var: PropertyVariable,
Var.Initialization == RequiredInitialization
Var.Initialization: RequiredVariableInitialization
{
/// The variable data with default expression
/// that output registration will have.
Expand All @@ -77,8 +77,31 @@ where
}
}

extension AnyPropertyVariable: DefaultPropertyVariable {}

extension Registration
where
Decl: AttributableDeclSyntax, Var: PropertyVariable,
Var.Initialization: RequiredVariableInitialization
{
/// Update registration with binding initializer value. If the ``Default`` attribute is applied, it takes precedence.
///
/// New registration is updated with default expression data that will be
/// used for decoding failure and memberwise initializer(s), if provided.
///
/// - Parameter decl: The declaration to check for attribute.
/// - Returns: Newly built registration with default expression data or self.
func addDefaultValueIfInitializerExists() -> Registration<Decl, Key, AnyPropertyVariable<AnyRequiredVariableInitialization>> {
guard Default(from: decl) == nil, let value = self.variable.value?.trimmed else {
return self.updating(with: variable.any)
}
let newVar = variable.with(default: value)
return self.updating(with: newVar.any)
}
}

fileprivate extension PropertyVariable
where Initialization == RequiredInitialization {
where Initialization: RequiredVariableInitialization {
/// Update variable data with the default value expression provided.
///
/// `DefaultValueVariable` is created with this variable as base
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct RequiredInitializationWithDefaultValue: RequiredVariableInitialization {
/// syntax is fetched from this value and
/// updated when adding this initialization
/// type to init-generator.
let base: RequiredInitialization
let base: RequiredVariableInitialization
/// The default expression when
/// no value provided explicitly.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,3 @@ package protocol RequiredVariableInitialization: VariableInitialization {
/// generating initializer.
var code: CodeBlockItemSyntax { get }
}

extension RequiredVariableInitialization {
/// Converts initialization to optional from required initialization.
///
/// Wraps current instance in `OptionalInitialization`.
var optionalize: OptionalInitialization<Self> {
return .init(base: self)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/// * For providing default value to variable in memberwise initializer(s).
struct DefaultValueVariable<Wrapped>: ComposedVariable, PropertyVariable
where
Wrapped: PropertyVariable, Wrapped.Initialization == RequiredInitialization
Wrapped: PropertyVariable, Wrapped.Initialization: RequiredVariableInitialization
{
/// The customization options for `DefaultValueVariable`.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,7 @@ where
in context: some MacroExpansionContext
) -> AnyInitialization {
return if options.`init` {
if options.initialized {
base.initializing(in: context).optionalize.any
} else {
base.initializing(in: context).any
}
base.initializing(in: context).any
} else {
IgnoredInitialization().any
}
Expand Down
1 change: 1 addition & 0 deletions Sources/PluginCore/Variables/Type/MemberGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ where Decl.ChildSyntaxInput == Void, Decl.MemberSyntax == PropertyDeclSyntax {
return
input
.transformKeysAccordingToStrategy(attachedTo: decl)
.addDefaultValueIfInitializerExists()
.checkInitializedCodingIgnored(attachedAt: decl)
.registerKeyPath(
provider: CodedAt(from: input.decl)
Expand Down
18 changes: 15 additions & 3 deletions Tests/MetaCodableTests/CodableInheritanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ final class CodableInheritanceTests: XCTestCase {

required init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.value = try container.decode(String.self, forKey: CodingKeys.value)
do {
self.value = try container.decodeIfPresent(String.self, forKey: CodingKeys.value) ?? ""
} catch {
self.value = ""
}
}

func encode(to encoder: any Encoder) throws {
Expand Down Expand Up @@ -122,7 +126,11 @@ final class CodableInheritanceTests: XCTestCase {

required init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.value = try container.decode(String.self, forKey: CodingKeys.value)
do {
self.value = try container.decodeIfPresent(String.self, forKey: CodingKeys.value) ?? ""
} catch {
self.value = ""
}
try super.init(from: decoder)
}

Expand Down Expand Up @@ -161,7 +169,11 @@ final class CodableInheritanceTests: XCTestCase {

required init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.value = try container.decode(String.self, forKey: CodingKeys.value)
do {
self.value = try container.decodeIfPresent(String.self, forKey: CodingKeys.value) ?? ""
} catch {
self.value = ""
}
try super.init(from: decoder)
}

Expand Down
39 changes: 18 additions & 21 deletions Tests/MetaCodableTests/GroupedMutableVariableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,7 @@ final class GroupedMutableVariableTests: XCTestCase {
struct SomeCodable {
var one, two: String, three: String = ""

init(one: String, two: String) {
self.one = one
self.two = two
}

init(one: String, two: String, three: String) {
init(one: String, two: String, three: String = "") {
self.one = one
self.two = two
self.three = three
Expand All @@ -85,7 +80,11 @@ final class GroupedMutableVariableTests: XCTestCase {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.one = try container.decode(String.self, forKey: CodingKeys.one)
self.two = try container.decode(String.self, forKey: CodingKeys.two)
self.three = try container.decode(String.self, forKey: CodingKeys.three)
do {
self.three = try container.decodeIfPresent(String.self, forKey: CodingKeys.three) ?? ""
} catch {
self.three = ""
}
}
}

Expand Down Expand Up @@ -215,12 +214,7 @@ final class GroupedMutableVariableTests: XCTestCase {
struct SomeCodable {
var one: String, two: String = "", three: Int

init(one: String, three: Int) {
self.one = one
self.three = three
}

init(one: String, two: String, three: Int) {
init(one: String, two: String = "", three: Int) {
self.one = one
self.two = two
self.three = three
Expand All @@ -231,7 +225,11 @@ final class GroupedMutableVariableTests: XCTestCase {
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.one = try container.decode(String.self, forKey: CodingKeys.one)
self.two = try container.decode(String.self, forKey: CodingKeys.two)
do {
self.two = try container.decodeIfPresent(String.self, forKey: CodingKeys.two) ?? ""
} catch {
self.two = ""
}
self.three = try container.decode(Int.self, forKey: CodingKeys.three)
}
}
Expand Down Expand Up @@ -270,12 +268,7 @@ final class GroupedMutableVariableTests: XCTestCase {
struct SomeCodable {
var one: String, two = "", three: Int

init(one: String, three: Int) {
self.one = one
self.three = three
}

init(one: String, two: Int, three: Int) {
init(one: String, two: Int = "", three: Int) {
self.one = one
self.two = two
self.three = three
Expand All @@ -286,7 +279,11 @@ final class GroupedMutableVariableTests: XCTestCase {
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.one = try container.decode(String.self, forKey: CodingKeys.one)
self.two = try container.decode(Int.self, forKey: CodingKeys.two)
do {
self.two = try container.decodeIfPresent(Int.self, forKey: CodingKeys.two) ?? ""
} catch {
self.two = ""
}
self.three = try container.decode(Int.self, forKey: CodingKeys.three)
}
}
Expand Down
62 changes: 53 additions & 9 deletions Tests/MetaCodableTests/IgnoreCodingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,11 @@ final class IgnoreCodingTests: XCTestCase {
extension SomeCodable: Decodable {
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.one = try container.decode(String.self, forKey: CodingKeys.one)
do {
self.one = try container.decodeIfPresent(String.self, forKey: CodingKeys.one) ?? "some"
} catch {
self.one = "some"
}
self.two = try container.decode(String.self, forKey: CodingKeys.two)
}
}
Expand Down Expand Up @@ -398,10 +402,30 @@ final class IgnoreCodingTests: XCTestCase {
extension SomeCodable: Decodable {
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let deeply_container = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.deeply)
let nested_deeply_container = try deeply_container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.nested)
self.four = try nested_deeply_container.decode(String.self, forKey: CodingKeys.two)
self.three = try nested_deeply_container.decode(String.self, forKey: CodingKeys.three)
if let deeply_container = try? container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.deeply) {
if let nested_deeply_container = try? deeply_container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.nested) {
do {
self.four = try nested_deeply_container.decodeIfPresent(String.self, forKey: CodingKeys.two) ?? "some"
} catch {
self.four = "some"
}
do {
self.three = try nested_deeply_container.decodeIfPresent(String.self, forKey: CodingKeys.three) ?? "some"
} catch {
self.three = "some"
}
} else {
self.one = "some"
self.two = "some"
self.four = "some"
self.three = "some"
}
} else {
self.one = "some"
self.two = "some"
self.four = "some"
self.three = "some"
}
}
}

Expand Down Expand Up @@ -457,10 +481,30 @@ final class IgnoreCodingTests: XCTestCase {

required init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let deeply_container = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.deeply)
let nested_deeply_container = try deeply_container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.nested)
self.four = try nested_deeply_container.decode(String.self, forKey: CodingKeys.two)
self.three = try nested_deeply_container.decode(String.self, forKey: CodingKeys.three)
if let deeply_container = try? container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.deeply) {
if let nested_deeply_container = try? deeply_container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.nested) {
do {
self.four = try nested_deeply_container.decodeIfPresent(String.self, forKey: CodingKeys.two) ?? "some"
} catch {
self.four = "some"
}
do {
self.three = try nested_deeply_container.decodeIfPresent(String.self, forKey: CodingKeys.three) ?? "some"
} catch {
self.three = "some"
}
} else {
self.one = "some"
self.two = "some"
self.four = "some"
self.three = "some"
}
} else {
self.one = "some"
self.two = "some"
self.four = "some"
self.three = "some"
}
}

func encode(to encoder: any Encoder) throws {
Expand Down
12 changes: 10 additions & 2 deletions Tests/MetaCodableTests/IgnoreInitializedTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,11 @@ final class IgnoreInitializedTests: XCTestCase {
extension SomeCodable: Decodable {
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.one = try container.decode(String.self, forKey: CodingKeys.one)
do {
self.one = try container.decodeIfPresent(String.self, forKey: CodingKeys.one) ?? "some"
} catch {
self.one = "some"
}
}
}

Expand Down Expand Up @@ -376,7 +380,11 @@ final class IgnoreInitializedTests: XCTestCase {
extension SomeCodable: Decodable {
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.one = try container.decode(String.self, forKey: CodingKeys.one)
do {
self.one = try container.decodeIfPresent(String.self, forKey: CodingKeys.one) ?? "some"
} catch {
self.one = "some"
}
}
}

Expand Down
Loading