Skip to content

Commit e8ed299

Browse files
authored
Merge pull request #2238 from woocommerce/feat/copiable-framework
Add Copiable Foundation
2 parents d931a6d + 52e9031 commit e8ed299

File tree

5 files changed

+475
-1
lines changed

5 files changed

+475
-1
lines changed

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
45ED4F10239E8A54004F1BE3 /* TaxClassListMapperTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45ED4F0F239E8A54004F1BE3 /* TaxClassListMapperTest.swift */; };
6666
45ED4F12239E8C57004F1BE3 /* taxes-classes.json in Resources */ = {isa = PBXBuildFile; fileRef = 45ED4F11239E8C57004F1BE3 /* taxes-classes.json */; };
6767
45ED4F14239E8F2E004F1BE3 /* TaxClassRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45ED4F13239E8F2E004F1BE3 /* TaxClassRemoteTests.swift */; };
68+
5726F72E2460A2820031CAAC /* Copiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5726F72D2460A2820031CAAC /* Copiable.swift */; };
69+
5726F7312460A8510031CAAC /* ProductImage+Copiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5726F7302460A8510031CAAC /* ProductImage+Copiable.swift */; };
70+
5726F7342460A8F00031CAAC /* CopiableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5726F7332460A8F00031CAAC /* CopiableTests.swift */; };
6871
57BE08D82409B63800F6DCED /* reviews-missing-avatar-urls.json in Resources */ = {isa = PBXBuildFile; fileRef = 57BE08D72409B63700F6DCED /* reviews-missing-avatar-urls.json */; };
6972
6647C0161DAC6AB6570C53A7 /* Pods_Networking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F25DC15EC1D7C631169CB5 /* Pods_Networking.framework */; };
7073
6856DE98F90AC6E4743D18CA /* XCTestCase+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6856D1228ADBC14D8202E49D /* XCTestCase+Wait.swift */; };
@@ -393,6 +396,9 @@
393396
45ED4F0F239E8A54004F1BE3 /* TaxClassListMapperTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaxClassListMapperTest.swift; sourceTree = "<group>"; };
394397
45ED4F11239E8C57004F1BE3 /* taxes-classes.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "taxes-classes.json"; sourceTree = "<group>"; };
395398
45ED4F13239E8F2E004F1BE3 /* TaxClassRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaxClassRemoteTests.swift; sourceTree = "<group>"; };
399+
5726F72D2460A2820031CAAC /* Copiable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Copiable.swift; sourceTree = "<group>"; };
400+
5726F7302460A8510031CAAC /* ProductImage+Copiable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProductImage+Copiable.swift"; sourceTree = "<group>"; };
401+
5726F7332460A8F00031CAAC /* CopiableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopiableTests.swift; sourceTree = "<group>"; };
396402
573B448C242422DB00E71ADC /* orders-load-all-2.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "orders-load-all-2.json"; sourceTree = "<group>"; };
397403
57BE08D72409B63700F6DCED /* reviews-missing-avatar-urls.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "reviews-missing-avatar-urls.json"; sourceTree = "<group>"; };
398404
6856D1228ADBC14D8202E49D /* XCTestCase+Wait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCTestCase+Wait.swift"; sourceTree = "<group>"; };
@@ -713,6 +719,30 @@
713719
path = Refund;
714720
sourceTree = "<group>";
715721
};
722+
5726F72C2460A25F0031CAAC /* Copiable */ = {
723+
isa = PBXGroup;
724+
children = (
725+
5726F72D2460A2820031CAAC /* Copiable.swift */,
726+
);
727+
path = Copiable;
728+
sourceTree = "<group>";
729+
};
730+
5726F72F2460A83D0031CAAC /* Copiable */ = {
731+
isa = PBXGroup;
732+
children = (
733+
5726F7302460A8510031CAAC /* ProductImage+Copiable.swift */,
734+
);
735+
path = Copiable;
736+
sourceTree = "<group>";
737+
};
738+
5726F7322460A8E30031CAAC /* Copiable */ = {
739+
isa = PBXGroup;
740+
children = (
741+
5726F7332460A8F00031CAAC /* CopiableTests.swift */,
742+
);
743+
path = Copiable;
744+
sourceTree = "<group>";
745+
};
716746
6856DE4E23A475D8CEBD10C1 /* Testing */ = {
717747
isa = PBXGroup;
718748
children = (
@@ -852,6 +882,7 @@
852882
B557D9E5209753AA005962F4 /* Networking */ = {
853883
isa = PBXGroup;
854884
children = (
885+
5726F72C2460A25F0031CAAC /* Copiable */,
855886
B5A0369F214C0F4C00774E2C /* Internal */,
856887
B5BB1D0A20A204F400112D92 /* Extensions */,
857888
B567AF2720A0FA0A00AB6C62 /* Mapper */,
@@ -871,6 +902,7 @@
871902
B557D9F0209753AA005962F4 /* NetworkingTests */ = {
872903
isa = PBXGroup;
873904
children = (
905+
5726F7322460A8E30031CAAC /* Copiable */,
874906
B559EBA820A0B5B100836CD4 /* Responses */,
875907
B518663220A0A2E800037A38 /* Settings */,
876908
B5C6FCC620A32E3100A4F8E4 /* Extensions */,
@@ -939,6 +971,7 @@
939971
B557DA1B20979E6D005962F4 /* Model */ = {
940972
isa = PBXGroup;
941973
children = (
974+
5726F72F2460A83D0031CAAC /* Copiable */,
942975
B50A583A21AD872E00617455 /* Devices */,
943976
020D07B623D852AB00FD9580 /* Media */,
944977
CE6BFEE62236CF0D005C79FB /* Product */,
@@ -1585,6 +1618,7 @@
15851618
B556FD69211CE2EC00B5DAE7 /* NetworkError.swift in Sources */,
15861619
B557DA0D20975DB1005962F4 /* WordPressAPIVersion.swift in Sources */,
15871620
7412A8EC21B6E286005D182A /* ReportOrderTotalsMapper.swift in Sources */,
1621+
5726F72E2460A2820031CAAC /* Copiable.swift in Sources */,
15881622
74A1D26F21189EA100931DFA /* SiteVisitStatsRemote.swift in Sources */,
15891623
B557DA1D20979E7D005962F4 /* Order.swift in Sources */,
15901624
74159625224D4045003C21CF /* SiteSettingGroup.swift in Sources */,
@@ -1633,6 +1667,7 @@
16331667
026CF61A237D607A009563D4 /* ProductVariationAttribute.swift in Sources */,
16341668
748D424A210F92EA00CF7D1B /* OrderStatsItem.swift in Sources */,
16351669
D8FBFF1A22D4DF7A006E3336 /* OrderStatsV4.swift in Sources */,
1670+
5726F7312460A8510031CAAC /* ProductImage+Copiable.swift in Sources */,
16361671
74A1D26B21189B8100931DFA /* SiteVisitStatsItem.swift in Sources */,
16371672
B505F6EC20BEFDC200BB1B69 /* Loader.swift in Sources */,
16381673
74D3BD142114FE6900A6E85E /* MIContainer.swift in Sources */,
@@ -1695,6 +1730,7 @@
16951730
74AB0ACA21948CE4008220CD /* CommentResultMapperTests.swift in Sources */,
16961731
B524194921AC659500D6FC0A /* DevicesRemoteTests.swift in Sources */,
16971732
B505F6D320BEE3A500BB1B69 /* AccountMapperTests.swift in Sources */,
1733+
5726F7342460A8F00031CAAC /* CopiableTests.swift in Sources */,
16981734
26615479242DA54D00A31661 /* ProductCategoyListMapperTests.swift in Sources */,
16991735
B5C6FCC820A32E4800A4F8E4 /* DateFormatterWooTests.swift in Sources */,
17001736
74C8F06A20EEBC8C00B6EDC9 /* OrderMapperTests.swift in Sources */,
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
2+
import Foundation
3+
4+
/// A typealias for arguments of `copy()` methods signifying that the required property's value
5+
/// will be copied by default if no value is given.
6+
///
7+
/// For example:
8+
///
9+
/// ```
10+
/// struct Person {
11+
/// let id: Int
12+
/// let name: String
13+
///
14+
/// func copy(id: CopiableProp<Int> = .copy,
15+
/// name: CopiableProp<String> = .copy) -> Person {
16+
/// Person(id: id ?? self.id,
17+
/// name: name ?? self.name)
18+
/// }
19+
/// }
20+
///
21+
/// let luke = Person(id: 1, name: "Luke")
22+
///
23+
/// let leia = luke.copy(name: "Leia")
24+
/// ```
25+
///
26+
/// The variable `leia` will have the same `id` as `luke`:
27+
///
28+
/// ```
29+
/// { id: 1, name: "Leia" }
30+
/// ```
31+
///
32+
public typealias CopiableProp<Wrapped> = Optional<Wrapped>
33+
34+
/// A typealias for arguments of `copy()` methods signifying that the property is `Optional` and
35+
/// that the existing value will be copied by default if no value is given.
36+
///
37+
/// Using `NullableCopiableProp` allows us to set an `Optional` property to `nil` when copying.
38+
/// For example, if passing a variable as an argument, the property will be set to `nil` as
39+
/// expected:
40+
///
41+
/// ```
42+
/// struct Person {
43+
/// let id: Int
44+
/// let name: String
45+
/// let address: String?
46+
///
47+
/// func copy(id: CopiableProp<Int> = .copy,
48+
/// name: CopiableProp<String> = .copy,
49+
/// address: NullableCopiableProp<String> = .copy) -> Person {
50+
/// Person(id: id ?? self.id,
51+
/// name: name ?? self.name,
52+
/// address: address ?? self.address)
53+
/// }
54+
/// }
55+
///
56+
/// let luke = Person(id: 1, name: "Luke", address: "Jakku")
57+
///
58+
/// let address: String? = nil
59+
///
60+
/// let lukeWithNoAddress = luke.copy(address: address)
61+
/// ```
62+
///
63+
/// The variable `lukeWithNoAddress` will have a `nil` `address` as expected:
64+
///
65+
/// ```
66+
/// { id: 1, name: "Luke", address: nil }
67+
/// ```
68+
///
69+
/// In order to **directly** set a `NullableCopiableProp` to `nil`, the argument `.some(nil)`
70+
/// must be passed:
71+
///
72+
/// ```
73+
/// let lukeWithNoAddress = luke.copy(address: .some(nil))
74+
/// ```
75+
///
76+
/// We will still end up with the same result:
77+
///
78+
/// ```
79+
/// { id: 1, name: "Luke", address: nil }
80+
/// ```
81+
///
82+
public typealias NullableCopiableProp<Wrapped> = CopiableProp<Wrapped?>
83+
84+
// MARK: - Support for `.copy` alias
85+
86+
extension CopiableProp {
87+
/// Allow `CopiableProp<>` declarations to use a `.copy` alias as the default value instead of
88+
/// using `nil`.
89+
///
90+
/// For example, instead of declaring `copy()` arguments like this:
91+
///
92+
/// ```
93+
/// func copy(orderID: CopiableProp<Int> = nil)
94+
/// ```
95+
///
96+
/// We can declare them like this:
97+
///
98+
/// ```
99+
/// func copy(orderID: CopiableProp<Int> = .copy)
100+
/// ```
101+
///
102+
/// Using `.copy` makes it a bit more clearer what will happen if you don't declare or
103+
/// provide a different value.
104+
///
105+
public static var copy: Wrapped? {
106+
nil
107+
}
108+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Foundation
2+
3+
/// TODO This will soon be generated instead.
4+
5+
extension ProductImage {
6+
public func copy(
7+
imageID: CopiableProp<Int64> = .copy,
8+
dateCreated: CopiableProp<Date> = .copy,
9+
dateModified: NullableCopiableProp<Date> = .copy,
10+
src: CopiableProp<String> = .copy,
11+
name: NullableCopiableProp<String> = .copy,
12+
alt: NullableCopiableProp<String> = .copy
13+
) -> ProductImage {
14+
/// Declare local variables because the Swift compiler will sometimes choke if there are
15+
/// too many arguments with default values.
16+
let imageID = imageID ?? self.imageID
17+
let dateCreated = dateCreated ?? self.dateCreated
18+
let dateModified = dateModified ?? self.dateModified
19+
let src = src ?? self.src
20+
let name = name ?? self.name
21+
let alt = alt ?? self.alt
22+
23+
return ProductImage(
24+
imageID: imageID,
25+
dateCreated: dateCreated,
26+
dateModified: dateModified,
27+
src: src,
28+
name: name,
29+
alt: alt
30+
)
31+
}
32+
}

0 commit comments

Comments
 (0)