├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── LICENSE
├── Package.swift
├── Podfile
├── Podfile.lock
├── README.md
├── Source
├── Codable
│ └── Codable.swift
├── Enum
│ └── Enum.swift
├── Print
│ └── Print.swift
├── Stuff.swift
└── TODO
│ └── TODO.swift
├── Stuff.podspec
├── Stuff.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
├── Stuff.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── StuffTests
├── CodableStuffTests.swift
├── EnumStuffTests.swift
├── Info.plist
├── PrintStuffTests.swift
└── TODOStuffTests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 |
20 | # CocoaPods
21 | #
22 | # We recommend against adding the Pods directory to your .gitignore. However
23 | # you should judge for yourself, the pros and cons are mentioned at:
24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
25 | #
26 | Pods/
27 |
28 | # Carthage
29 | #
30 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
31 | # Carthage/Checkouts
32 | Carthage/Build
33 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT 3 License
2 |
3 | Copyright (c) 2015, EVICT B.V.
4 | All rights reserved.
5 | http://evict.nl, mailto://edwin@evict.nl
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 | * Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 | * Redistributions in binary form must reproduce the above copyright
12 | notice, this list of conditions and the following disclaimer in the
13 | documentation and/or other materials provided with the distribution.
14 | * Neither the name of EVICT B.V. nor the
15 | names of its contributors may be used to endorse or promote products
16 | derived from this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.5
2 |
3 | //
4 | // Package.swift
5 | //
6 | //
7 | // Created by Sander van Tulden on 12/10/2023.
8 | //
9 |
10 | import PackageDescription
11 |
12 | let packageName = "Stuff"
13 |
14 | let package = Package(
15 | name: packageName,
16 | platforms: [
17 | .iOS(.v8),
18 | .watchOS(.v2),
19 | .macOS(.v10_10),
20 | .tvOS(.v9)
21 | ],
22 | products: [
23 | .library(
24 | name: packageName,
25 | targets: [packageName]
26 | )
27 | ],
28 | targets: [
29 | .target(
30 | name: packageName,
31 | path: "Source"
32 | ),
33 | .testTarget(
34 | name: packageName + "Tests",
35 | dependencies: [.target(name: packageName)],
36 | path: "StuffTests"
37 | )
38 | ]
39 | )
40 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 | use_frameworks!
3 | workspace 'Stuff'
4 |
5 | target 'StuffTests' do
6 | platform :ios, '8.0'
7 | pod 'Stuff', :path => "./"
8 | end
9 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Stuff (0.9.0):
3 | - Stuff/All (= 0.9.0)
4 | - Stuff/All (0.9.0):
5 | - Stuff/Codable
6 | - Stuff/Enum
7 | - Stuff/Print
8 | - Stuff/TODO
9 | - Stuff/Codable (0.9.0)
10 | - Stuff/Enum (0.9.0)
11 | - Stuff/Print (0.9.0)
12 | - Stuff/TODO (0.9.0)
13 |
14 | DEPENDENCIES:
15 | - Stuff (from `./`)
16 |
17 | EXTERNAL SOURCES:
18 | Stuff:
19 | :path: "./"
20 |
21 | SPEC CHECKSUMS:
22 | Stuff: c61c749c1f6464ad1e9ef8fcc561792c265fb10e
23 |
24 | PODFILE CHECKSUM: bf19cca12781c8d2d79fc7cc174325633ebbe909
25 |
26 | COCOAPODS: 1.6.0.rc.2
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Stuff
2 |
3 | [](https://github.com/evermeer/Stuff/issues)
4 | [](http://cocoadocs.org/docsets/Stuff/)
5 | [](https://github.com/evermeer/Stuff/stargazers)
6 | [](https://cocoapods.org/pods/Stuff)
7 |
8 |
9 | [](http://cocoadocs.org/docsets/Stuff)
10 | [](https://developer.apple.com/swift)
11 | [](http://cocoadocs.org/docsets/Stuff)
12 | [](http://cocoadocs.org/docsets/Stuff)
13 |
14 | [](https://github.com/evermeer)
15 | [](http://twitter.com/evermeer)
16 | [](http://nl.linkedin.com/in/evermeer/en)
17 | [](http://evict.nl)
18 | [](mailto:edwin@evict.nl?SUBJECT=About%20Stuff)
19 |
20 | # General information
21 |
22 | Stuff is a collection of code 'snippets' that are too small to create a library for and which do not fit in an other library. Run the unit tests to see the code in action.
23 |
24 | - [Print](#print) - For creating a nice output log
25 | - [Enum](#enum) - Adding functionality to an enum
26 | - [TODO](#todo) - Adding a TODO helper function
27 | - [Codable](#codable) - Adding Codable helper functions (Swift 4)
28 |
29 | To install all parts via Swift Package Manager, add version `1.1.4` or higher with URL `https://github.com/evermeer/Stuff` to your project file.
30 |
31 | ## Print
32 |
33 | You can install this by adding the following line to your Podfile:
34 |
35 | ```
36 | pod "Stuff/Print"
37 | ```
38 |
39 | The Stuff.print function is meant to be a replacement for the standard .print function. It will give you extra information about when and where the print function was executed. Besides that there is also support for different log levels and you can specify the minimum log level that should be in the output.
40 |
41 | Here are some samples:
42 |
43 | ```swift
44 | Stuff.print("Just as the standard print but now with detailed information")
45 | Stuff.print("Now it's a warning", .warn)
46 | Stuff.print("Or even an error", .error)
47 |
48 | Stuff.minimumLogLevel = .error
49 | Stuff.print("Now you won't see normal log output")
50 | Stuff.print("Only errors are shown", .error)
51 |
52 | Stuff.minimumLogLevel = .none
53 | Stuff.print("Or if it's disabled you won't see any log", .error)
54 | ```
55 |
56 | The output of the code above is:
57 |
58 | ```console
59 | ✳️ .debug ⏱ 02/13/2017 09:52:51:852 📱 xctest [18960:?] 📂 PrintStuffTests.swift(15) ⚙️ testExample() ➡️
60 | Just as the standard print but now with detailed information
61 |
62 | ⚠️ .warn ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(16) ⚙️ testExample() ➡️
63 | Now it's a warning
64 |
65 | 🚫 .error ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(17) ⚙️ testExample() ➡️
66 | Or even an error
67 |
68 | 🚫 .error ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(21) ⚙️ testExample() ➡️
69 | Only errors are shown
70 | ```
71 |
72 | There is also a shortcut print statement for an error object. This will print the localizedDescription and set the warning level to .error.
73 | ```swift
74 | Stuff.print(error)
75 | ```
76 |
77 | Update: From now on printing .error will also give you a stacktrace.
78 |
79 | Update 04-04-2019 : You can now also set the minimumLogLevel to productionLogAll. This will make sure you can also see the logging in the console (menu 'Window', 'Devices and Simulators', 'Open Console') In most cases you should only use this if you want to see logging for an app that you distributed using Testflight.
80 |
81 | ## Enum
82 |
83 | You can install this by adding the following line to your Podfile:
84 |
85 | ```
86 | pod "Stuff/Enum"
87 | ```
88 |
89 | - getting all possible enum values in an arry
90 | - getting the associated value of any enum
91 | - converting an array of enums with associated values to a dictionary or an query string.
92 | - get the raw value of an enum even it it was passed in an any
93 |
94 |
95 | ```swift
96 | // You have to extend the enum with the Enum protocol (and RawEnum if you want the raw value when it's an Any)
97 | enum test1: String, Enum, RawEnum {
98 | case option1
99 | case option2
100 | case option3
101 | }
102 |
103 | enum test2: Enum {
104 | case option4(String)
105 | case option5(Int)
106 | case option6(Int, String)
107 | }
108 |
109 | XCTAssert(test1.allValues.count == 3, "There should be 3 values")
110 | for value in test1.allValues {
111 | print("value = \(value)")
112 | }
113 |
114 | let v1: test2 = .option4("test")
115 | print("v1 = \(v1.associated.label), \(v1.associated.value!)")
116 | let v2: test2 = .option5(3)
117 | print("v2 = \(v2.associated.label), \(v2.associated.value!)")
118 | let v3: test2 = .option6(4, "more")
119 | print("v3 = \(v3.associated.label), \(v3.associated.value!)")
120 |
121 | let array = [v1, v2, v3]
122 | let dict = [String:Any](array)
123 | print("Array of enums as dictionary:\n \(dict)")
124 |
125 | print("query = \(array.queryString))")
126 |
127 | let v = getRawValue(test1.option2)
128 | print("raw value = \(v)")
129 |
130 | func getRawValue(_ value: Any) -> Any {
131 | return (value as? RawEnum)?.anyRawValue ?? ""
132 | }
133 |
134 | ```
135 | The output is:
136 |
137 | ```swift
138 | value = option1
139 | value = option2
140 | value = option3
141 | v1 = option4, test
142 | v2 = option5, 3
143 | v3 = option6, (4, "more")
144 | Array of enums as dictionary:
145 | ["option5": 3, "option4": "test", "option6": (4, "more")]
146 | query = option4=test,option5=3,option6=(4, "more"))
147 | raw value = option2
148 | ```
149 |
150 | ## TODO
151 |
152 | You can install this by adding the following line to your Podfile:
153 |
154 | ```
155 | pod "Stuff/TODO"
156 | ```
157 |
158 | Whenever you add a function to your project and postpone implementing it, you should add a TODO.
159 | Whenever you temporarilly change functioning code in order to debug something, you should add a TODO
160 | Before commiting/pushing your code, you should evaluate/solve your TODO's
161 | Usually you just add a TODO comment in your code like this:
162 |
163 | ```swift
164 | //TODO: This needs to be fixed
165 | ```
166 |
167 | With the Stuff/TODO helper, you can get compile time and run time support for helping to find your TODO's. Here is an overview of the variants that you can use:
168 |
169 | ```swift
170 | // We need to fix something, but this code can run (compiler warning)
171 | TODO()
172 |
173 | // Now output extra info when this code is executed.
174 | TODO("An other todo, now giving some detailed info")
175 |
176 | // We need to fix this. Otherwise just fail. The code will crash here. See the stacktrace,
177 | TODO_
178 | ```
179 |
180 | The code above will put the following in your output. Besides that, you will also see depricated warnings when you have the code open in Xcode.
181 |
182 | ```
183 | ⚠️ TODO code is still in use! ⚠️
184 |
185 | ⚠️ TODO code is still in use! ⚠️
186 | An other todo, now giving some detailed info
187 | fatal error: TODO left in code: file /Users/evermeer/Desktop/dev/GitHub/Stuff/Source/TODO/TODO.swift, line 15
188 | ```
189 |
190 | But... It might be nicer to just add the following build phase script which will also give you compile time warnings:
191 |
192 | ```
193 | KEYWORDS="TODO|FIXME|\?\?\?:|\!\!\!:"
194 | find "${SRCROOT}" \( -name "*.swift" \) -print0 | \
195 | xargs -0 egrep --with-filename --line-number --only-matching "($KEYWORDS).*\$" | \
196 | perl -p -e "s/($KEYWORDS)/ warning: \$1/"
197 | ```
198 |
199 | ## Codable
200 |
201 | You can install this by adding the following line to your Podfile:
202 |
203 | ```
204 | pod "Stuff/Codable"
205 | ```
206 |
207 | Swift 4 added the Codable (EnCodable and DeCodable) protocol which you can add to a class or struct. The swift compile will then add coding and decoding functionality to your object. With the JSONEncoder and JSONDecoder classes you can then convert an object from and to json. The Stuff Codable extension will let you do these things in a 1 liner. Here is Apple documentaion about [Codable](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types) The one liners that you can use are:
208 |
209 | ```swift
210 | let json = yourEncodableObjectInstance.toJsonString()
211 | let data = yourEncodableObjectInstance.toJsonData()
212 | let newObject = try? YourCodableObject(json: json)
213 | let newObject2 = try? YourCodableObject(data: data)
214 | let objectArray = try? [YourCodableObject](json: json)
215 | let objectArray2 = try? [YourCodableObject](data: data)
216 | let newJson = objectArray.toJsonString()
217 | let innerObject = try? TestCodable(json: "{\"user\":{\"id\":1,\"naam\":\"Edwin\"}}", keyPath: "user")
218 | try initialObject.saveToDocuments("myFile.dat")
219 | let readObject = try? TestCodable(fileNameInDocuments: "myFile.dat")
220 | try objectArray.saveToDocuments("myFile2.dat")
221 | let objectArray3 = try? [TestCodable](fileNameInDocuments: "myFile2.dat")
222 | ```
223 |
224 | And here you can see how you can use these Stuff/Codable functions:
225 |
226 | ```swift
227 | func test() {
228 | let initialObject = TestCodable(naam: "Edwin", id: 1, testField: "tst")
229 |
230 | guard let json = initialObject.toJsonString() else {
231 | print("Could not create json from object")
232 | return
233 | }
234 | print("Json string of object = \n\t\(json)")
235 |
236 | guard let newObject = try? TestCodable(json: json) else {
237 | print("Could not create object from json")
238 | return
239 | }
240 | print("Object created with json = \n\t\(newObject)")
241 |
242 | let json2 = "[{\"id\":1,\"naam\":\"Edwin\"},{\"id\":2,\"naam\":\"Vermeer\"}]"
243 | guard let array = try? [TestCodable](jsonArray: json2) else {
244 | print("Could not create object array from json")
245 | return
246 | }
247 | print("Object array created with json = \(array)")
248 |
249 | let newJson = array.toJsonString()
250 | print("Json from object array = \n\t\(newJson)")
251 |
252 | guard let innerObject = try? TestCodable(json: "{\"user\":{\"id\":1,\"naam\":\"Edwin\"}}", keyPath: "user") else {
253 | print("Could not create object from json")
254 | return
255 | }
256 | print("inner object from json \(String(describing: innerObject))")
257 |
258 | guard let custom = try TestCodable(json: "{\"Naam\":\"UpperN\", \"Id\":5, \"Test_field\":\"lowerSnake\"}", keyPath: nil, codingStrategy: customCodingStragegy) else {
259 | print("Could not custom case convert")
260 | return
261 | }
262 | print("read object with custom key coding from json to \(String(describing:
263 | }
264 |
265 | struct TestCodable : Codable {
266 | var naam: String?
267 | var id: Int?
268 | var testField: String?
269 | }
270 | ```
271 |
272 | besides the keyPath a shown in the sample code above you could also add one or more of the folowing parameters which are part of the standard JSONDecoder. If these parameters are not supplied, then the default value (see what's after the =) will be used.
273 |
274 | ```
275 | keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .convertFromSnakeCase,
276 | dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate,
277 | dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .base64,
278 | nonConformingFloatDecodingStrategy: JSONDecoder.NonConformingFloatDecodingStrategy = .throw
279 | ```
280 |
281 | ## License
282 |
283 | Stuff is available under the MIT 3 license. See the LICENSE file for more info.
284 |
285 | ## My other libraries:
286 | Also see my other public source iOS libraries:
287 |
288 | - [EVReflection](https://github.com/evermeer/EVReflection) - Reflection based (Dictionary, CKRecord, JSON and XML) object mapping with extensions for Alamofire and Moya with RxSwift or ReactiveSwift
289 | - [EVCloudKitDao](https://github.com/evermeer/EVCloudKitDao) - Simplified access to Apple's CloudKit
290 | - [EVFaceTracker](https://github.com/evermeer/EVFaceTracker) - Calculate the distance and angle of your device with regards to your face in order to simulate a 3D effect
291 | - [EVURLCache](https://github.com/evermeer/EVURLCache) - a NSURLCache subclass for handling all web requests that use NSURLReques
292 | - [AlamofireOauth2](https://github.com/evermeer/AlamofireOauth2) - A swift implementation of OAuth2 using Alamofire
293 | - [EVWordPressAPI](https://github.com/evermeer/EVWordPressAPI) - Swift Implementation of the WordPress (Jetpack) API using AlamofireOauth2, EVReflection and Alamofire (work in progress)
294 | - [PassportScanner](https://github.com/evermeer/PassportScanner) - Scan the MRZ code of a passport and extract the firstname, lastname, passport number, nationality, date of birth, expiration date and personal numer.
295 | - [AttributedTextView](https://github.com/evermeer/AttributedTextView) - Easiest way to create an attributed UITextView with support for multiple links (url, hashtags, mentions).
296 | - [UITestHelper](https://github.com/evermeer/UITestHelper) - UI test helper functions.
297 |
298 |
--------------------------------------------------------------------------------
/Source/Codable/Codable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Codable.swift
3 | // Stuff
4 | //
5 | // Created by Edwin Vermeer on 28/06/2017.
6 | // Copyright © 2017 EVICT BV. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | enum CodingError : Error {
11 | case RuntimeError(String)
12 | }
13 |
14 | struct AnyKey: CodingKey {
15 | var stringValue: String
16 | var intValue: Int?
17 |
18 | init(stringValue: String) {
19 | self.stringValue = stringValue
20 | self.intValue = nil
21 | }
22 |
23 | init(intValue: Int) {
24 | self.stringValue = String(intValue)
25 | self.intValue = intValue
26 | }
27 | }
28 |
29 | public var customCodingStragegy: JSONDecoder.KeyDecodingStrategy = .custom { keys in
30 | let lastComponent = keys.last!.stringValue
31 | let snakeCased = lastComponent.split(separator: "_").map { $0.prefix(1).uppercased() + $0.dropFirst() }.reduce("") { $0 + $1}
32 | let lowerFirst = snakeCased.prefix(1).lowercased() + snakeCased.dropFirst()
33 | return AnyKey(stringValue: lowerFirst)
34 | }
35 |
36 | public extension Encodable {
37 | /**
38 | Convert this object to json data
39 |
40 | - parameter outputFormatting: The formatting of the output JSON data (compact or pritty printed)
41 | - parameter dateEncodinStrategy: how do you want to format the date
42 | - parameter dataEncodingStrategy: what kind of encoding. base64 is the default
43 |
44 | - returns: The json data
45 | */
46 | func toJsonData(outputFormatting: JSONEncoder.OutputFormatting = [], dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .deferredToDate, dataEncodingStrategy: JSONEncoder.DataEncodingStrategy = .base64) -> Data? {
47 | let encoder = JSONEncoder()
48 | encoder.outputFormatting = outputFormatting
49 | encoder.dateEncodingStrategy = dateEncodingStrategy
50 | encoder.dataEncodingStrategy = dataEncodingStrategy
51 | return try? encoder.encode(self)
52 | }
53 |
54 | /**
55 | Convert this object to a json string
56 |
57 | - parameter outputFormatting: The formatting of the output JSON data (compact or pritty printed)
58 | - parameter dateEncodinStrategy: how do you want to format the date
59 | - parameter dataEncodingStrategy: what kind of encoding. base64 is the default
60 |
61 | - returns: The json string
62 | */
63 | func toJsonString(outputFormatting: JSONEncoder.OutputFormatting = [], dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .deferredToDate, dataEncodingStrategy: JSONEncoder.DataEncodingStrategy = .base64) -> String? {
64 | let data = self.toJsonData(outputFormatting: outputFormatting, dateEncodingStrategy: dateEncodingStrategy, dataEncodingStrategy: dataEncodingStrategy)
65 | return data == nil ? nil : String(data: data!, encoding: .utf8)
66 | }
67 |
68 |
69 | /**
70 | Save this object to a file in the temp directory
71 |
72 | - parameter fileName: The filename
73 |
74 | - returns: Nothing
75 | */
76 | func saveTo(_ fileURL: URL) throws {
77 | guard let data = self.toJsonData() else { throw CodingError.RuntimeError("cannot create data from object")}
78 | try data.write(to: fileURL, options: .atomic)
79 | }
80 |
81 |
82 | /**
83 | Save this object to a file in the temp directory
84 |
85 | - parameter fileName: The filename
86 |
87 | - returns: Nothing
88 | */
89 | func saveToTemp(_ fileName: String) throws {
90 | let fileURL = try FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(fileName)
91 | try self.saveTo(fileURL)
92 | }
93 |
94 |
95 |
96 | #if os(tvOS)
97 | // Save to documents folder is not supported on tvOS
98 | #else
99 | /**
100 | Save this object to a file in the documents directory
101 |
102 | - parameter fileName: The filename
103 |
104 | - returns: true if successfull
105 | */
106 | func saveToDocuments(_ fileName: String) throws {
107 | let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(fileName)
108 | try self.saveTo(fileURL)
109 | }
110 | #endif
111 | }
112 |
113 | public extension Decodable {
114 | /**
115 | Create an instance of this type from a json string
116 |
117 | - parameter json: The json string
118 | - parameter keyPath: for if you want something else than the root object
119 | */
120 | init(json: String, keyPath: String? = nil,
121 | keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .convertFromSnakeCase,
122 | dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate,
123 | dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .base64,
124 | nonConformingFloatDecodingStrategy: JSONDecoder.NonConformingFloatDecodingStrategy = .throw) throws {
125 | guard let data = json.data(using: .utf8) else { throw CodingError.RuntimeError("cannot create data from string") }
126 | try self.init(data: data, keyPath: keyPath, keyDecodingStrategy: keyDecodingStrategy, dateDecodingStrategy: dateDecodingStrategy, dataDecodingStrategy: dataDecodingStrategy, nonConformingFloatDecodingStrategy: nonConformingFloatDecodingStrategy)
127 | }
128 |
129 | /**
130 | Create an instance of this type from a json string
131 |
132 | - parameter data: The json data
133 | - parameter keyPath: for if you want something else than the root object
134 | */
135 | init(data: Data, keyPath: String? = nil,
136 | keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .convertFromSnakeCase,
137 | dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate,
138 | dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .base64,
139 | nonConformingFloatDecodingStrategy: JSONDecoder.NonConformingFloatDecodingStrategy = .throw) throws {
140 |
141 | let decoder = JSONDecoder()
142 | decoder.keyDecodingStrategy = keyDecodingStrategy
143 | decoder.dateDecodingStrategy = dateDecodingStrategy
144 | decoder.dataDecodingStrategy = dataDecodingStrategy
145 | decoder.nonConformingFloatDecodingStrategy = nonConformingFloatDecodingStrategy
146 |
147 | if let keyPath = keyPath {
148 | let topLevel = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)
149 | guard let nestedJson = (topLevel as AnyObject).value(forKeyPath: keyPath) else { throw CodingError.RuntimeError("Cannot decode data to object") }
150 | let nestedData = try JSONSerialization.data(withJSONObject: nestedJson)
151 | self = try decoder.decode(Self.self, from: nestedData)
152 | return
153 | }
154 | self = try decoder.decode(Self.self, from: data)
155 | }
156 |
157 | /**
158 | Initialize this object from an archived file from an URL
159 |
160 | - parameter fileNameInTemp: The filename
161 | */
162 | init(fileURL: URL) throws {
163 | let data = try Data(contentsOf: fileURL)
164 | try self.init(data: data)
165 | }
166 |
167 | /**
168 | Initialize this object from an archived file from the temp directory
169 |
170 | - parameter fileNameInTemp: The filename
171 | */
172 | init(fileNameInTemp: String) throws {
173 | let fileURL = try FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(fileNameInTemp)
174 | try self.init(fileURL: fileURL)
175 | }
176 |
177 | /**
178 | Initialize this object from an archived file from the documents directory
179 |
180 | - parameter fileNameInDocuments: The filename
181 | */
182 | init(fileNameInDocuments: String) throws {
183 | let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(fileNameInDocuments)
184 | try self.init(fileURL: fileURL)
185 | }
186 | }
187 |
188 |
189 |
--------------------------------------------------------------------------------
/Source/Enum/Enum.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnumExtensions.swift
3 | // Stuff
4 | //
5 | // Created by Edwin Vermeer on 10/02/2017.
6 | // Copyright © 2017 EVICT BV. All rights reserved.
7 | //
8 |
9 |
10 | /**
11 | Protocol for the enum extension functions
12 | */
13 | public protocol Enum {
14 | }
15 |
16 | /**
17 | Protocol for the workaround when using an enum with a rawValue of an undefined type
18 | */
19 | public protocol RawEnum {
20 | /**
21 | For implementing a function that will return the rawValue for a non sepecific enum
22 | */
23 | var anyRawValue: Any { get }
24 | }
25 |
26 |
27 | /**
28 | Enum extension for getting the associated value of an enum
29 | */
30 | public extension Enum {
31 | /**
32 | Get the associated value of the enum
33 | */
34 | var associated: (label: String, value: Any?, values: [Any]) {
35 | get {
36 | let mirror = Mirror(reflecting: self)
37 | if mirror.displayStyle == .enum {
38 | if let associated = mirror.children.first {
39 | let values = Mirror(reflecting: associated.value).children
40 | var valuesArray = [Any]()
41 | for item in values {
42 | valuesArray.append(item.value)
43 | }
44 | return (associated.label!, associated.value, valuesArray)
45 | }
46 | print("WARNING: Enum option of \(self) does not have an associated value")
47 | return ("\(self)", nil, [])
48 | }
49 | print("WARNING: You can only extend an enum with the EnumExtension")
50 | return ("\(self)", nil, [])
51 | }
52 | }
53 | }
54 |
55 |
56 | /**
57 | Enum extension for getting all enum options in an array
58 | */
59 | public extension Enum where Self: Hashable {
60 | /**
61 | Return all enum values
62 | */
63 | static var allValues: [Self] {
64 | return [Self](AnySequence { () -> AnyIterator in
65 | var raw = 0
66 | var first: Self?
67 | return AnyIterator {
68 | let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
69 | if raw == 0 {
70 | first = current
71 | } else if current == first {
72 | return nil
73 | }
74 | raw += 1
75 | return current
76 | }
77 | })
78 | }
79 | }
80 |
81 |
82 | /**
83 | Enum extension for getting the rawValue even if the enum is passed in an Enum
84 | */
85 | public extension RawEnum where Self: RawRepresentable {
86 | /**
87 | Return the raw value of the enum
88 | */
89 | var anyRawValue: Any {
90 | get {
91 | let mirror = Mirror(reflecting: self)
92 | if mirror.displayStyle != .enum {
93 | print("WARNING: You can only extend an enum with the Enum protocol")
94 | }
95 | return rawValue as Any
96 |
97 | }
98 | }
99 | }
100 |
101 | /**
102 | extension for creating a querystring from an array of Enum values (with associated value)
103 | */
104 | public extension Array where Element: Enum {
105 | var queryString: String {
106 | get {
107 | return (self.map {"\($0.associated.label)=\($0.associated.value!)"}).joined(separator: ",")
108 | }
109 | }
110 | }
111 |
112 |
113 | /**
114 | Dictionary extension for creating a dictionary from an array of enum values
115 | */
116 | public extension Dictionary {
117 | /**
118 | Create a dictionairy based on all associated values of an enum array
119 |
120 | - parameter associated: array of dictionairy values which have an associated value
121 |
122 | */
123 | init(_ associated: [T]?) {
124 | self.init()
125 | if associated != nil {
126 | for myEnum in associated! {
127 | self[(myEnum.associated.label as? Key)!] = myEnum.associated.value as? Value
128 | }
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/Source/Print/Print.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Print.swift
3 | //
4 | // Created by Edwin Vermeer on 29/01/2017.
5 | // Copyright © 2017 EVICT BV. All rights reserved.
6 | //
7 |
8 | import Foundation
9 | import os.log
10 |
11 | /**
12 | Extending the Stuff object with print functionality
13 | */
14 | public extension Stuff {
15 |
16 | /**
17 | Enumeration of the log levels
18 | */
19 | enum logLevel: Int {
20 | // Make sure all log events goes to the device log
21 | case productionLogAll = 0
22 | // Informational loging, lowest level
23 | case info = 1
24 | // Debug loging, default level
25 | case debug = 2
26 | // Warning loging, You should take notice
27 | case warn = 3
28 | // Error loging, Something went wrong, take action
29 | case error = 4
30 | // Fatal loging, Something went seriously wrong, can't recover from it.
31 | case fatal = 5
32 | // Set the minimumLogLevel to .none to stop everything from loging
33 | case none = 6
34 |
35 | /**
36 | Get the emoticon for the log level.
37 | */
38 | public func description() -> String {
39 | switch self {
40 | case .info:
41 | return "❓"
42 | case .debug:
43 | return "✳️"
44 | case .warn:
45 | return "⚠️"
46 | case .error:
47 | return "🚫"
48 | case .fatal:
49 | return "🆘"
50 | case .productionLogAll:
51 | return "🚧"
52 | case .none:
53 | return ""
54 | }
55 | }
56 | }
57 |
58 | /**
59 | Set the minimum log level. By default set to .info which is the minimum. Everything will be loged.
60 | */
61 | static var minimumLogLevel: logLevel = .info
62 |
63 | /**
64 | The print command for writing to the output window
65 | */
66 | static func print(_ object: T, _ level: logLevel = (T.self is Error ? .error : .debug), showTrace: Bool = false, filename: String = #file, line: Int = #line, funcname: String = #function, trace: [String] = Thread.callStackSymbols) {
67 | if level.rawValue >= Stuff.minimumLogLevel.rawValue {
68 | let dateFormatter = DateFormatter()
69 | dateFormatter.dateFormat = "MM/dd/yyyy HH:mm:ss:SSS"
70 | let process = ProcessInfo.processInfo
71 | let threadId = Thread.current.name ?? ""
72 | let file = URL(string: filename)?.lastPathComponent ?? ""
73 | let traceOutput: String = !showTrace ? "" : trace.map { "\t\t\($0)" }.reduce("\n") { "\($0)\n\($1)" }
74 | let output: String = object is Error ? "\((object as! Error).localizedDescription)\(traceOutput)" : "\(object)"
75 | let logText = "\n\(level.description()) .\(level) ⏱ \(dateFormatter.string(from: Foundation.Date())) 📱 \(process.processName) [\(process.processIdentifier):\(threadId)] 📂 \(file)(\(line)) ⚙️ \(funcname) ➡️\r\t\(output)"
76 | if Stuff.minimumLogLevel == .productionLogAll || level == .productionLogAll {
77 | if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3 , *) {
78 | let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Stuff")
79 | os_log("%{public}@", log: log, logText)
80 | } else {
81 | NSLog("#Stuff# /(logText)")
82 | }
83 | } else {
84 | Swift.print(logText)
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Source/Stuff.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Stuff.swift
3 | //
4 | // Created by Edwin Vermeer on 29/01/2017.
5 | // Copyright © 2017 EVICT BV. All rights reserved.
6 | //
7 |
8 | /**
9 | Just the root class for extending with generic functionality (See Print)
10 | */
11 | open class Stuff {
12 | }
13 |
--------------------------------------------------------------------------------
/Source/TODO/TODO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TODO.swift
3 | //
4 | // Created by Edwin Vermeer on 28/02/2017.
5 | // Copyright © 2017 EVICT BV. All rights reserved.
6 | //
7 |
8 | @available(*, deprecated, message: "TODO left in code")
9 | func TODO(_ log: String = "") {
10 | print("⚠️ TODO code is still in use! ⚠️\n\(log)")
11 | }
12 |
13 | @available(*, deprecated, message: "TODO left in code")
14 | var TODO_: Never {
15 | fatalError("TODO left in code")
16 | }
17 |
--------------------------------------------------------------------------------
/Stuff.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "Stuff"
3 | s.version = "1.1.2"
4 | s.summary = "Too small for a library, too important to just forget"
5 |
6 | s.description = <<-EOS
7 | This is a collection of helpfull code that is difficult to place in a specific library.
8 | EOS
9 |
10 | s.homepage = "https://github.com/evermeer/Stuff"
11 | s.license = { :type => "MIT", :file => "License" }
12 | s.author = { "Edwin Vermeer" => "edwin@evict.nl" }
13 | s.social_media_url = "http://twitter.com/evermeer"
14 |
15 | s.ios.deployment_target = '8.0'
16 | s.osx.deployment_target = '10.10'
17 | s.watchos.deployment_target = '2.0'
18 | s.tvos.deployment_target = '9.0'
19 |
20 | s.source = { :git => "https://github.com/evermeer/Stuff.git", :tag => s.version }
21 | s.default_subspec = "All"
22 |
23 | # This is the complete Stuff library
24 | s.subspec "All" do |ss|
25 | ss.dependency "Stuff/Enum"
26 | ss.dependency "Stuff/Print"
27 | ss.dependency "Stuff/TODO"
28 | ss.dependency "Stuff/Codable"
29 | end
30 |
31 | # This is the core Print library
32 | s.subspec "Print" do |ss|
33 | ss.source_files = "Source/*.swift", "Source/Print/*.swift"
34 | end
35 |
36 | # This is the core Enum library
37 | s.subspec "Enum" do |ss|
38 | ss.source_files = "Source/*.swift", "Source/Enum/*.swift"
39 | end
40 |
41 | # This is the core TODO library
42 | s.subspec "TODO" do |ss|
43 | ss.source_files = "Source/TODO/*.swift"
44 | end
45 |
46 | # This is the core Coding library
47 | s.subspec "Codable" do |ss|
48 | ss.source_files = "Source/Codable/*.swift"
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/Stuff.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 08E428A7B01137966D47BE47 /* Pods_StuffTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E27E8C40F9CACB5D81F585D5 /* Pods_StuffTests.framework */; };
11 | 13E8825E1F03CF3900F1DA7D /* CodableStuffTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13E8825D1F03CF3900F1DA7D /* CodableStuffTests.swift */; };
12 | 7F29F37C1E4E05070048B915 /* EnumStuffTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F29F37B1E4E05070048B915 /* EnumStuffTests.swift */; };
13 | 7F9A2FC81E51A9C8004450B6 /* PrintStuffTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9A2FC71E51A9C8004450B6 /* PrintStuffTests.swift */; };
14 | 7FF3E19E1E65888A0057B575 /* TODOStuffTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FF3E19D1E65888A0057B575 /* TODOStuffTests.swift */; };
15 | /* End PBXBuildFile section */
16 |
17 | /* Begin PBXFileReference section */
18 | 0BD3780882CCECD3D4223F11 /* Pods-StuffTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StuffTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-StuffTests/Pods-StuffTests.debug.xcconfig"; sourceTree = ""; };
19 | 13E8825D1F03CF3900F1DA7D /* CodableStuffTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableStuffTests.swift; sourceTree = ""; };
20 | 14C53FB6FF7E4E49FE104565 /* Pods-StuffTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StuffTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-StuffTests/Pods-StuffTests.release.xcconfig"; sourceTree = ""; };
21 | 7F29F37B1E4E05070048B915 /* EnumStuffTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumStuffTests.swift; sourceTree = ""; };
22 | 7F29F37D1E4E05070048B915 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
23 | 7F29F3861E4E092C0048B915 /* StuffTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StuffTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
24 | 7F9A2FC71E51A9C8004450B6 /* PrintStuffTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrintStuffTests.swift; sourceTree = ""; };
25 | 7FF3E19D1E65888A0057B575 /* TODOStuffTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TODOStuffTests.swift; sourceTree = ""; };
26 | E27E8C40F9CACB5D81F585D5 /* Pods_StuffTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_StuffTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
27 | /* End PBXFileReference section */
28 |
29 | /* Begin PBXFrameworksBuildPhase section */
30 | 7F29F3741E4E05070048B915 /* Frameworks */ = {
31 | isa = PBXFrameworksBuildPhase;
32 | buildActionMask = 2147483647;
33 | files = (
34 | 08E428A7B01137966D47BE47 /* Pods_StuffTests.framework in Frameworks */,
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | 50526C767D66A5D96A2B0D34 /* Frameworks */ = {
42 | isa = PBXGroup;
43 | children = (
44 | E27E8C40F9CACB5D81F585D5 /* Pods_StuffTests.framework */,
45 | );
46 | name = Frameworks;
47 | sourceTree = "";
48 | };
49 | 7F29F35A1E4E05070048B915 = {
50 | isa = PBXGroup;
51 | children = (
52 | 7F29F37A1E4E05070048B915 /* StuffTests */,
53 | 973835B12DDA3113D12045C3 /* Pods */,
54 | 50526C767D66A5D96A2B0D34 /* Frameworks */,
55 | 7F29F3861E4E092C0048B915 /* StuffTests.xctest */,
56 | );
57 | sourceTree = "";
58 | };
59 | 7F29F37A1E4E05070048B915 /* StuffTests */ = {
60 | isa = PBXGroup;
61 | children = (
62 | 13E8825D1F03CF3900F1DA7D /* CodableStuffTests.swift */,
63 | 7F29F37B1E4E05070048B915 /* EnumStuffTests.swift */,
64 | 7F9A2FC71E51A9C8004450B6 /* PrintStuffTests.swift */,
65 | 7FF3E19D1E65888A0057B575 /* TODOStuffTests.swift */,
66 | 7F29F37D1E4E05070048B915 /* Info.plist */,
67 | );
68 | path = StuffTests;
69 | sourceTree = "";
70 | };
71 | 973835B12DDA3113D12045C3 /* Pods */ = {
72 | isa = PBXGroup;
73 | children = (
74 | 0BD3780882CCECD3D4223F11 /* Pods-StuffTests.debug.xcconfig */,
75 | 14C53FB6FF7E4E49FE104565 /* Pods-StuffTests.release.xcconfig */,
76 | );
77 | name = Pods;
78 | sourceTree = "";
79 | };
80 | /* End PBXGroup section */
81 |
82 | /* Begin PBXNativeTarget section */
83 | 7F29F3761E4E05070048B915 /* StuffTests */ = {
84 | isa = PBXNativeTarget;
85 | buildConfigurationList = 7F29F3831E4E05070048B915 /* Build configuration list for PBXNativeTarget "StuffTests" */;
86 | buildPhases = (
87 | F3824567CF8D34B0A4F24E01 /* [CP] Check Pods Manifest.lock */,
88 | 7F29F3731E4E05070048B915 /* Sources */,
89 | 7F29F3741E4E05070048B915 /* Frameworks */,
90 | 7F29F3751E4E05070048B915 /* Resources */,
91 | 25B19118C00DCF76F87052DF /* [CP] Embed Pods Frameworks */,
92 | );
93 | buildRules = (
94 | );
95 | dependencies = (
96 | );
97 | name = StuffTests;
98 | productName = StuffTests;
99 | productReference = 7F29F3861E4E092C0048B915 /* StuffTests.xctest */;
100 | productType = "com.apple.product-type.bundle.unit-test";
101 | };
102 | /* End PBXNativeTarget section */
103 |
104 | /* Begin PBXProject section */
105 | 7F29F35B1E4E05070048B915 /* Project object */ = {
106 | isa = PBXProject;
107 | attributes = {
108 | LastSwiftUpdateCheck = 0820;
109 | LastUpgradeCheck = 1020;
110 | ORGANIZATIONNAME = evict;
111 | TargetAttributes = {
112 | 7F29F3761E4E05070048B915 = {
113 | CreatedOnToolsVersion = 8.2.1;
114 | DevelopmentTeam = X356V8CMHF;
115 | LastSwiftMigration = 0910;
116 | ProvisioningStyle = Automatic;
117 | };
118 | };
119 | };
120 | buildConfigurationList = 7F29F35E1E4E05070048B915 /* Build configuration list for PBXProject "Stuff" */;
121 | compatibilityVersion = "Xcode 3.2";
122 | developmentRegion = en;
123 | hasScannedForEncodings = 0;
124 | knownRegions = (
125 | en,
126 | Base,
127 | );
128 | mainGroup = 7F29F35A1E4E05070048B915;
129 | productRefGroup = 7F29F35A1E4E05070048B915;
130 | projectDirPath = "";
131 | projectRoot = "";
132 | targets = (
133 | 7F29F3761E4E05070048B915 /* StuffTests */,
134 | );
135 | };
136 | /* End PBXProject section */
137 |
138 | /* Begin PBXResourcesBuildPhase section */
139 | 7F29F3751E4E05070048B915 /* Resources */ = {
140 | isa = PBXResourcesBuildPhase;
141 | buildActionMask = 2147483647;
142 | files = (
143 | );
144 | runOnlyForDeploymentPostprocessing = 0;
145 | };
146 | /* End PBXResourcesBuildPhase section */
147 |
148 | /* Begin PBXShellScriptBuildPhase section */
149 | 25B19118C00DCF76F87052DF /* [CP] Embed Pods Frameworks */ = {
150 | isa = PBXShellScriptBuildPhase;
151 | buildActionMask = 2147483647;
152 | files = (
153 | );
154 | inputPaths = (
155 | "${PODS_ROOT}/Target Support Files/Pods-StuffTests/Pods-StuffTests-frameworks.sh",
156 | "${BUILT_PRODUCTS_DIR}/Stuff/Stuff.framework",
157 | );
158 | name = "[CP] Embed Pods Frameworks";
159 | outputPaths = (
160 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Stuff.framework",
161 | );
162 | runOnlyForDeploymentPostprocessing = 0;
163 | shellPath = /bin/sh;
164 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-StuffTests/Pods-StuffTests-frameworks.sh\"\n";
165 | showEnvVarsInLog = 0;
166 | };
167 | F3824567CF8D34B0A4F24E01 /* [CP] Check Pods Manifest.lock */ = {
168 | isa = PBXShellScriptBuildPhase;
169 | buildActionMask = 2147483647;
170 | files = (
171 | );
172 | inputPaths = (
173 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
174 | "${PODS_ROOT}/Manifest.lock",
175 | );
176 | name = "[CP] Check Pods Manifest.lock";
177 | outputPaths = (
178 | "$(DERIVED_FILE_DIR)/Pods-StuffTests-checkManifestLockResult.txt",
179 | );
180 | runOnlyForDeploymentPostprocessing = 0;
181 | shellPath = /bin/sh;
182 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
183 | showEnvVarsInLog = 0;
184 | };
185 | /* End PBXShellScriptBuildPhase section */
186 |
187 | /* Begin PBXSourcesBuildPhase section */
188 | 7F29F3731E4E05070048B915 /* Sources */ = {
189 | isa = PBXSourcesBuildPhase;
190 | buildActionMask = 2147483647;
191 | files = (
192 | 7F9A2FC81E51A9C8004450B6 /* PrintStuffTests.swift in Sources */,
193 | 7FF3E19E1E65888A0057B575 /* TODOStuffTests.swift in Sources */,
194 | 7F29F37C1E4E05070048B915 /* EnumStuffTests.swift in Sources */,
195 | 13E8825E1F03CF3900F1DA7D /* CodableStuffTests.swift in Sources */,
196 | );
197 | runOnlyForDeploymentPostprocessing = 0;
198 | };
199 | /* End PBXSourcesBuildPhase section */
200 |
201 | /* Begin XCBuildConfiguration section */
202 | 7F29F37E1E4E05070048B915 /* Debug */ = {
203 | isa = XCBuildConfiguration;
204 | buildSettings = {
205 | ALWAYS_SEARCH_USER_PATHS = NO;
206 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
207 | CLANG_ANALYZER_NONNULL = YES;
208 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
209 | CLANG_CXX_LIBRARY = "libc++";
210 | CLANG_ENABLE_MODULES = YES;
211 | CLANG_ENABLE_OBJC_ARC = YES;
212 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
213 | CLANG_WARN_BOOL_CONVERSION = YES;
214 | CLANG_WARN_COMMA = YES;
215 | CLANG_WARN_CONSTANT_CONVERSION = YES;
216 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
217 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
218 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
219 | CLANG_WARN_EMPTY_BODY = YES;
220 | CLANG_WARN_ENUM_CONVERSION = YES;
221 | CLANG_WARN_INFINITE_RECURSION = YES;
222 | CLANG_WARN_INT_CONVERSION = YES;
223 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
224 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
225 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
226 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
227 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
228 | CLANG_WARN_STRICT_PROTOTYPES = YES;
229 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
230 | CLANG_WARN_UNREACHABLE_CODE = YES;
231 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
232 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: evermeer@beterdichtbij.nl (4SA8U36ZTM)";
233 | COPY_PHASE_STRIP = NO;
234 | DEBUG_INFORMATION_FORMAT = dwarf;
235 | ENABLE_STRICT_OBJC_MSGSEND = YES;
236 | ENABLE_TESTABILITY = YES;
237 | GCC_C_LANGUAGE_STANDARD = gnu99;
238 | GCC_DYNAMIC_NO_PIC = NO;
239 | GCC_NO_COMMON_BLOCKS = YES;
240 | GCC_OPTIMIZATION_LEVEL = 0;
241 | GCC_PREPROCESSOR_DEFINITIONS = (
242 | "DEBUG=1",
243 | "$(inherited)",
244 | );
245 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
246 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
247 | GCC_WARN_UNDECLARED_SELECTOR = YES;
248 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
249 | GCC_WARN_UNUSED_FUNCTION = YES;
250 | GCC_WARN_UNUSED_VARIABLE = YES;
251 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
252 | MTL_ENABLE_DEBUG_INFO = YES;
253 | ONLY_ACTIVE_ARCH = YES;
254 | SDKROOT = iphoneos;
255 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
256 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
257 | SWIFT_VERSION = 5.0;
258 | TARGETED_DEVICE_FAMILY = "1,2";
259 | };
260 | name = Debug;
261 | };
262 | 7F29F37F1E4E05070048B915 /* Release */ = {
263 | isa = XCBuildConfiguration;
264 | buildSettings = {
265 | ALWAYS_SEARCH_USER_PATHS = NO;
266 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
267 | CLANG_ANALYZER_NONNULL = YES;
268 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
269 | CLANG_CXX_LIBRARY = "libc++";
270 | CLANG_ENABLE_MODULES = YES;
271 | CLANG_ENABLE_OBJC_ARC = YES;
272 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
273 | CLANG_WARN_BOOL_CONVERSION = YES;
274 | CLANG_WARN_COMMA = YES;
275 | CLANG_WARN_CONSTANT_CONVERSION = YES;
276 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
277 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
278 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
279 | CLANG_WARN_EMPTY_BODY = YES;
280 | CLANG_WARN_ENUM_CONVERSION = YES;
281 | CLANG_WARN_INFINITE_RECURSION = YES;
282 | CLANG_WARN_INT_CONVERSION = YES;
283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
284 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
285 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
286 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
287 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
288 | CLANG_WARN_STRICT_PROTOTYPES = YES;
289 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
290 | CLANG_WARN_UNREACHABLE_CODE = YES;
291 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
292 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: evermeer@beterdichtbij.nl (4SA8U36ZTM)";
293 | COPY_PHASE_STRIP = NO;
294 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
295 | ENABLE_NS_ASSERTIONS = NO;
296 | ENABLE_STRICT_OBJC_MSGSEND = YES;
297 | GCC_C_LANGUAGE_STANDARD = gnu99;
298 | GCC_NO_COMMON_BLOCKS = YES;
299 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
300 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
301 | GCC_WARN_UNDECLARED_SELECTOR = YES;
302 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
303 | GCC_WARN_UNUSED_FUNCTION = YES;
304 | GCC_WARN_UNUSED_VARIABLE = YES;
305 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
306 | MTL_ENABLE_DEBUG_INFO = NO;
307 | SDKROOT = iphoneos;
308 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
309 | SWIFT_VERSION = 5.0;
310 | TARGETED_DEVICE_FAMILY = "1,2";
311 | VALIDATE_PRODUCT = YES;
312 | };
313 | name = Release;
314 | };
315 | 7F29F3841E4E05070048B915 /* Debug */ = {
316 | isa = XCBuildConfiguration;
317 | baseConfigurationReference = 0BD3780882CCECD3D4223F11 /* Pods-StuffTests.debug.xcconfig */;
318 | buildSettings = {
319 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
320 | DEVELOPMENT_TEAM = X356V8CMHF;
321 | INFOPLIST_FILE = StuffTests/Info.plist;
322 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
323 | PRODUCT_BUNDLE_IDENTIFIER = nl.evict.StuffTests;
324 | PRODUCT_NAME = "$(TARGET_NAME)";
325 | SWIFT_VERSION = 5.0;
326 | };
327 | name = Debug;
328 | };
329 | 7F29F3851E4E05070048B915 /* Release */ = {
330 | isa = XCBuildConfiguration;
331 | baseConfigurationReference = 14C53FB6FF7E4E49FE104565 /* Pods-StuffTests.release.xcconfig */;
332 | buildSettings = {
333 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
334 | DEVELOPMENT_TEAM = X356V8CMHF;
335 | INFOPLIST_FILE = StuffTests/Info.plist;
336 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
337 | PRODUCT_BUNDLE_IDENTIFIER = nl.evict.StuffTests;
338 | PRODUCT_NAME = "$(TARGET_NAME)";
339 | SWIFT_VERSION = 5.0;
340 | };
341 | name = Release;
342 | };
343 | /* End XCBuildConfiguration section */
344 |
345 | /* Begin XCConfigurationList section */
346 | 7F29F35E1E4E05070048B915 /* Build configuration list for PBXProject "Stuff" */ = {
347 | isa = XCConfigurationList;
348 | buildConfigurations = (
349 | 7F29F37E1E4E05070048B915 /* Debug */,
350 | 7F29F37F1E4E05070048B915 /* Release */,
351 | );
352 | defaultConfigurationIsVisible = 0;
353 | defaultConfigurationName = Release;
354 | };
355 | 7F29F3831E4E05070048B915 /* Build configuration list for PBXNativeTarget "StuffTests" */ = {
356 | isa = XCConfigurationList;
357 | buildConfigurations = (
358 | 7F29F3841E4E05070048B915 /* Debug */,
359 | 7F29F3851E4E05070048B915 /* Release */,
360 | );
361 | defaultConfigurationIsVisible = 0;
362 | defaultConfigurationName = Release;
363 | };
364 | /* End XCConfigurationList section */
365 | };
366 | rootObject = 7F29F35B1E4E05070048B915 /* Project object */;
367 | }
368 |
--------------------------------------------------------------------------------
/Stuff.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Stuff.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
15 |
16 |
18 |
19 |
21 |
22 |
24 |
25 |
27 |
28 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Stuff.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/StuffTests/CodableStuffTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodableStuffTests.swift
3 | // StuffTests
4 | //
5 | // Created by Vermeer, Edwin on 28/06/2017.
6 | // Copyright © 2017 evict. All rights reserved.
7 | //
8 |
9 |
10 | import XCTest
11 | @testable import Stuff
12 |
13 | class CodingStuffTests: XCTestCase {
14 |
15 | func test() {
16 | let initialObject = TestCodable(naam: "Edwin", id: 1, testField: "tst")
17 |
18 | guard let json = initialObject.toJsonString() else {
19 | print("Could not create json from object")
20 | assertionFailure()
21 | return
22 | }
23 | print("Json string of object = \n\t\(json)")
24 |
25 | guard let newObject = try? TestCodable(json: json) else {
26 | print("Could not create object from json")
27 | assertionFailure()
28 | return
29 | }
30 | print("Object created with json = \n\t\(String(describing: newObject))")
31 |
32 | let json2 = "[{\"id\":1,\"naam\":\"Edwin\"},{\"id\":2,\"naam\":\"Vermeer\"}]"
33 | guard let array = try? [TestCodable](json: json2) else {
34 | print("Could not create object array from json")
35 | assertionFailure()
36 | return
37 | }
38 | print("Object array created with json = \(String(describing: array))")
39 |
40 | let newJson = array.toJsonString() ?? ""
41 | print("Json from object array = \n\t\(newJson)")
42 |
43 | guard let innerObject = try? TestCodable(json: "{\"user\":{\"id\":1,\"naam\":\"Edwin\"}}", keyPath: "user") else {
44 | print("Could not create object from json")
45 | assertionFailure()
46 | return
47 | }
48 | print("inner object from json \(String(describing: innerObject))")
49 |
50 | do {
51 | let custom = try TestCodable(json: "{\"Naam\":\"UN\", \"Id\":5, \"Test_field\":\"tst\"}", keyPath: nil, keyDecodingStrategy: customCodingStragegy)
52 | print("read object with custom key coding from json to \(String(describing: custom))")
53 | } catch {
54 | print("Could not custom case convert \(error)")
55 | assertionFailure()
56 | return
57 | }
58 |
59 | do {
60 | try initialObject.saveToDocuments("myFile.dat")
61 | } catch {
62 | print("Could not write to documents data : \(error)")
63 | // assertionFailure()
64 | return
65 | }
66 | guard let readObject = try? TestCodable(fileNameInDocuments: "myFile.dat") else {
67 | print("Could not read from documents data")
68 | assertionFailure()
69 | return
70 | }
71 | print("read object from documents \(String(describing: readObject))")
72 |
73 | do {
74 | try array.saveToDocuments("myFile2.dat")
75 | } catch {
76 | print("Could not write to documents data")
77 | assertionFailure()
78 | return
79 | }
80 | guard let readObjectArray = try? [TestCodable](fileNameInDocuments: "myFile2.dat") else {
81 | print("Could not read from documents data")
82 | assertionFailure()
83 | return
84 | }
85 | print("read object array from documents \(String(describing: readObjectArray))")
86 | }
87 | }
88 |
89 | struct TestCodable : Codable {
90 | var naam: String?
91 | var id: Int?
92 | var testField: String?
93 | }
94 |
--------------------------------------------------------------------------------
/StuffTests/EnumStuffTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StuffTests.swift
3 | // StuffTests
4 | //
5 | // Created by Edwin Vermeer on 10/02/2017.
6 | // Copyright © 2017 evict. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Stuff
11 |
12 | class EnumStuffTests: XCTestCase {
13 |
14 | // You have to extend the enum with the Enum protocol (and RawEnum if you want the raw value when it's an Any)
15 | enum test1: String, Enum, RawEnum {
16 | case option1
17 | case option2
18 | case option3
19 | }
20 |
21 | // You have to extend the enum with the Enum protocol
22 | enum test2: Enum {
23 | case option4(String)
24 | case option5(Int)
25 | case option6(Int, String)
26 | }
27 |
28 | func testEnum() {
29 | XCTAssert(test1.allValues.count == 3, "There should be 3 values")
30 | for value in test1.allValues {
31 | print("value = \(value)")
32 | }
33 |
34 | let v1: test2 = .option4("test")
35 | print("v1 = \(v1.associated.label), \(v1.associated.value!)")
36 | let v2: test2 = .option5(3)
37 | print("v2 = \(v2.associated.label), \(v2.associated.value!)")
38 | let v3: test2 = .option6(4, "more")
39 | print("v3 = \(v3.associated.label), \(v3.associated.value!)")
40 | print("v3 = \(v3.associated.label), \(v3.associated.values)")
41 |
42 | let array = [v1, v2, v3]
43 | let dict = [String:Any](array)
44 | print("Array of enums as dictionary:\n \(dict)")
45 |
46 | print("query = \(array.queryString))")
47 |
48 | let v = getRawValue(test1.option2)
49 | print("raw value = \(v)")
50 | }
51 |
52 | func getRawValue(_ value: Any) -> Any {
53 | return (value as? RawEnum)?.anyRawValue ?? ""
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/StuffTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/StuffTests/PrintStuffTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PrintStuffTests.swift
3 | // Stuff
4 | //
5 | // Created by Edwin Vermeer on 13/02/2017.
6 | // Copyright © 2017 evict. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Stuff
11 |
12 | class PrintStuffTests: XCTestCase {
13 |
14 | func testPrint() {
15 | Stuff.print("Just as the standard print but now with detailed information")
16 | Stuff.print("Now it's a warning", .warn)
17 | Stuff.print("Or even an error", .error)
18 |
19 | Stuff.minimumLogLevel = .error
20 | Stuff.print("Now you won't see normal log output")
21 | Stuff.print("Only errors are shown", .error)
22 |
23 | Stuff.minimumLogLevel = .none
24 | Stuff.print("Or if it's disabled you won't see any log", .error)
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/StuffTests/TODOStuffTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TODOStuffTests.swift
3 | // Stuff
4 | //
5 | // Created by Edwin Vermeer on 28/02/2017.
6 | // Copyright © 2017 evict. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Stuff
11 |
12 | class TODOStuffTests: XCTestCase {
13 |
14 | func testTODO() {
15 | // We need to fix something, but function can run
16 | TODO()
17 |
18 | TODO("An other todo, now giving some detailed info")
19 |
20 | // We need to fix this. Otherwise just fail. The tet will crash here. See the stacktrace
21 | //Cant test anymore TODO_
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------