{"id":16487200,"url":"https://github.com/nerdsupremacist/sweeft","last_synced_at":"2025-03-23T12:33:33.801Z","repository":{"id":62456328,"uuid":"74278503","full_name":"nerdsupremacist/Sweeft","owner":"nerdsupremacist","description":"Swift but a bit Sweeter - More Syntactic Sugar for Swift #MakeSwiftGreatAgain","archived":false,"fork":false,"pushed_at":"2018-10-21T08:50:47.000Z","size":574,"stargazers_count":21,"open_issues_count":4,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-14T21:17:41.861Z","etag":null,"topics":["api","closure","cocoapods","extensions","functional-programming","json","library","sweet","swift","syntax"],"latest_commit_sha":null,"homepage":"https://cocoapods.org/pods/Sweeft","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nerdsupremacist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-20T14:09:46.000Z","updated_at":"2023-10-18T13:00:38.000Z","dependencies_parsed_at":"2022-11-02T00:15:18.418Z","dependency_job_id":null,"html_url":"https://github.com/nerdsupremacist/Sweeft","commit_stats":null,"previous_names":["mathiasquintero/sweeft"],"tags_count":70,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSweeft","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSweeft/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSweeft/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FSweeft/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nerdsupremacist","download_url":"https://codeload.github.com/nerdsupremacist/Sweeft/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244297871,"owners_count":20430347,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","closure","cocoapods","extensions","functional-programming","json","library","sweet","swift","syntax"],"created_at":"2024-10-11T13:33:11.380Z","updated_at":"2025-03-23T12:33:33.461Z","avatar_url":"https://github.com/nerdsupremacist.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv style=\"text-align:center;\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/mathiasquintero/Sweeft/master/logo.png\" height=250\u003e\u003c/div\u003e\n\n\n# Sweeft\nSwift but a bit Sweeter - More Syntactic Sugar for Swift\n\nThis is a collection of extensions and operators that make swift a bit sweeter. I have added these from multiple projects where I've been using these.\n\n*Note:* These operators are supposed to help me in the way I write Swift. Which is a functional style.\nSo most of these regard possible problems and annoyances with functional programming in Swift.\n\n\n\n**Please:** Contribute to make Swift a bit cooler looking... Post your ideas in the issues as enhancements\n\n## Installing Sweeft\n\n\u003cdiv\u003e\u003cimg src=\"http://i.giphy.com/3knKct3fGqxhK.gif\" height=250\u003e\u003c/div\u003e\n\nSweeft is available both as a Pod in Cocoapods and as a Dependency in the Swift Package Manager. So you can choose how you include Sweeft into your project.\n\n### Cocoapods\n\nAdd 'Sweeft' to your Podfile:\n\n```ruby\npod 'Sweeft'\n```\n\n### Swift Package Manager\n\nAdd 'Sweeft' to your Package.swift:\n\n```Swift\nimport PackageDescription\n\nlet package = Package(\n    // ... your project details\n    dependencies: [\n        // As a required dependency\n        .Package(url: \"ssh://git@github.com/mathiasquintero/Sweeft.git\", majorVersion: 0)\n    ]\n)\n```\n\n### Carthage\n\nAdd this to your Cartfile:\n\n```\ngithub \"mathiasquintero/Sweeft\"\n```\n\n## Why use Sweeft?\n\n\u003cdiv\u003e\u003cimg src=\"http://i.giphy.com/l4JyX3V0yydvPHNBe.gif\" height=200\u003e\u003c/div\u003e\n\nI know what you're wondering. Why the hell do I need this? \nWell. Sweeft allows you to make your code so much shorter.\n\nFor instance: let's say you have an array with some integers and some nil values.\n\n```Swift\nlet array: [Int?]? = [1, 2, 3, nil, 5, nil]\n```\n\nAnd now you want to store all of the even numbers in a single array. Easy right:\n\n```Swift\nvar even = [Int]()\nif let array = array {\n    for i in array {\n        if let i = i, i % 2 == 0 {\n            even.append(i)\n        }\n    }\n}\n```\n\nSeems a bit too much.\nNow those who know swift a bit better will tell me to write something more along the lines of:\n\n```Swift\nlet even = (array ?? [])\n            .flatMap { $0 }\n            .filter { $0 \u0026 1 == 0 }\n```\n\nBut even that seems a bit too long. Here's that same code written using **Sweeft**:\n\n```Swift\nlet even = !array |\u003e { $0 \u0026 1 == 0 }\n```\n\nNow to be clear, the last two solutions are following the same principles.\n\nFirst we get rid of all the nil values from the array and cast it as a [Int] using the prefix '!'.\nThen we just call filter. But since our fingers are too lazy we spelled it '|\u003e' ;)\n\n\u003cdiv\u003e\u003cimg src=\"http://i.giphy.com/1VrOcCmld1a92.gif\" height=150\u003e\u003c/div\u003e\n\n### Still not convinced?\n\nOk. Another example:\n\nSay you're really curious and want to know all the numbers from 0 to 1000 that are both palindromes and primes. Exciting! I know.\n\nWell easy:\n\n```Swift\nlet palindromePrimes = (0...1000) |\u003e { $0.isPalindrome } |\u003e { $0.isPrime }\n```\n\nFirst we filter out the non-palindromes.\nAnd then we filter out the non-primes.\n\n### Wow! You're a hard sell.\n\n\u003cdiv\u003e\u003cimg src=\"http://i.giphy.com/Fjr6v88OPk7U4.gif\" height=250\u003e\u003c/div\u003e\n\nOk. If you still are not sure if you should use Sweeft, see this example.\n\nSay you're looping over an array:\n\n```Swift\nfor item in array {\n    // Do Stuff\n}\n```\n\nAnd all of the sudden you notice that you're going to need the index of the item as well.\nSo now you have to use a range:\n\n```Swift\nfor index in 0..\u003carray.count {\n    let item = array[index]\n    // Do Stuff\n}\n```\n\nBut you still haven't accounted for the fact that this will crash if the array is empty:\nSo you need:\n\n```Swift\nif !array.isEmpty {\n    for index in 0..\u003carray.count {\n        let item = array[index]\n        // Do Stuff\n    }\n}\n```\n\nOk... That's too much work for a loop. Instead you could just use '.withIndex' property of the array.\n\n```Swift\nfor (item, index) in array.withIndex {\n    // Do Stuff\n}\n```\n\nWhich I know ```array.enumerated()``` already does. But ```array.withIndex``` just sounds so much clearer. ;)\n\nOr even better. With the built in for-each operator:\n\n```Swift\narray =\u003e { item, index in\n    // Do Stuff\n}\n```\n\nI think we can all agree that's much cleaner looking.\n\n## Usage\n\n### Operators\n\n#### (|) Pipe\n\nWill pipe the left value to the function to the right. Just like in Bash:\n\n```Swift\nvalue | function\n```\n\nis the same as:\n\n```Swift\nfunction(value)\n```\n\n#### (|) Safely Get Value\n\nIf you want to access any value from an Array or a Dictionary:\n\n```Swift\nlet first = array | 0\nlet second = array | 1\n```\n\nAny it will return nil if there is nothing in that index. So it won't crash ;)\n\nYou can also use negative numbers to go the other way around:\n\n```Swift\nlet last = array | -1\nlet secondToLast = array | -2\n```\n\nAwesome, right?\n\n#### (=\u003e) Map with\n\nThis will call map with the function to the right:\n\n```Swift\narray =\u003e function\n```\n\nis the same as:\n\n```Swift\narray.map(function)\n```\n\n#### (=\u003e) For each\n\nIf the closure returns void instead of a value, it will run it as a loop and not map:\n\n```Swift\narray =\u003e { item in\n    // Do Stuff\n}\n```\n\n#### (==\u003e) FlatMap with\n\nThe same as above but with flatMap.\n\n#### (==\u003e) Simple Reduce with\n\nIf you're doing reduce to the same type as your array has. You can reduce without specifying an initial result. Instead it will take the first item as an initial result:\n\nSo if you want to sum all the items in an Array:\n\n```Swift\nlet sum = array ==\u003e (+)\nlet mult = array ==\u003e (*)\n```\n\nOr you could just use the standard:\n\n```Swift\nlet sum = array.sum { $0 }\nlet mult = array.multiply { $0 }\n```\n\n#### (==\u003e) Reduce with\n\nYou could also use the standard reduce by specifying the initial result\n\n```Swift\nlet joined = myStrings ==\u003e \"\" ** { \"\\($0), \\($1)\" }\n```\n\nor if you feel like it, you can also flip the opperands:\n\n```Swift\nlet joined = myStrings ==\u003e { \"\\($0), \\($1)\" } ** \"\"\n```\n\nor since String conforms to 'Defaultable' and we know the default string is \"\", we can use the '\u003e' operator to tell reduce to use the default:\n\n```Swift\nlet joined = myStrings ==\u003e \u003e{ \"\\($0), \\($1)\" }\n```\n\n#### (|\u003e) Filter with\n\nThe same as above but with filter\n\n#### (\u003e\u003e=) Turn into Dictionary\n\nWill turn any Collection into a dictionary by dividing each element into a key and a value:\n\n```Swift\narray \u003e\u003e= { item in\n    // generate key and value from item\n\n    return (key, item)\n}\n```\n\n##### With indexes:\n\nWhen handling an array you can call the above functions with a closure that also accepts the index of the item:\n\nFor example:\n\n```Swift\narray =\u003e { item, index in\n    // Map\n    return ...\n}\n\narray ==\u003e initial ** { result, item, index in\n    // Reduce\n    return ...\n}\n\narray \u003e\u003e= { item, index in\n    // Turn into dictionary\n    return (..., ...)\n}\n```\n\n#### ( ** ) Bind with input\n\nIf you want some of functions inputs to be already filled you can use \\** to bind them to the function.\n\n```Swift\nlet inc = (+) ** 1\n\ninc(3) // 4\ninc(4) // 5\n```\n\nYou can also go from right to left with \u003c\\**\n\n#### (\u003c+\u003e) or (\u003c*\u003e) Parallelize closures.\n\nSay you want to combine to closures into one, that takes both inputs and delivers both outputs.\nFor example you have a dictionary dict [Int: Int] and you want to increase every key by one and get the square of every value.\n\nSimple:\n\n```Swift\nlet dict = [ 2 : 4, 3 : 5]\nlet newDict = dict \u003e\u003e= inc \u003c*\u003e { $0 ** 2 } // [3 : 16, 4 : 25]\n```\n\nOr if you want to use binding:\n\n```Swift\nlet newDict = dict \u003e\u003e= inc \u003c*\u003e ((**) \u003c** 2)  // Now no one can read. Perfect!\n```\n\nBut what if both functions should take the same input? Then use \u003c+\u003e and both closures will be fed the same input:\n\n```Swift\nlet dict = [1, 2, 3, 4]\nlet newDict = dict \u003e\u003e= inc \u003c+\u003e { $0 ** 2 } // [2 : 1, 3 : 4, 4 : 9, 5 : 16] \n```\n\nAnd now your code will look so awesome:\n\n\u003cdiv\u003e\u003cimg src=\"http://i.giphy.com/uWv3uPfWOz088.gif\" height=250\u003e\u003c/div\u003e\n\n#### ( ** ) Drop input/output from function\n\nWill cast a function to allow any input and drop it.\n\n```Swift\n**{\n    // Do stuff\n}\n```\n\nis the same as:\n\n```Swift\n{ _,_ in\n    // Do stuff\n}\n```\n\nor as a postfix it will drop the output\n\n```Swift\n{\n    return something\n}**\n```\n\nis equivalent to:\n\n```Swift\n{\n    _ = something\n}\n```\n\n#### (\u003c-) Assignment of non-nil\n\nWill assign b to a if b is not nil\n\n```Swift\na \u003c- b\n```\n\nis equivalent to:\n\n```Swift\na = b ?? a\n```\n\n#### (\u003c-) Assign result of map\n\nWill assign the result of a map to an array.\n\n```Swift\narray \u003c- handler\n```\n\nis equivalent to:\n\n```Swift\narray = array.map(handler)\n```\n\nIf the handler returns an optional, but the array can't handle optionals then it will drop all of the optionals.\n\n#### (\u003c|) Assign result of filter\n\nWill assign the result of a filter to the array\n\n```Swift\narray \u003c| handler\n```\n\nis the same as:\n\n```Swift\narray = array.filter(handler)\n```\n\n#### (+) Concatenate Arrays\n\nThis way you can concatenate arrays quickly:\n\n```Swift\nlet concat = firstArray + secondArray\n```\n\nOr even do:\n\n```Swift\nfirstArray += secondArray\n```\n\n#### (!) Will remove all the optional values from an array\n\n```Swift\nlet array = [1, nil, 3]\n!array // [1, 3]\n```\n\n#### (\u003c=\u003e) Will swap the values of two variables\n\n```Swift\n// a = 1 and b = 2\na \u003c=\u003e b // a = 2 and b = 1\n```\n\n#### (.?) Will unwrap an optional. Is not it will give the types default value\n\n*Note:* the type has to conform to the *Defaultable* protocol.\n\n```Swift\nlet i: Int? = nil\nlet j: Int? = 2\n\ni.? // 0\nj.? // 2\n```\n\nIt even works inside a Collection:\n\n```Swift\nlet array = [1, 2, nil, 4]\narray.? // [1, 2, 0, 4]\n```\n\nNot to be confused with the default value of an array:\n\n```Swift\nlet a: [Int?]? = nil\nlet b: [Int?]? = [1, 2, nil, 4]\n\na.? // []\nb.? // [1, 2, nil, 4]\n(b.?).? // [1, 2, 0, 4]\n```\n\n#### (??) Check for nil\n\nWill check if a value is not nil\n\n\n```Swift\n??myVariable\n```\n\nis equivalent to:\n\n\n```Swift\nmyVariable != nil\n```\n\nIt can even be given to closures.\n\nThis means:\n\n```Swift\n??{ (item: String) in\n    return item.date(\"HH:mm, dd:MM:yyyy\")\n}\n```\n\nIs a closure of type ```(String) -\u003e (Bool)``` Meaning if the date in the string is nil or not.\n\n#### (\u003e\u003e\u003e) Run in Queue\n\nYou you want to run a closure in a specific queue:\n\n```Swift\nqueue \u003e\u003e\u003e {\n    // Do Stuff.\n}\n```\n\nOr if you want to run it after a certain time interval in seconds. For example the following will run the closure after 5 seconds:\n\n```Swift\n5.0 \u003e\u003e\u003e {\n    // Do Stuff\n}\n```\n\nAnd of course you can combine them:\n\n```Swift\n(queue, 5.0) \u003e\u003e\u003e {\n    // Do Stuff\n}\n\n// Or\n\n(5.0, queue) \u003e\u003e\u003e {\n    // Do Stuff\n}\n```\n\n#### (\u003e\u003e\u003e) Chain Closures\n\nIf you want to be more modular with your closures you can always chain them toghether and turn them into a bigger closure.\n\nFor example: Let's say you have an array of dates. And you want an array of the hours of each.\n\n```Swift\nlet hours = dates =\u003e { $0.string(\"hh\") } \u003e\u003e\u003e Int.init\n```\n\nWhich is equivalent to saying:\n\n```Swift\nlet hours = dates.map { date in\n    let string = date.string(\"hh\")\n    return Int(string)\n}\n```\n\nThe precedence works as follows:\n\nChaining before mapping. So \u003e\u003e\u003e will be evaluated before =\u003e.\n\nOf course you don't need chaining in the previous example. You could use the pipe and will be even shorter:\n\n```Swift\nlet hours = dates =\u003e { $0.string(\"hh\") | Int.init }\n```\n\nBut that's the cool thing about Sweeft. It gives you options ;)\n\n### User Defaults\n\nStoring data to UserDefaults can be lead to issues. Mainly because of the fact that UserDefaults uses strings as keys, which make it easy to make mistakes. Furthermore the code to read something from user defaults requires you to cast the value to the type that you want. Which is unnecesarily complicated.\n\nWhich is why Sweeft has a Status API. Meaning that anything that has to be stored into UserDefaults has to be it's own Status Struct.\n\n#### Status\n\nFor example if you want to store the amount of times in which your app was opened:\n\nWe start by creating the keys for your app.\n\nSimply create an enum for them that inherits from StatusKey:\n\n```Swift\nenum AppDefaults: String, StatusKey {\n    case timesOpened\n    /// More Cases here...\n}\n```\n\nAnd now we create the Status:\n\n```Swift\nstruct TimesOpened: Status {\n    static let key: AppDefaults = .timesOpened\n    static let defaultValue: Int = 0\n}\n```\n\nTo access it you can simply call it from your code:\n\n```Swift\nlet times = TimesOpened.value\n// Do Something with it...\nTimesOpened.value = times + 1\n```\n\n#### ObjectStatus\n\nSometimes you may want to store more complex information than just stock types that are usually supported in user defaults.\n\nFor that there's the ObjectStatus. First off, your Data has to conform to the protocol 'StatusSerializable'. Meaning it can be serialized and deserialized into a ```[String:Any]```.\n\nFor example:\n\n```Swift\nextension MyData: StatusSerializable {\n\n    var serialized: [String:Any] {\n        return [\n            // Store your data\n        ]\n    }\n\n    init?(from status: [String:Any]) {\n        // Read data from the dictionary and set everything up\n        // This init is allowed to fail ;)\n    }\n\n}\n```\n\nAnd then create your ObjectStatus:\n\n```Swift\nstruct MyDataStatus: ObjectStatus {\n    static let key: AppDefaults = .myDataKey // Create a Key for this too\n    static let defaultValue: MyData = MyData() // Hand some default value here\n}\n```\n\n### REST and HTTP\n\nSweeft also abstracts away a lot of repetetive work on sending requests to your REST API.\n\n#### API and Endpoints\n\nTo access an API you simply have to describe the API by creating a list of endpoints you can access.\n\n```Swift\nenum MyEndpoint: String, APIEndpoint {\n    case login = \"login\"\n    case user = \"user/{id}\"\n}\n```\n\nThen you can create your own API Object:\n\n```Swift\nstruct MyAPI: API {\n    typealias Endpoint = MyEndpoint\n    let baseURL = \"https://...\"\n}\n```\n\nAnd do any requests from it, be it Data, JSON or anything that conforms to our DataRepresentable Protocol. Like so:\n\n```Swift\nlet api = MyAPI()\napi.doJSONRequest(with: .get, to: .user, arguments: [\"id\": 1234])\n    .onSuccess { json in\n        let name = json[\"name\"].string ?? \"No name for the user is available\"\n        print(name)\n    }\n    .onError { error in\n        print(\"Some Error Happened :(\")\n        print(error)\n    }\n\n```\n\nThe code above does a GET Request to /user/1234 and if the request is successful it will read the name attribute of the JSON Object and print it out.\n\n#### Deserializable Objects\n\nA deserializable object is any object that conforms to the protocol Deserializable and can therefore be instantiated from JSON.\nFor instance let's say that we get an object representing a user from our API.\n\n```Swift\nstruct User {\n    let name: String\n}\n\nextension User: Deserializable {\n    \n    init?(from: JSON) {\n        guard let name = json[\"name\"].string else {\n            return nil\n        }\n        self.init(name: name)\n    }\n    \n}\n```\n\nHaving done this you can automatically get User's from your api by calling get(:) or getAll(:) respectively.\n\nFor example you can now call:\n\n```Swift\nlet api = MyAPI()\nUser.get(using: api, at: .user, arguments: [\"id\": 1234])\n    .onSuccess { user in\n        print(user.name)\n    }\n    .onError { error in\n        print(error)\n    }\n```\n\n## Contributing\n\nPlease contribute and help me make swift even better with more cool ways to simplify the swift syntax.\nFork and star this repo and #MakeSwiftGreatAgain\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnerdsupremacist%2Fsweeft","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnerdsupremacist%2Fsweeft","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnerdsupremacist%2Fsweeft/lists"}