├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── Shank
│ └── Shank.swift
└── Tests
└── ShankTests
└── ShankTests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019 Zamzam Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Shank",
8 | platforms: [
9 | .macOS(.v10_12),
10 | .iOS(.v10),
11 | .tvOS(.v10),
12 | .watchOS(.v3)
13 | ],
14 | products: [
15 | .library(
16 | name: "Shank",
17 | targets: ["Shank"]
18 | )
19 | ],
20 | targets: [
21 | .target(
22 | name: "Shank"
23 | ),
24 | .testTarget(
25 | name: "ShankTests",
26 | dependencies: ["Shank"]
27 | )
28 | ]
29 | )
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Shank
2 |
3 | A Swift micro-library that provides lightweight dependency injection.
4 |
5 | Read more here: https://basememara.com/swift-dependency-injection-via-property-wrapper/
6 |
7 | Inject dependencies via property wrappers:
8 | ```swift
9 | class ViewController: UIViewController {
10 |
11 | @Inject private var widgetModule: WidgetModuleType
12 | @Inject private var sampleModule: SampleModuleType
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 |
17 | widgetModule.test()
18 | sampleModule.test()
19 | }
20 | }
21 | ```
22 | Register modules early in your app:
23 | ```swift
24 | class AppDelegate: UIResponder, UIApplicationDelegate {
25 |
26 | private let dependencies = Dependencies {
27 | Module { WidgetModule() as WidgetModuleType }
28 | Module { SampleModule() as SampleModuleType }
29 | }
30 |
31 | override init() {
32 | super.init()
33 | dependencies.build()
34 | }
35 | }
36 | ```
37 | If you forget to `build` the dependency container, it will result in a run-time exception.
38 | Since there is no type-safety to guard against this, it is recommended to
39 | limit the dependency container to hold "modules" only:
40 | ```swift
41 | struct WidgetModule: WidgetModuleType {
42 |
43 | func component() -> WidgetWorkerType {
44 | WidgetWorker(
45 | store: component(),
46 | remote: component()
47 | )
48 | }
49 |
50 | func component() -> WidgetRemote {
51 | WidgetNetworkRemote(httpService: component())
52 | }
53 |
54 | func component() -> WidgetStore {
55 | WidgetRealmStore()
56 | }
57 |
58 | func component() -> HTTPServiceType {
59 | HTTPService()
60 | }
61 |
62 | func test() -> String {
63 | "WidgetModule.test()"
64 | }
65 | }
66 |
67 | struct SampleModule: SampleModuleType {
68 |
69 | func component() -> SomeObjectType {
70 | SomeObject()
71 | }
72 |
73 | func component() -> AnotherObjectType {
74 | AnotherObject(someObject: component())
75 | }
76 |
77 | func component() -> ViewModelObjectType {
78 | SomeViewModel(
79 | someObject: component(),
80 | anotherObject: component()
81 | )
82 | }
83 |
84 | func component() -> ViewControllerObjectType {
85 | SomeViewController()
86 | }
87 |
88 | func test() -> String {
89 | "SampleModule.test()"
90 | }
91 | }
92 |
93 | // MARK: API
94 |
95 | protocol WidgetModuleType {
96 | func component() -> WidgetWorkerType
97 | func component() -> WidgetRemote
98 | func component() -> WidgetStore
99 | func component() -> HTTPServiceType
100 | func test() -> String
101 | }
102 |
103 | protocol SampleModuleType {
104 | func component() -> SomeObjectType
105 | func component() -> AnotherObjectType
106 | func component() -> ViewModelObjectType
107 | func component() -> ViewControllerObjectType
108 | func test() -> String
109 | }
110 | ```
111 | Then resolve individual components lazily:
112 | ```swift
113 | class ViewController: UIViewController {
114 |
115 | @Inject private var widgetModule: WidgetModuleType
116 | @Inject private var sampleModule: SampleModuleType
117 |
118 | private lazy var widgetWorker: WidgetWorkerType = widgetModule.component()
119 | private lazy var someObject: SomeObjectType = sampleModule.component()
120 | private lazy var anotherObject: AnotherObjectType = sampleModule.component()
121 | private lazy var viewModelObject: ViewModelObjectType = sampleModule.component()
122 | private lazy var viewControllerObject: ViewControllerObjectType = sampleModule.component()
123 |
124 | override func viewDidLoad() {
125 | super.viewDidLoad()
126 |
127 | widgetModule.test() //"WidgetModule.test()"
128 | sampleModule.test() //"SampleModule.test()"
129 | widgetWorker.fetch(id: 3) //"|MediaRealmStore.3||MediaNetworkRemote.3|"
130 | someObject.testAbc() //"SomeObject.testAbc"
131 | anotherObject.testXyz() //"AnotherObject.testXyz|SomeObject.testAbc"
132 | viewModelObject.testLmn() //"SomeViewModel.testLmn|SomeObject.testAbc"
133 | viewModelObject.testLmnNested() //"SomeViewModel.testLmnNested|AnotherObject.testXyz|SomeObject.testAbc"
134 | viewControllerObject.testRst() //"SomeViewController.testRst|SomeObject.testAbc"
135 | viewControllerObject.testRstNested() //"SomeViewController.testRstNested|AnotherObject.testXyz|SomeObject.testAbc"
136 | }
137 | }
138 |
139 | // MARK: - Subtypes
140 |
141 | extension DependencyTests {
142 |
143 | struct WidgetModule: WidgetModuleType {
144 |
145 | func component() -> WidgetWorkerType {
146 | WidgetWorker(
147 | store: component(),
148 | remote: component()
149 | )
150 | }
151 |
152 | func component() -> WidgetRemote {
153 | WidgetNetworkRemote(httpService: component())
154 | }
155 |
156 | func component() -> WidgetStore {
157 | WidgetRealmStore()
158 | }
159 |
160 | func component() -> HTTPServiceType {
161 | HTTPService()
162 | }
163 |
164 | func test() -> String {
165 | "WidgetModule.test()"
166 | }
167 | }
168 |
169 | struct SampleModule: SampleModuleType {
170 |
171 | func component() -> SomeObjectType {
172 | SomeObject()
173 | }
174 |
175 | func component() -> AnotherObjectType {
176 | AnotherObject(someObject: component())
177 | }
178 |
179 | func component() -> ViewModelObjectType {
180 | SomeViewModel(
181 | someObject: component(),
182 | anotherObject: component()
183 | )
184 | }
185 |
186 | func component() -> ViewControllerObjectType {
187 | SomeViewController()
188 | }
189 |
190 | func test() -> String {
191 | "SampleModule.test()"
192 | }
193 | }
194 |
195 | struct SomeObject: SomeObjectType {
196 | func testAbc() -> String {
197 | "SomeObject.testAbc"
198 | }
199 | }
200 |
201 | struct AnotherObject: AnotherObjectType {
202 | private let someObject: SomeObjectType
203 |
204 | init(someObject: SomeObjectType) {
205 | self.someObject = someObject
206 | }
207 |
208 | func testXyz() -> String {
209 | "AnotherObject.testXyz|" + someObject.testAbc()
210 | }
211 | }
212 |
213 | struct SomeViewModel: ViewModelObjectType {
214 | private let someObject: SomeObjectType
215 | private let anotherObject: AnotherObjectType
216 |
217 | init(someObject: SomeObjectType, anotherObject: AnotherObjectType) {
218 | self.someObject = someObject
219 | self.anotherObject = anotherObject
220 | }
221 |
222 | func testLmn() -> String {
223 | "SomeViewModel.testLmn|" + someObject.testAbc()
224 | }
225 |
226 | func testLmnNested() -> String {
227 | "SomeViewModel.testLmnNested|" + anotherObject.testXyz()
228 | }
229 | }
230 |
231 | class SomeViewController: ViewControllerObjectType {
232 | @Inject private var module: SampleModuleType
233 |
234 | private lazy var someObject: SomeObjectType = module.component()
235 | private lazy var anotherObject: AnotherObjectType = module.component()
236 |
237 | func testRst() -> String {
238 | "SomeViewController.testRst|" + someObject.testAbc()
239 | }
240 |
241 | func testRstNested() -> String {
242 | "SomeViewController.testRstNested|" + anotherObject.testXyz()
243 | }
244 | }
245 |
246 | struct WidgetWorker: WidgetWorkerType {
247 | private let store: WidgetStore
248 | private let remote: WidgetRemote
249 |
250 | init(store: WidgetStore, remote: WidgetRemote) {
251 | self.store = store
252 | self.remote = remote
253 | }
254 |
255 | func fetch(id: Int) -> String {
256 | store.fetch(id: id)
257 | + remote.fetch(id: id)
258 | }
259 | }
260 |
261 | struct WidgetNetworkRemote: WidgetRemote {
262 | private let httpService: HTTPServiceType
263 |
264 | init(httpService: HTTPServiceType) {
265 | self.httpService = httpService
266 | }
267 |
268 | func fetch(id: Int) -> String {
269 | "|MediaNetworkRemote.\(id)|"
270 | }
271 | }
272 |
273 | struct WidgetRealmStore: WidgetStore {
274 |
275 | func fetch(id: Int) -> String {
276 | "|MediaRealmStore.\(id)|"
277 | }
278 |
279 | func createOrUpdate(_ request: String) -> String {
280 | "MediaRealmStore.createOrUpdate\(request)"
281 | }
282 | }
283 |
284 | struct HTTPService: HTTPServiceType {
285 |
286 | func get(url: String) -> String {
287 | "HTTPService.get"
288 | }
289 |
290 | func post(url: String) -> String {
291 | "HTTPService.post"
292 | }
293 | }
294 |
295 | // MARK: API
296 |
297 | protocol WidgetModuleType {
298 | func component() -> WidgetWorkerType
299 | func component() -> WidgetRemote
300 | func component() -> WidgetStore
301 | func component() -> HTTPServiceType
302 | func test() -> String
303 | }
304 |
305 | protocol SampleModuleType {
306 | func component() -> SomeObjectType
307 | func component() -> AnotherObjectType
308 | func component() -> ViewModelObjectType
309 | func component() -> ViewControllerObjectType
310 | func test() -> String
311 | }
312 |
313 | protocol SomeObjectType {
314 | func testAbc() -> String
315 | }
316 |
317 | protocol AnotherObjectType {
318 | func testXyz() -> String
319 | }
320 |
321 | protocol ViewModelObjectType {
322 | func testLmn() -> String
323 | func testLmnNested() -> String
324 | }
325 |
326 | protocol ViewControllerObjectType {
327 | func testRst() -> String
328 | func testRstNested() -> String
329 | }
330 |
331 | protocol WidgetStore {
332 | func fetch(id: Int) -> String
333 | func createOrUpdate(_ request: String) -> String
334 | }
335 |
336 | protocol WidgetRemote {
337 | func fetch(id: Int) -> String
338 | }
339 |
340 | protocol WidgetWorkerType {
341 | func fetch(id: Int) -> String
342 | }
343 |
344 | protocol HTTPServiceType {
345 | func get(url: String) -> String
346 | func post(url: String) -> String
347 | }
348 | ```
349 | This way, only your "modules" are not type-safe, which is acceptable since
350 | an exception with a missing module should happen early on and hopefully
351 | obvious enough in development.
352 |
353 | However, the individual components are type-safe and have greater flexiblity to include
354 | parameters while resolving the component. The components should have their dependencies
355 | injected through the constructor, which is the best form of dependency injection.
356 | The modules get the property wrappers support and can even inject modules within modules.
357 |
--------------------------------------------------------------------------------
/Sources/Shank/Shank.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Shank
3 | // A Swift micro-library that provides lightweight dependency injection.
4 | //
5 | // Inspired by:
6 | // https://dagger.dev
7 | // https://github.com/hmlongco/Resolver
8 | // https://github.com/InsertKoinIO/koin
9 | //
10 | // Created by Basem Emara on 2019-09-06.
11 | // Copyright © 2019 Zamzam Inc. All rights reserved.
12 | //
13 |
14 | import Foundation
15 |
16 | /// A dependency collection that provides resolutions for object instances.
17 | open class Dependencies {
18 | /// Stored object instance factories.
19 | private var modules = [String: Module]()
20 |
21 | /// Construct dependency resolutions.
22 | public init(@ModuleBuilder _ modules: () -> [Module]) {
23 | modules().forEach { add(module: $0) }
24 | }
25 |
26 | /// Construct dependency resolution.
27 | public init(@ModuleBuilder _ module: () -> Module) {
28 | add(module: module())
29 | }
30 |
31 | /// Assigns the current container to the composition root.
32 | open func build() {
33 | Self.root = self
34 | }
35 |
36 | fileprivate init() {}
37 | deinit { modules.removeAll() }
38 | }
39 |
40 | private extension Dependencies {
41 | /// Composition root container of dependencies.
42 | static var root = Dependencies()
43 |
44 | /// Registers a specific type and its instantiating factory.
45 | func add(module: Module) {
46 | modules[module.name] = module
47 | }
48 |
49 | /// Resolves through inference and returns an instance of the given type from the current default container.
50 | ///
51 | /// If the dependency is not found, an exception will occur.
52 | func resolve(for name: String? = nil) -> T {
53 | let name = name ?? String(describing: T.self)
54 |
55 | guard let component: T = modules[name]?.resolve() as? T else {
56 | fatalError("Dependency '\(T.self)' not resolved!")
57 | }
58 |
59 | return component
60 | }
61 | }
62 |
63 | // MARK: Public API
64 |
65 | public extension Dependencies {
66 |
67 | /// DSL for declaring modules within the container dependency initializer.
68 | @_functionBuilder struct ModuleBuilder {
69 | public static func buildBlock(_ modules: Module...) -> [Module] { modules }
70 | public static func buildBlock(_ module: Module) -> Module { module }
71 | }
72 | }
73 |
74 | /// A type that contributes to the object graph.
75 | public struct Module {
76 | fileprivate let name: String
77 | fileprivate let resolve: () -> Any
78 |
79 | public init(_ name: String? = nil, _ resolve: @escaping () -> T) {
80 | self.name = name ?? String(describing: T.self)
81 | self.resolve = resolve
82 | }
83 | }
84 |
85 | /// Resolves an instance from the dependency injection container.
86 | @propertyWrapper
87 | public class Inject {
88 | private let name: String?
89 | private var storage: Value?
90 |
91 | public var wrappedValue: Value {
92 | storage ?? {
93 | let value: Value = Dependencies.root.resolve(for: name)
94 | storage = value // Reuse instance for later
95 | return value
96 | }()
97 | }
98 |
99 | public init() {
100 | self.name = nil
101 | }
102 |
103 | public init(_ name: String) {
104 | self.name = name
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Tests/ShankTests/ShankTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Shank
3 |
4 | final class DependencyTests: XCTestCase {
5 |
6 | private static let dependencies = Dependencies {
7 | Module { WidgetModule() as WidgetModuleType }
8 | Module { SampleModule() as SampleModuleType }
9 | Module("abc") { SampleModule(value: "123") as SampleModuleType }
10 | Module { SomeClass() as SomeClassType }
11 | }
12 |
13 | @Inject private var widgetModule: WidgetModuleType
14 | @Inject private var sampleModule: SampleModuleType
15 | @Inject("abc") private var sampleModule2: SampleModuleType
16 | @Inject private var someClass: SomeClassType
17 |
18 | private lazy var widgetWorker: WidgetWorkerType = widgetModule.component()
19 | private lazy var someObject: SomeObjectType = sampleModule.component()
20 | private lazy var anotherObject: AnotherObjectType = sampleModule.component()
21 | private lazy var viewModelObject: ViewModelObjectType = sampleModule.component()
22 | private lazy var viewControllerObject: ViewControllerObjectType = sampleModule.component()
23 |
24 | override class func setUp() {
25 | super.setUp()
26 | dependencies.build()
27 | }
28 | }
29 |
30 | // MARK: - Test Cases
31 |
32 | extension DependencyTests {
33 |
34 | func testResolver() {
35 | // Given
36 | let widgetModuleResult = widgetModule.test()
37 | let sampleModuleResult = sampleModule.test()
38 | let sampleModule2Result = sampleModule2.test()
39 | let widgetResult = widgetWorker.fetch(id: 3)
40 | let someResult = someObject.testAbc()
41 | let anotherResult = anotherObject.testXyz()
42 | let viewModelResult = viewModelObject.testLmn()
43 | let viewModelNestedResult = viewModelObject.testLmnNested()
44 | let viewControllerResult = viewControllerObject.testRst()
45 | let viewControllerNestedResult = viewControllerObject.testRstNested()
46 |
47 | // Then
48 | XCTAssertEqual(widgetModuleResult, "WidgetModule.test()")
49 | XCTAssertEqual(sampleModuleResult, "SampleModule.test()")
50 | XCTAssertEqual(sampleModule2Result, "SampleModule.test()123")
51 | XCTAssertEqual(widgetResult, "|MediaRealmStore.3||MediaNetworkRemote.3|")
52 | XCTAssertEqual(someResult, "SomeObject.testAbc")
53 | XCTAssertEqual(anotherResult, "AnotherObject.testXyz|SomeObject.testAbc")
54 | XCTAssertEqual(viewModelResult, "SomeViewModel.testLmn|SomeObject.testAbc")
55 | XCTAssertEqual(viewModelNestedResult, "SomeViewModel.testLmnNested|AnotherObject.testXyz|SomeObject.testAbc")
56 | XCTAssertEqual(viewControllerResult, "SomeViewController.testRst|SomeObject.testAbc")
57 | XCTAssertEqual(viewControllerNestedResult, "SomeViewController.testRstNested|AnotherObject.testXyz|SomeObject.testAbc")
58 | }
59 |
60 | func testNumberOfInstances() {
61 | let instance1 = someClass
62 | let instance2 = someClass
63 | XCTAssertEqual(instance1.id, instance2.id)
64 | }
65 | }
66 |
67 | // MARK: - Subtypes
68 |
69 | extension DependencyTests {
70 |
71 | struct WidgetModule: WidgetModuleType {
72 |
73 | func component() -> WidgetWorkerType {
74 | WidgetWorker(
75 | store: component(),
76 | remote: component()
77 | )
78 | }
79 |
80 | func component() -> WidgetRemote {
81 | WidgetNetworkRemote(httpService: component())
82 | }
83 |
84 | func component() -> WidgetStore {
85 | WidgetRealmStore()
86 | }
87 |
88 | func component() -> HTTPServiceType {
89 | HTTPService()
90 | }
91 |
92 | func test() -> String {
93 | "WidgetModule.test()"
94 | }
95 | }
96 |
97 | struct SampleModule: SampleModuleType {
98 | let value: String?
99 |
100 | init(value: String? = nil) {
101 | self.value = value
102 | }
103 |
104 | func component() -> SomeObjectType {
105 | SomeObject()
106 | }
107 |
108 | func component() -> AnotherObjectType {
109 | AnotherObject(someObject: component())
110 | }
111 |
112 | func component() -> ViewModelObjectType {
113 | SomeViewModel(
114 | someObject: component(),
115 | anotherObject: component()
116 | )
117 | }
118 |
119 | func component() -> ViewControllerObjectType {
120 | SomeViewController()
121 | }
122 |
123 | func test() -> String {
124 | "SampleModule.test()\(value ?? "")"
125 | }
126 | }
127 |
128 | struct SomeObject: SomeObjectType {
129 | func testAbc() -> String {
130 | "SomeObject.testAbc"
131 | }
132 | }
133 |
134 | class SomeClass: SomeClassType {
135 | let id: String
136 |
137 | init() {
138 | self.id = UUID().uuidString
139 | }
140 | }
141 |
142 | struct AnotherObject: AnotherObjectType {
143 | private let someObject: SomeObjectType
144 |
145 | init(someObject: SomeObjectType) {
146 | self.someObject = someObject
147 | }
148 |
149 | func testXyz() -> String {
150 | "AnotherObject.testXyz|" + someObject.testAbc()
151 | }
152 | }
153 |
154 | struct SomeViewModel: ViewModelObjectType {
155 | private let someObject: SomeObjectType
156 | private let anotherObject: AnotherObjectType
157 |
158 | init(someObject: SomeObjectType, anotherObject: AnotherObjectType) {
159 | self.someObject = someObject
160 | self.anotherObject = anotherObject
161 | }
162 |
163 | func testLmn() -> String {
164 | "SomeViewModel.testLmn|" + someObject.testAbc()
165 | }
166 |
167 | func testLmnNested() -> String {
168 | "SomeViewModel.testLmnNested|" + anotherObject.testXyz()
169 | }
170 | }
171 |
172 | class SomeViewController: ViewControllerObjectType {
173 | @Inject private var module: SampleModuleType
174 |
175 | private lazy var someObject: SomeObjectType = module.component()
176 | private lazy var anotherObject: AnotherObjectType = module.component()
177 |
178 | func testRst() -> String {
179 | "SomeViewController.testRst|" + someObject.testAbc()
180 | }
181 |
182 | func testRstNested() -> String {
183 | "SomeViewController.testRstNested|" + anotherObject.testXyz()
184 | }
185 | }
186 |
187 | struct WidgetWorker: WidgetWorkerType {
188 | private let store: WidgetStore
189 | private let remote: WidgetRemote
190 |
191 | init(store: WidgetStore, remote: WidgetRemote) {
192 | self.store = store
193 | self.remote = remote
194 | }
195 |
196 | func fetch(id: Int) -> String {
197 | store.fetch(id: id)
198 | + remote.fetch(id: id)
199 | }
200 | }
201 |
202 | struct WidgetNetworkRemote: WidgetRemote {
203 | private let httpService: HTTPServiceType
204 |
205 | init(httpService: HTTPServiceType) {
206 | self.httpService = httpService
207 | }
208 |
209 | func fetch(id: Int) -> String {
210 | "|MediaNetworkRemote.\(id)|"
211 | }
212 | }
213 |
214 | struct WidgetRealmStore: WidgetStore {
215 |
216 | func fetch(id: Int) -> String {
217 | "|MediaRealmStore.\(id)|"
218 | }
219 |
220 | func createOrUpdate(_ request: String) -> String {
221 | "MediaRealmStore.createOrUpdate\(request)"
222 | }
223 | }
224 |
225 | struct HTTPService: HTTPServiceType {
226 |
227 | func get(url: String) -> String {
228 | "HTTPService.get"
229 | }
230 |
231 | func post(url: String) -> String {
232 | "HTTPService.post"
233 | }
234 | }
235 | }
236 |
237 | // MARK: API
238 |
239 | protocol WidgetModuleType {
240 | func component() -> WidgetWorkerType
241 | func component() -> WidgetRemote
242 | func component() -> WidgetStore
243 | func component() -> HTTPServiceType
244 | func test() -> String
245 | }
246 |
247 | protocol SampleModuleType {
248 | func component() -> SomeObjectType
249 | func component() -> AnotherObjectType
250 | func component() -> ViewModelObjectType
251 | func component() -> ViewControllerObjectType
252 | func test() -> String
253 | }
254 |
255 | protocol SomeObjectType {
256 | func testAbc() -> String
257 | }
258 |
259 | protocol AnotherObjectType {
260 | func testXyz() -> String
261 | }
262 |
263 | protocol SomeClassType {
264 | var id: String { get }
265 | }
266 |
267 | protocol ViewModelObjectType {
268 | func testLmn() -> String
269 | func testLmnNested() -> String
270 | }
271 |
272 | protocol ViewControllerObjectType {
273 | func testRst() -> String
274 | func testRstNested() -> String
275 | }
276 |
277 | protocol WidgetStore {
278 | func fetch(id: Int) -> String
279 | func createOrUpdate(_ request: String) -> String
280 | }
281 |
282 | protocol WidgetRemote {
283 | func fetch(id: Int) -> String
284 | }
285 |
286 | protocol WidgetWorkerType {
287 | func fetch(id: Int) -> String
288 | }
289 |
290 | protocol HTTPServiceType {
291 | func get(url: String) -> String
292 | func post(url: String) -> String
293 | }
294 |
--------------------------------------------------------------------------------