diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4607e3aa..f9e5dc30 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
# Changelog
+### 1.7.0
+- **Add**: `TINetworking` - Swagger-frendly networking layer helpers
+
### 1.6.0
- **Add**: the pretty timer - TITimer.
diff --git a/LeadKit.podspec b/LeadKit.podspec
index 03d8ca8c..dc8548be 100644
--- a/LeadKit.podspec
+++ b/LeadKit.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "LeadKit"
- s.version = "1.6.0"
+ s.version = "1.7.0"
s.summary = "iOS framework with a bunch of tools for rapid development"
s.homepage = "https://github.com/TouchInstinct/LeadKit"
s.license = "Apache License, Version 2.0"
diff --git a/Package.resolved b/Package.resolved
index 3dfc4c9c..94b92e20 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -1,6 +1,15 @@
{
"object": {
"pins": [
+ {
+ "package": "Alamofire",
+ "repositoryURL": "https://github.com/Alamofire/Alamofire.git",
+ "state": {
+ "branch": null,
+ "revision": "f96b619bcb2383b43d898402283924b80e2c4bae",
+ "version": "5.4.3"
+ }
+ },
{
"package": "Cursors",
"repositoryURL": "https://github.com/petropavel13/Cursors",
diff --git a/Package.swift b/Package.swift
index 8f8862f1..03aebe37 100644
--- a/Package.swift
+++ b/Package.swift
@@ -17,6 +17,7 @@ let package = Package(
.library(name: "TIFoundationUtils", targets: ["TIFoundationUtils"]),
.library(name: "TIKeychainUtils", targets: ["TIKeychainUtils"]),
.library(name: "TITableKitUtils", targets: ["TITableKitUtils"]),
+ .library(name: "TINetworking", targets: ["TINetworking"]),
// MARK: - Elements
.library(name: "OTPSwiftView", targets: ["OTPSwiftView"]),
@@ -24,9 +25,10 @@ let package = Package(
.library(name: "TIPagination", targets: ["TIPagination"]),
],
dependencies: [
- .package(url: "https://github.com/maxsokolov/TableKit.git", from: "2.11.0"),
- .package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", from: "4.2.2"),
- .package(url: "https://github.com/petropavel13/Cursors", from: "0.5.1")
+ .package(url: "https://github.com/maxsokolov/TableKit.git", .upToNextMajor(from: "2.11.0")),
+ .package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", .upToNextMajor(from: "4.2.2")),
+ .package(url: "https://github.com/petropavel13/Cursors", .upToNextMajor(from: "0.5.1")),
+ .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.4.0")),
],
targets: [
@@ -39,6 +41,7 @@ let package = Package(
.target(name: "TIFoundationUtils", dependencies: ["TISwiftUtils"], path: "TIFoundationUtils/Sources"),
.target(name: "TIKeychainUtils", dependencies: ["TIFoundationUtils", "KeychainAccess"], path: "TIKeychainUtils/Sources"),
.target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"),
+ .target(name: "TINetworking", dependencies: ["TISwiftUtils", "Alamofire"], path: "TINetworking/Sources"),
// MARK: - Elements
diff --git a/TIFoundationUtils/TIFoundationUtils.podspec b/TIFoundationUtils/TIFoundationUtils.podspec
index 2079438d..557d461e 100644
--- a/TIFoundationUtils/TIFoundationUtils.podspec
+++ b/TIFoundationUtils/TIFoundationUtils.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIFoundationUtils'
- s.version = '1.6.0'
+ s.version = '1.7.0'
s.summary = 'Set of helpers for Foundation framework classes.'
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
diff --git a/TIKeychainUtils/TIKeychainUtils.podspec b/TIKeychainUtils/TIKeychainUtils.podspec
index 407932f6..8e72b025 100644
--- a/TIKeychainUtils/TIKeychainUtils.podspec
+++ b/TIKeychainUtils/TIKeychainUtils.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIKeychainUtils'
- s.version = '1.6.0'
+ s.version = '1.7.0'
s.summary = 'Set of helpers for Keychain classes.'
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
diff --git a/TINetworking/Sources/Mapping/BaseContent.swift b/TINetworking/Sources/Mapping/BaseContent.swift
new file mode 100644
index 00000000..b91c5b6d
--- /dev/null
+++ b/TINetworking/Sources/Mapping/BaseContent.swift
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+open class BaseContent: Content {
+ public let mediaTypeName: String
+
+ public init(mediaTypeName: String = CommonMediaTypes.textPlain.rawValue) {
+ self.mediaTypeName = mediaTypeName
+ }
+}
diff --git a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift
new file mode 100644
index 00000000..a99145eb
--- /dev/null
+++ b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+import TISwiftUtils
+
+open class ApplicationJsonBodyContent
: BaseContent, BodyContent {
+ private let encodingClosure: ThrowableResultClosure
+
+ public init(body: Body, jsonEncoder: JSONEncoder = JSONEncoder()) where Body: Encodable {
+ encodingClosure = {
+ try jsonEncoder.encode(body)
+ }
+
+ super.init(mediaTypeName: CommonMediaTypes.applicationJson.rawValue)
+ }
+
+ public init(jsonBody: Body, options: JSONSerialization.WritingOptions = .prettyPrinted) {
+ encodingClosure = {
+ try JSONSerialization.data(withJSONObject: jsonBody, options: options)
+ }
+
+ super.init(mediaTypeName: CommonMediaTypes.applicationJson.rawValue)
+ }
+
+ // MARK: - BodyContent
+
+ public func encodeBody() throws -> Data {
+ try encodingClosure()
+ }
+}
diff --git a/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift
new file mode 100644
index 00000000..e055fa9a
--- /dev/null
+++ b/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+public protocol BodyContent: Content {
+ func encodeBody() throws -> Data
+}
diff --git a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift
new file mode 100644
index 00000000..faed4a9c
--- /dev/null
+++ b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+public final class EmptyBodyContent: BaseContent, BodyContent {
+
+ // MARK: - BodyContent
+
+ public func encodeBody() throws -> Data {
+ Data()
+ }
+}
+
+public extension BodyContent {
+ static var empty: EmptyBodyContent {
+ .init()
+ }
+}
diff --git a/TINetworking/Sources/Mapping/Codable+Required.swift b/TINetworking/Sources/Mapping/Codable+Required.swift
new file mode 100644
index 00000000..634f7d6c
--- /dev/null
+++ b/TINetworking/Sources/Mapping/Codable+Required.swift
@@ -0,0 +1,45 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public extension KeyedDecodingContainer {
+ func decode(_ type: T?.Type,
+ forKey key: Key,
+ required: Bool) throws -> T? {
+
+ required
+ ? try decode(type, forKey: key)
+ : try decodeIfPresent(T.self, forKey: key)
+ }
+}
+
+public extension KeyedEncodingContainer {
+ mutating func encode(_ value: T?,
+ forKey key: Key,
+ required: Bool) throws {
+
+ if let value = value {
+ try encode(value, forKey: key)
+ } else if required {
+ try encodeNil(forKey: key)
+ }
+ }
+}
diff --git a/TINetworking/Sources/Mapping/CommonMediaTypes.swift b/TINetworking/Sources/Mapping/CommonMediaTypes.swift
new file mode 100644
index 00000000..b925af5f
--- /dev/null
+++ b/TINetworking/Sources/Mapping/CommonMediaTypes.swift
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public enum CommonMediaTypes: String {
+ case applicationJson = "application/json"
+ case textPlain = "text/plain"
+}
diff --git a/TINetworking/Sources/Mapping/Content.swift b/TINetworking/Sources/Mapping/Content.swift
new file mode 100644
index 00000000..b5735b3b
--- /dev/null
+++ b/TINetworking/Sources/Mapping/Content.swift
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public protocol Content {
+ var mediaTypeName: String { get }
+}
diff --git a/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift
new file mode 100644
index 00000000..2e92361e
--- /dev/null
+++ b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift
@@ -0,0 +1,47 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import TISwiftUtils
+
+public struct AnyTypeMapping {
+ private let mappingClosure: ResultClosure>
+
+ public let type: Any.Type
+
+ public init(decoder: Decoder,
+ transform: @escaping Closure) {
+
+ type = T.self
+
+ mappingClosure = {
+ do {
+ return .success(transform(try T(from: decoder)))
+ } catch {
+ return .failure(error)
+ }
+ }
+ }
+
+ public func decode() -> Result {
+ mappingClosure()
+ }
+}
diff --git a/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift b/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift
new file mode 100644
index 00000000..501adc40
--- /dev/null
+++ b/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public struct OneOfMappingError: Error, CustomDebugStringConvertible {
+ public typealias MappingFailures = [KeyValueTuple]
+
+ public let codingPath: [CodingKey]
+ public let mappingFailures: MappingFailures
+
+ public init(codingPath: [CodingKey], mappingFailures: MappingFailures) {
+ self.codingPath = codingPath
+ self.mappingFailures = mappingFailures
+ }
+
+ public var debugDescription: String {
+ var formattedString = "\"oneOf\" mapping failed for codingPath \(codingPath)\nwith following errors:\n"
+
+ for (type, error) in mappingFailures {
+ formattedString += "\(type) mapping failed with error: \(error)\n"
+ }
+
+ return formattedString
+ }
+}
diff --git a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift
new file mode 100644
index 00000000..37a6497f
--- /dev/null
+++ b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift
@@ -0,0 +1,45 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+open class ApplicationJsonResponseContent: BaseContent, ResponseContent {
+ public let jsonDecoder: JSONDecoder
+
+ public init(jsonDecoder: JSONDecoder = JSONDecoder()) {
+ self.jsonDecoder = jsonDecoder
+
+ super.init(mediaTypeName: CommonMediaTypes.applicationJson.rawValue)
+ }
+
+ // MARK: - ResponseContent
+
+ public func decodeResponse(data: Data) throws -> Model {
+ try jsonDecoder.decode(Model.self, from: data)
+ }
+}
+
+public extension JSONDecoder {
+ func responseContent() -> ApplicationJsonResponseContent {
+ .init(jsonDecoder: self)
+ }
+}
diff --git a/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift
new file mode 100644
index 00000000..32aaec1e
--- /dev/null
+++ b/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+public final class EmptyResponseContent: BaseContent, ResponseContent {
+ public func decodeResponse(data: Data) throws -> Void {
+ ()
+ }
+}
diff --git a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift
new file mode 100644
index 00000000..7e38fabb
--- /dev/null
+++ b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+import TISwiftUtils
+
+public final class MapResponseContent: BaseContent, ResponseContent {
+ private let decodeClosure: ThrowableClosure
+
+ public init(responseContent: C, transform: @escaping Closure) {
+ decodeClosure = {
+ transform(try responseContent.decodeResponse(data: $0))
+ }
+
+ super.init(mediaTypeName: responseContent.mediaTypeName)
+ }
+
+ // MARK: - ResponseContent
+
+ public func decodeResponse(data: Data) throws -> Model {
+ try decodeClosure(data)
+ }
+}
+
+public extension ResponseContent {
+ typealias TransformClosure = Closure
+
+ func map(_ transform: @escaping TransformClosure) -> MapResponseContent {
+ .init(responseContent: self, transform: transform)
+ }
+}
+
+public extension JSONDecoder {
+ func responseContent(_ tranfsorm: @escaping Closure) -> MapResponseContent {
+ responseContent().map(tranfsorm)
+ }
+
+ func decoding(to tranfsorm: @escaping Closure) -> ThrowableClosure {
+ responseContent(tranfsorm).decodeResponse
+ }
+}
diff --git a/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift
new file mode 100644
index 00000000..91cdd16c
--- /dev/null
+++ b/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+public protocol ResponseContent: Content {
+ associatedtype Model
+
+ func decodeResponse(data: Data) throws -> Model
+}
diff --git a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift
new file mode 100644
index 00000000..c26cd2ff
--- /dev/null
+++ b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+public final class TextPlainResponseContent: BaseContent, ResponseContent {
+ public struct StringDecodingError: Error {
+ let data: Data
+ let encoding: String.Encoding
+ }
+
+ private let encoding: String.Encoding
+
+ public init(encoding: String.Encoding = .utf8) {
+ self.encoding = encoding
+
+ super.init(mediaTypeName: CommonMediaTypes.textPlain.rawValue)
+ }
+
+ // MARK: - ResponseContent
+
+ public func decodeResponse(data: Data) throws -> String {
+ guard let plainText = String(data: data, encoding: encoding) else {
+ throw StringDecodingError(data: data, encoding: encoding)
+ }
+
+ return plainText
+ }
+}
diff --git a/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift
new file mode 100644
index 00000000..90a9f75c
--- /dev/null
+++ b/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift
@@ -0,0 +1,47 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Alamofire
+
+open class BaseUrlParameterEncoding {
+ private let encoding: URLEncoding = .queryString
+
+ public init() {}
+
+ open func encode(parameters: [String: Parameter]) -> [KeyValueTuple] {
+ var filteredComponents: [KeyValueTuple] = []
+
+ for key in parameters.keys.sorted(by: <) {
+ guard let parameter = parameters[key] else {
+ continue
+ }
+
+ let components = encoding.queryComponents(fromKey: key, value: parameter.value)
+ // filter components with empty values if parameter doesn't allow empty value
+ .filter { !$0.1.isEmpty || parameter.allowEmptyValue }
+
+ filteredComponents.append(contentsOf: components)
+ }
+
+ return filteredComponents
+ }
+}
diff --git a/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift
new file mode 100644
index 00000000..f11c3da5
--- /dev/null
+++ b/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+open class PathParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding {
+ public let templateUrl: String
+
+ public init(templateUrl: String) {
+ self.templateUrl = templateUrl
+ }
+
+ // MARK: - ParameterEncoding
+
+ open func encode(parameters: [String: Parameter]) -> String {
+ .render(template: templateUrl, using: encode(parameters: parameters))
+ }
+}
diff --git a/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift
new file mode 100644
index 00000000..7931e26c
--- /dev/null
+++ b/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+open class QueryStringParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding {
+
+ // MARK: - ParameterEncoding
+
+ open func encode(parameters: [String: Parameter]) -> [String: Any] {
+ let includedKeys = Set(super.encode(parameters: parameters).map { $0.key })
+
+ return parameters
+ .filter { includedKeys.contains($0.key) }
+ .mapValues { $0.value }
+ }
+}
diff --git a/TINetworking/Sources/Parameters/Parameter.swift b/TINetworking/Sources/Parameters/Parameter.swift
new file mode 100644
index 00000000..a1dab8a5
--- /dev/null
+++ b/TINetworking/Sources/Parameters/Parameter.swift
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public struct Parameter {
+ public let value: Any
+ public let allowEmptyValue: Bool
+
+ public init(value: Any, allowEmptyValue: Bool = false) {
+ self.value = value
+ self.allowEmptyValue = allowEmptyValue
+ }
+}
diff --git a/TINetworking/Sources/Parameters/ParameterEncoding.swift b/TINetworking/Sources/Parameters/ParameterEncoding.swift
new file mode 100644
index 00000000..16f69eba
--- /dev/null
+++ b/TINetworking/Sources/Parameters/ParameterEncoding.swift
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+protocol ParameterEncoding {
+ associatedtype Location: ParameterLocation
+ associatedtype Result
+
+ func encode(parameters: [String: Parameter]) -> Result
+}
diff --git a/TINetworking/Sources/Parameters/ParameterLocation.swift b/TINetworking/Sources/Parameters/ParameterLocation.swift
new file mode 100644
index 00000000..0fe68c32
--- /dev/null
+++ b/TINetworking/Sources/Parameters/ParameterLocation.swift
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public protocol ParameterLocation {}
+
+public struct LocationQuery: ParameterLocation {}
+public struct LocationPath: ParameterLocation {}
+public struct LocationHeader: ParameterLocation {}
+public struct LocationCookie: ParameterLocation {}
diff --git a/TINetworking/Sources/Request/Request.swift b/TINetworking/Sources/Request/Request.swift
new file mode 100644
index 00000000..d4b88b14
--- /dev/null
+++ b/TINetworking/Sources/Request/Request.swift
@@ -0,0 +1,64 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Alamofire
+
+public struct Request {
+
+ public var templatePath: String
+ public var method: HTTPMethod
+ public var requestBodyContent: Content
+ public var queryParameters: [String: Parameter]
+ public var pathParameters: [String: Parameter]
+ public var headerParameters: HTTPHeaders?
+ public var cookieParameters: [String: Parameter]
+ public var acceptableStatusCodes: Set
+ public var customServer: Server?
+ public var customServerVariables: [KeyValueTuple]
+
+ public var path: String {
+ PathParameterEncoding(templateUrl: templatePath).encode(parameters: pathParameters)
+ }
+
+ public init(templatePath: String,
+ method: HTTPMethod,
+ requestBodyContent: Content,
+ queryParameters: [String: Parameter] = [:],
+ pathParameters: [String: Parameter] = [:],
+ headerParameters: HTTPHeaders? = nil,
+ cookieParameters: [String: Parameter] = [:],
+ acceptableStatusCodes: Set = [200],
+ customServer: Server? = nil,
+ customServerVariables: [KeyValueTuple] = []) {
+
+ self.templatePath = templatePath
+ self.method = method
+ self.requestBodyContent = requestBodyContent
+ self.queryParameters = queryParameters
+ self.pathParameters = pathParameters
+ self.headerParameters = headerParameters
+ self.cookieParameters = cookieParameters
+ self.acceptableStatusCodes = acceptableStatusCodes
+ self.customServer = customServer
+ self.customServerVariables = customServerVariables
+ }
+}
diff --git a/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift b/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift
new file mode 100644
index 00000000..a447c7ef
--- /dev/null
+++ b/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+open class MimeTypeUnsupportedError: Error, CustomDebugStringConvertible {
+
+ public let mimeType: String?
+
+ // MARK: - CustomDebugStringConvertible
+
+ public var debugDescription: String {
+ "Mime type \(mimeType.debugDescription) isn't supported."
+ }
+
+ public init(mimeType: String?) {
+ self.mimeType = mimeType
+ }
+}
diff --git a/TINetworking/Sources/Response/ResponseType+Decoding.swift b/TINetworking/Sources/Response/ResponseType+Decoding.swift
new file mode 100644
index 00000000..ad2a0499
--- /dev/null
+++ b/TINetworking/Sources/Response/ResponseType+Decoding.swift
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+import TISwiftUtils
+
+public typealias StatusCodeMimeType = (statusCode: Int, mimeType: String?)
+public typealias StatusCodesMimeType = (statusCodes: Set, mimeType: String?)
+
+public typealias DecodingClosure = ThrowableClosure
+
+public extension ResponseType {
+ func decode(mapping: [KeyValueTuple>]) -> Result {
+ for ((mappingStatusCode, mappingMimeType), decodeClosure) in mapping
+ where mappingStatusCode == statusCode && mappingMimeType == mimeType {
+ do {
+ return .success(try decodeClosure(data))
+ } catch {
+ return .failure(objectMappingError(underlyingError: error))
+ }
+ }
+
+ guard mapping.contains(where: { $0.key.statusCode == statusCode }) else {
+ return .failure(unsupportedStatusCodeError(statusCode: statusCode))
+ }
+
+ guard mapping.contains(where: { $0.key.mimeType == mimeType }) else {
+ return .failure(unsupportedMimeTypeError(mimeType: mimeType))
+ }
+
+ return .failure(unsupportedStatusCodeMimeTypePairError(statusCode: statusCode, mimeType: mimeType))
+ }
+
+ func decode(mapping: [KeyValueTuple>]) -> Result {
+ decode(mapping: mapping.map { key, value in
+ key.statusCodes.map { KeyValueTuple(StatusCodeMimeType($0, key.mimeType), value) }
+ }.flatMap { $0 })
+ }
+}
diff --git a/TINetworking/Sources/Response/ResponseType.swift b/TINetworking/Sources/Response/ResponseType.swift
new file mode 100644
index 00000000..d6980445
--- /dev/null
+++ b/TINetworking/Sources/Response/ResponseType.swift
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+public protocol ResponseType {
+ associatedtype ErrorType: Error
+
+ var statusCode: Int { get }
+ var data: Data { get }
+ var mimeType: String? { get }
+
+ func unsupportedStatusCodeError(statusCode: Int) -> ErrorType
+ func unsupportedMimeTypeError(mimeType: String?) -> ErrorType
+ func objectMappingError(underlyingError: Error) -> ErrorType
+ func unsupportedStatusCodeMimeTypePairError(statusCode: Int, mimeType: String?) -> ErrorType
+}
diff --git a/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift b/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift
new file mode 100644
index 00000000..844e9044
--- /dev/null
+++ b/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+open class StatusCodeMimeTypePairUnsupportedError: MimeTypeUnsupportedError {
+
+ public let statusCode: Int
+
+ // MARK: - CustomDebugStringConvertible
+
+ public override var debugDescription: String {
+ "Status code: \(statusCode), mimeType: \(mimeType ?? "nil") pair is unsupported!"
+ }
+
+ public init(statusCode: Int, mimeType: String?) {
+ self.statusCode = statusCode
+
+ super.init(mimeType: mimeType)
+ }
+}
diff --git a/TINetworking/Sources/Server.swift b/TINetworking/Sources/Server.swift
new file mode 100644
index 00000000..e05db673
--- /dev/null
+++ b/TINetworking/Sources/Server.swift
@@ -0,0 +1,81 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+private enum Scheme: String {
+ case https
+
+ var urlPrefix: String {
+ rawValue + "://"
+ }
+}
+
+public struct Server {
+ public struct Variable {
+ public let values: [String]
+ public let defaultValue: String
+
+ public init(values: [String], defaultValue: String) {
+ self.values = values
+ self.defaultValue = defaultValue
+ }
+ }
+
+ private var defaultVariables: [KeyValueTuple] {
+ variables.map { ($0.key, $0.value.defaultValue) }
+ }
+
+ public let urlTemplate: String
+ public let variables: [String: Variable]
+
+ public init(urlTemplate: String, variables: [String: Variable]) {
+ self.urlTemplate = urlTemplate
+ self.variables = variables
+ }
+
+ public init(baseUrl: String) {
+ self.init(urlTemplate: baseUrl, variables: [:])
+ }
+
+ public func url(using variables: [KeyValueTuple] = [],
+ appendHttpsSchemeIfMissing: Bool = true) -> URL? {
+
+ guard !variables.isEmpty else {
+ return URL(string: .render(template: urlTemplate, using: defaultVariables))
+ }
+
+ let defaultVariablesToApply = self.defaultVariables
+ .filter { (key, _) in variables.contains { $0.key == key } }
+
+ let defaultParametersTemplate = String.render(template: urlTemplate,
+ using: defaultVariablesToApply)
+
+ let formattedUrlString = String.render(template: defaultParametersTemplate, using: variables)
+
+ if appendHttpsSchemeIfMissing, !formattedUrlString.contains(Scheme.https.urlPrefix) {
+ return URL(string: Scheme.https.urlPrefix + formattedUrlString)
+ }
+
+ return URL(string: formattedUrlString)
+ }
+}
diff --git a/TINetworking/Sources/SessionFactory.swift b/TINetworking/Sources/SessionFactory.swift
new file mode 100644
index 00000000..d12aff10
--- /dev/null
+++ b/TINetworking/Sources/SessionFactory.swift
@@ -0,0 +1,54 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+import Alamofire
+
+open class SessionFactory {
+
+ public var timeoutInterval: TimeInterval
+ public var additionalHttpHeaders: HTTPHeaders
+ public var serverTrustPolicies: [String: ServerTrustEvaluating]
+
+ public init(timeoutInterval: TimeInterval = 20,
+ additionalHttpHeaders: HTTPHeaders = HTTPHeaders(),
+ trustPolicies: [String: ServerTrustEvaluating] = [:]) {
+
+ self.timeoutInterval = timeoutInterval
+ self.additionalHttpHeaders = additionalHttpHeaders
+ self.serverTrustPolicies = Dictionary(uniqueKeysWithValues: trustPolicies.map { ($0.key.urlHost, $0.value) })
+ }
+
+ open func createSession() -> Session {
+ Session(configuration: createSessionConfiguration(),
+ serverTrustManager: ServerTrustManager(allHostsMustBeEvaluated: false,
+ evaluators: serverTrustPolicies))
+ }
+
+ open func createSessionConfiguration() -> URLSessionConfiguration {
+ let sessionConfiguration = URLSessionConfiguration.default
+ sessionConfiguration.timeoutIntervalForResource = timeoutInterval
+ sessionConfiguration.httpAdditionalHeaders = additionalHttpHeaders.dictionary
+
+ return sessionConfiguration
+ }
+}
diff --git a/TINetworking/Sources/String+URLExtensions.swift b/TINetworking/Sources/String+URLExtensions.swift
new file mode 100644
index 00000000..e152ba5a
--- /dev/null
+++ b/TINetworking/Sources/String+URLExtensions.swift
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+public extension String {
+ var urlEscaped: String {
+ return addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? self
+ }
+
+ var urlHost: String {
+ URL(string: self)?.host ?? self
+ }
+
+ static func render(template: String, using variables: [KeyValueTuple]) -> String {
+ variables.reduce(template) {
+ $0.replacingOccurrences(of: "{\($1.key)}", with: $1.value.urlEscaped)
+ }
+ }
+}
diff --git a/TINetworking/Sources/Typealiases.swift b/TINetworking/Sources/Typealiases.swift
new file mode 100644
index 00000000..6adf2891
--- /dev/null
+++ b/TINetworking/Sources/Typealiases.swift
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2021 Touch Instinct
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the Software), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+public typealias KeyValueTuple = (key: K, value: V)
diff --git a/TINetworking/TINetworking.podspec b/TINetworking/TINetworking.podspec
new file mode 100644
index 00000000..a9355971
--- /dev/null
+++ b/TINetworking/TINetworking.podspec
@@ -0,0 +1,16 @@
+Pod::Spec.new do |s|
+ s.name = 'TINetworking'
+ s.version = '1.7.0'
+ s.summary = 'Swagger-frendly networking layer helpers.'
+ s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
+ s.license = { :type => 'MIT', :file => 'LICENSE' }
+ s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
+ s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
+
+ s.ios.deployment_target = '10.0'
+ s.swift_versions = ['5.3']
+
+ s.source_files = s.name + '/Sources/**/*'
+
+ s.dependency 'Alamofire'
+end
diff --git a/TISwiftUtils/TISwiftUtils.podspec b/TISwiftUtils/TISwiftUtils.podspec
index e3fbf696..b89b2c68 100644
--- a/TISwiftUtils/TISwiftUtils.podspec
+++ b/TISwiftUtils/TISwiftUtils.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TISwiftUtils'
- s.version = '1.6.0'
+ s.version = '1.7.0'
s.summary = 'Bunch of useful helpers for Swift development.'
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
diff --git a/TITableKitUtils/TITableKitUtils.podspec b/TITableKitUtils/TITableKitUtils.podspec
index c62ddc09..1a3d5eb1 100644
--- a/TITableKitUtils/TITableKitUtils.podspec
+++ b/TITableKitUtils/TITableKitUtils.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TITableKitUtils'
- s.version = '1.6.0'
+ s.version = '1.7.0'
s.summary = 'Set of helpers for TableKit classes.'
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
diff --git a/TITransitions/TITransitions.podspec b/TITransitions/TITransitions.podspec
index 0f4cc5e2..af42244b 100644
--- a/TITransitions/TITransitions.podspec
+++ b/TITransitions/TITransitions.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TITransitions'
- s.version = '1.6.0'
+ s.version = '1.7.0'
s.summary = 'Set of custom transitions to present controller. '
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
diff --git a/TIUIElements/TIUIElements.podspec b/TIUIElements/TIUIElements.podspec
index 759d9fcc..dc40a6f3 100644
--- a/TIUIElements/TIUIElements.podspec
+++ b/TIUIElements/TIUIElements.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIUIElements'
- s.version = '1.6.0'
+ s.version = '1.7.0'
s.summary = 'Bunch of useful protocols and views.'
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
diff --git a/TIUIKitCore/TIUIKitCore.podspec b/TIUIKitCore/TIUIKitCore.podspec
index 0a863b71..88340b88 100644
--- a/TIUIKitCore/TIUIKitCore.podspec
+++ b/TIUIKitCore/TIUIKitCore.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIUIKitCore'
- s.version = '1.6.0'
+ s.version = '1.7.0'
s.summary = 'Core UI elements: protocols, views and helpers.'
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }