molt 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +56 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +6 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +5 -0
  8. data/Gemfile.lock +55 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +210 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +7 -0
  13. data/bin/molt +6 -0
  14. data/bin/setup +7 -0
  15. data/bundled/models/Entity+CoreData.swift.liquid +15 -0
  16. data/bundled/models/Entity.swift.liquid +7 -0
  17. data/bundled/models/Model.swift.liquid +20 -0
  18. data/bundled/partials/_header.liquid +5 -0
  19. data/bundled/swift_helpers/ErrorTypes/APIError.swift +28 -0
  20. data/bundled/swift_helpers/ErrorTypes/ErrorTypes.swift +12 -0
  21. data/bundled/swift_helpers/ErrorTypes/PersistenceError.swift +28 -0
  22. data/bundled/swift_helpers/ISODateTransform.swift +26 -0
  23. data/bundled/swift_helpers/Identifiable.swift +29 -0
  24. data/bundled/swift_helpers/Loadable.swift +37 -0
  25. data/bundled/swift_helpers/Networking/APIRouter.swift +54 -0
  26. data/bundled/swift_helpers/StoryboardExtensions.swift +49 -0
  27. data/bundled/template_sets/viper_detail/Presenter.swift.liquid +17 -0
  28. data/bundled/template_sets/viper_detail/Protocols.swift.liquid +23 -0
  29. data/bundled/template_sets/viper_detail/View.swift.liquid +25 -0
  30. data/bundled/template_sets/viper_detail/WireFrame.swift.liquid +21 -0
  31. data/bundled/template_sets/viper_table/DataManagers/LocalDataManager.swift.liquid +45 -0
  32. data/bundled/template_sets/viper_table/DataManagers/RemoteDataManager.swift.liquid +26 -0
  33. data/bundled/template_sets/viper_table/Interactor.swift.liquid +48 -0
  34. data/bundled/template_sets/viper_table/Presenter.swift.liquid +49 -0
  35. data/bundled/template_sets/viper_table/Protocols.swift.liquid +58 -0
  36. data/bundled/template_sets/viper_table/View.swift.liquid +60 -0
  37. data/bundled/template_sets/viper_table/WireFrame.swift.liquid +43 -0
  38. data/lib/generamba/string-colorize.rb +31 -0
  39. data/lib/molt/cli/create_module.rb +76 -0
  40. data/lib/molt/cli/main.rb +74 -0
  41. data/lib/molt/cli/setup.rb +23 -0
  42. data/lib/molt/cli/template_sets.rb +18 -0
  43. data/lib/molt/configuration.rb +43 -0
  44. data/lib/molt/template.rb +9 -0
  45. data/lib/molt/version.rb +3 -0
  46. data/lib/molt.rb +22 -0
  47. data/molt.gemspec +32 -0
  48. data/sample_configs/global_config.yml.erb +7 -0
  49. metadata +218 -0
@@ -0,0 +1,29 @@
1
+ //
2
+ // Identifiable.swift
3
+ // YATodo
4
+ //
5
+ // Created by Marco Cabazal on 2/3/18.
6
+ // Copyright © 2018 The Chill Mill, Inc. All rights reserved.
7
+ //
8
+
9
+ import UIKit
10
+ import CoreData
11
+
12
+ // swiftlint:disable identifier_name
13
+ protocol Identifiable {
14
+ static var id: String { get }
15
+ }
16
+
17
+ extension Identifiable {
18
+
19
+ // return an introspective string representation of the invoking class, which is
20
+ // generally a shorter alternative to using R.swift's R.nib.viewClass.identifier
21
+ static var id: String {
22
+ return String(describing: self)
23
+ }
24
+ }
25
+ // swiftlint:enable identifier_name
26
+
27
+ extension UIViewController: Identifiable { }
28
+ extension UIView: Identifiable { }
29
+ extension NSManagedObject: Identifiable { }
@@ -0,0 +1,37 @@
1
+ //
2
+ // Loadable.swift
3
+ // YATodo
4
+ //
5
+ // Created by Marco Cabazal on 2/3/18.
6
+ // Copyright © 2018 The Chill Mill, Inc. All rights reserved.
7
+ //
8
+
9
+ import UIKit
10
+ import PKHUD
11
+
12
+ protocol Loadable: class {
13
+ func show(error: Error)
14
+ func showLoadingIndicator()
15
+ func hideLoadingIndicator()
16
+ }
17
+
18
+ extension UIViewController: Loadable {
19
+
20
+ func show(error: Error) {
21
+ switch error {
22
+ case let error as DisplayableError:
23
+ HUD.flash(.labeledError(title: error.title, subtitle: error.message), delay: 5.0)
24
+ default:
25
+ // TODO: error is not displayable so log specifics of error instead
26
+ HUD.flash(.labeledError(title: "Ooops", subtitle: "Something is not cooperating"), delay: 5.0)
27
+ }
28
+ }
29
+
30
+ func showLoadingIndicator() {
31
+ HUD.show(.progress)
32
+ }
33
+
34
+ func hideLoadingIndicator() {
35
+ HUD.hide()
36
+ }
37
+ }
@@ -0,0 +1,54 @@
1
+ //
2
+ // Endpoints.swift
3
+ // CapoRegime
4
+ //
5
+ // Created by Marco Cabazal on 18 Jan 2017.
6
+ // Copyright © 2017 The Chill Mill, Inc. All rights reserved.
7
+ //
8
+
9
+ import Alamofire
10
+
11
+ struct Config {
12
+ static let API = "http://caporegime.rb/v1"
13
+ }
14
+
15
+ enum APIRouter: URLRequestConvertible {
16
+ case friends
17
+
18
+ private var path: String {
19
+ switch self {
20
+ case .friends:
21
+ return "/friends"
22
+ }
23
+ }
24
+
25
+ private var method: HTTPMethod {
26
+ switch self {
27
+ case .friends:
28
+ return .get
29
+ }
30
+ }
31
+
32
+ private var parameters: Parameters? {
33
+ return nil
34
+ }
35
+
36
+ private var headers: [String: String] {
37
+ return [ "Content-Type": "application/json" ]
38
+ }
39
+
40
+ func asURLRequest() throws -> URLRequest {
41
+ let baseURL = try Config.API.asURL()
42
+ var urlRequest = URLRequest(url: baseURL.appendingPathComponent(path))
43
+
44
+ urlRequest.httpMethod = method.rawValue
45
+
46
+ for (header, value) in headers {
47
+ urlRequest.setValue(value, forHTTPHeaderField: header)
48
+ }
49
+
50
+ urlRequest = try JSONEncoding.default.encode(urlRequest, with: parameters)
51
+
52
+ return urlRequest
53
+ }
54
+ }
@@ -0,0 +1,49 @@
1
+ //
2
+ // StoryboardExtensions.swift
3
+ // YATodo
4
+ //
5
+ // Created by Marco Cabazal on 18 Jan 2017.
6
+ // Copyright © 2018 The Chill Mill, Inc. All rights reserved.
7
+ //
8
+
9
+ import UIKit
10
+
11
+ enum Storyboard: String {
12
+ case main = "Main"
13
+
14
+ var storyboard: UIStoryboard {
15
+ return UIStoryboard(name: self.rawValue, bundle: Bundle.main)
16
+ }
17
+
18
+ fileprivate func viewController<T: UIViewController>(as: T.Type, identifier: String,
19
+ function: String = #function, line: Int = #line, file: String = #file) -> T {
20
+
21
+ guard let scene = storyboard.instantiateViewController(withIdentifier: identifier) as? T else {
22
+ fatalError("ViewController with identifier \(identifier), not found. Reference: \(self.rawValue) Storyboard.\nFile : \(file) \nLine Number : \(line) \nFunction : \(function)")
23
+ }
24
+
25
+ return scene
26
+ }
27
+
28
+ func initialViewController() -> UIViewController? {
29
+ return storyboard.instantiateInitialViewController()
30
+ }
31
+ }
32
+
33
+ extension UIViewController {
34
+
35
+ static func instantiate(from storyboard: Storyboard) -> Self {
36
+ return storyboard.viewController(as: self, identifier: self.id)
37
+ }
38
+
39
+ static func instantiate(from storyboard: Storyboard, identifier: String) -> Self {
40
+ return storyboard.viewController(as: self, identifier: identifier)
41
+ }
42
+ }
43
+
44
+ extension UITableViewCell {
45
+
46
+ static var nib: UINib {
47
+ return UINib(nibName: self.id, bundle: Bundle.main)
48
+ }
49
+ }
@@ -0,0 +1,17 @@
1
+ //
2
+ // {{ module_name }}Interactor.swift
3
+ {% include 'header' %}
4
+ final class {{ module_name }}Presenter {
5
+
6
+ weak var view: {{ module_name }}ViewProtocol?
7
+ var wireFrame: {{ module_name }}WireFrameProtocol?
8
+ var dataSource: {{ model }}?
9
+ }
10
+
11
+ // MARK: CALLED BY VIEW
12
+ extension {{ module_name }}Presenter: {{ module_name }}PresenterProtocol {
13
+
14
+ func viewDidLoad() {
15
+ view?.render(content: dataSource)
16
+ }
17
+ }
@@ -0,0 +1,23 @@
1
+ //
2
+ // {{ module_name }}Protocols.swift
3
+ {% include 'header' %}
4
+ import UIKit
5
+
6
+ // MARK: Called by VIEW -> Implemented BY PRESENTER
7
+ protocol {{ module_name }}PresenterProtocol: class {
8
+ weak var view: {{ module_name }}ViewProtocol? { get set }
9
+ weak var wireFrame: {{ module_name }}WireFrameProtocol? { get set }
10
+ var dataSource: {{ model }}? { get set }
11
+
12
+ func viewDidLoad()
13
+ }
14
+
15
+ // MARK: PRESENTER -> VIEW
16
+ protocol {{ module_name }}ViewProtocol: Loadable {
17
+ func render(content: {{ model }}?)
18
+ }
19
+
20
+ // MARK: PRESENTER -> WIREFRAME
21
+ protocol {{ module_name }}WireFrameProtocol: class {
22
+ static func prepareModule(with object: {{ model }}) -> UIViewController
23
+ }
@@ -0,0 +1,25 @@
1
+ //
2
+ // {{ module_name }}View.swift
3
+ {% include 'header' %}
4
+ import UIKit
5
+
6
+ class {{ module_name }}View: UIViewController {
7
+
8
+ var presenter: {{ module_name }}PresenterProtocol?
9
+
10
+ @IBOutlet weak var titleLabel: UILabel!
11
+
12
+ override func viewDidLoad() {
13
+ super.viewDidLoad()
14
+ presenter?.viewDidLoad()
15
+ }
16
+ }
17
+
18
+ // MARK: CALLED BY PRESENTER
19
+ extension {{ module_name }}View: {{ module_name }}ViewProtocol {
20
+
21
+ func render(content: {{ model }}?) {
22
+ guard let content = content else { return }
23
+ titleLabel?.text = content.title
24
+ }
25
+ }
@@ -0,0 +1,21 @@
1
+ //
2
+ // {{ module_name }}WireFrame.swift
3
+ {% include 'header' %}
4
+ import UIKit
5
+
6
+ final class {{ module_name }}WireFrame: {{ module_name }}WireFrameProtocol {
7
+
8
+ static func prepareModule(with object: {{ model }}) -> UIViewController {
9
+ let view = {{ module_name }}View.instantiate(from: .main)
10
+
11
+ let presenter: {{ module_name }}PresenterProtocol = {{ module_name }}Presenter()
12
+ let wireFrame = {{ module_name }}WireFrame()
13
+
14
+ view.presenter = presenter
15
+ presenter.view = view
16
+ presenter.dataSource = object
17
+ presenter.wireFrame = wireFrame
18
+
19
+ return view
20
+ }
21
+ }
@@ -0,0 +1,45 @@
1
+ //
2
+ // {{ module_name }}LocalDataManager.swift
3
+ {% include 'header' %}
4
+ import CoreData
5
+ import Hydra
6
+
7
+ // MARK: CALLED BY INTERACTOR
8
+ class {{ module_name }}LocalDataManager: {{ module_name }}LocalDataManagerProtocol {
9
+
10
+ func retrieveDataFromStorage() -> Promise<[{{ entity }}]> {
11
+ return Promise<[{{ entity }}]>(in: .main) { resolve, reject, _ in
12
+ guard let moc = CoreDataStore.moc else {
13
+ reject(PersistenceError.mocNotFound)
14
+ return
15
+ }
16
+ do {
17
+ let request: NSFetchRequest<{{ entity }}> = NSFetchRequest(entityName: {{ entity }}.id)
18
+ resolve(try moc.fetch(request))
19
+ } catch {
20
+ reject(PersistenceError.objectNotFound)
21
+ }
22
+ }
23
+ }
24
+
25
+ func saveEntity(id: Int, title: String) -> Promise<Void> {
26
+ return Promise<Void>(in: .main) { resolve, reject, _ in
27
+ guard let moc = CoreDataStore.moc else {
28
+ reject(PersistenceError.mocNotFound)
29
+ return
30
+ }
31
+
32
+ do {
33
+ if let entity = NSEntityDescription.entity(forEntityName: {{ entity }}.id, in: moc) {
34
+ let object = {{ entity }}(entity: entity, insertInto: moc)
35
+ object.id = Int32(id)
36
+ object.title = title
37
+ try moc.save()
38
+ resolve(())
39
+ }
40
+ } catch {
41
+ reject(PersistenceError.couldNotSaveObject)
42
+ }
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,26 @@
1
+ //
2
+ // {{ module_name }}RemoteDataManager.swift
3
+ {% include 'header' %}
4
+ import Alamofire
5
+ import AlamofireObjectMapper
6
+ import Hydra
7
+
8
+ // MARK: CALLED BY INTERACTOR
9
+ class {{ module_name }}RemoteDataManager: {{ module_name }}RemoteDataManagerProtocol {
10
+
11
+ func retrieveDataFromAPI() -> Promise<[{{ model }}]> {
12
+ return Promise<[{{ model }}]>(in: .background) { resolve, reject, _ in
13
+ Alamofire.request(APIRouter.{{ model | downcase }})
14
+ .validate()
15
+ .responseArray(keyPath: "{{ model | downcase }}") { (response: DataResponse<[{{ model }}]>) in
16
+
17
+ switch response.result {
18
+ case .success(let data):
19
+ resolve(data)
20
+ case .failure:
21
+ reject(APIError.unknown)
22
+ }
23
+ }
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,48 @@
1
+ //
2
+ // {{ module_name }}Interactor.swift
3
+ {% include 'header' %}
4
+ final class {{ module_name }}Interactor {
5
+ weak var presenter: {{ module_name }}InteractorOutputProtocol?
6
+ var localDataManager: {{ module_name }}LocalDataManagerProtocol?
7
+ var remoteDataManager: {{ module_name }}RemoteDataManagerProtocol?
8
+ }
9
+
10
+ // MARK: CALLED BY PRESENTER
11
+ extension {{ module_name }}Interactor: {{ module_name }}InteractorProtocol {
12
+
13
+ func retrieveData() {
14
+ localDataManager?.retrieveDataFromStorage().then({ [weak self] persistedData in
15
+ let data: [{{ model }}] = persistedData.map {
16
+ return {{ model }}(id: Int($0.id), title: $0.title ?? "", dueDate: $0.dueDate)
17
+ }
18
+
19
+ if !data.isEmpty {
20
+ self?.presenter?.present(data: data)
21
+ } else {
22
+ self?.retrieveDataFromAPI()
23
+ }
24
+ }).catch({ [weak self] error in
25
+ self?.presenter?.present(error: error)
26
+ })
27
+ }
28
+ }
29
+
30
+ extension {{ module_name }}Interactor {
31
+
32
+ fileprivate func retrieveDataFromAPI() {
33
+ remoteDataManager?.retrieveDataFromAPI().then({ [weak self] data in
34
+ self?.persist(data: data)
35
+ self?.presenter?.present(data: data)
36
+ }).catch({ [weak self] error in
37
+ self?.presenter?.present(error: error)
38
+ })
39
+ }
40
+
41
+ fileprivate func persist(data: [{{ model }}]) {
42
+ for item in data {
43
+ localDataManager?.saveEntity(id: item.id, title: item.title).catch({ [weak self] error in
44
+ self?.presenter?.present(error: error)
45
+ })
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,49 @@
1
+ //
2
+ // {{ module_name }}Presenter.swift
3
+ {% include 'header' %}
4
+ final class {{ module_name }}Presenter {
5
+
6
+ weak var view: {{ module_name }}ViewProtocol?
7
+ var wireFrame: {{ module_name }}WireFrameProtocol?
8
+ var interactor: {{ module_name }}InteractorProtocol?
9
+ var dataSource: [{{ model }}] = []
10
+ }
11
+
12
+ // MARK: CALLED BY VIEW
13
+ extension {{ module_name }}Presenter: {{ module_name }}PresenterProtocol {
14
+
15
+ func viewDidLoad() {
16
+ view?.showLoadingIndicator()
17
+ interactor?.retrieveData()
18
+ }
19
+
20
+ var numberOfSection: Int { return self.dataSource.count + 1 }
21
+
22
+ func numberOfRows(in section: Int) -> Int {
23
+ return dataSource.count
24
+ }
25
+
26
+ func content(at row: Int) -> {{ model }}? {
27
+ return dataSource[row]
28
+ }
29
+
30
+ func process(object: {{ model }}) {
31
+ guard let view = view else { return }
32
+ wireFrame?.navigate(to: object, from: view)
33
+ }
34
+ }
35
+
36
+ // MARK: CALLED BY INTERACTOR
37
+ extension {{ module_name }}Presenter: {{ module_name }}InteractorOutputProtocol {
38
+
39
+ func present(data: [{{ model }}]) {
40
+ self.dataSource = data
41
+ view?.hideLoadingIndicator()
42
+ view?.render()
43
+ }
44
+
45
+ func present(error: Error) {
46
+ view?.hideLoadingIndicator()
47
+ view?.show(error: error)
48
+ }
49
+ }
@@ -0,0 +1,58 @@
1
+ //
2
+ // {{ module_name }}Protocols.swift
3
+ {% include 'header' %}
4
+ import UIKit
5
+ import Hydra
6
+
7
+ // MARK: Called by VIEW -> Implemented BY PRESENTER
8
+ protocol {{ module_name }}PresenterProtocol: class {
9
+ var view: {{ module_name }}ViewProtocol? { get set }
10
+ var wireFrame: {{ module_name }}WireFrameProtocol? { get set }
11
+ var interactor: {{ module_name }}InteractorProtocol? { get set }
12
+
13
+ func viewDidLoad()
14
+
15
+ // datasource
16
+ var numberOfSection: Int { get }
17
+ func numberOfRows(in section: Int) -> Int
18
+ func content(at row: Int) -> <{{ model }}>?
19
+
20
+ func process(object: {{ model }})
21
+ }
22
+
23
+ // MARK: PRESENTER -> INTERACTOR
24
+ protocol {{ module_name }}InteractorProtocol: class {
25
+ var presenter: {{ module_name }}InteractorOutputProtocol? { get set }
26
+ var localDataManager: {{ module_name }}LocalDataManagerProtocol? { get set }
27
+ var remoteDataManager: {{ module_name }}RemoteDataManagerProtocol? { get set }
28
+
29
+ func retrieveData()
30
+ }
31
+
32
+ // MARK: INTERACTOR -> REMOTEDATAMANAGER
33
+ protocol {{ module_name }}RemoteDataManagerProtocol: class {
34
+ func retrieveDataFromAPI() -> Promise<[{{ model }}]>
35
+ }
36
+
37
+ // MARK: INTERACTOR -> LOCALDATAMANAGER
38
+ protocol {{ module_name }}LocalDataManagerProtocol: class {
39
+ func retrieveDataFromStorage() -> Promise<[{{ entity }}]>
40
+ func saveEntity(id: Int, title: String) -> Promise<Void>
41
+ }
42
+
43
+ // MARK: INTERACTOR -> PRESENTER
44
+ protocol {{ module_name }}InteractorOutputProtocol: class {
45
+ func present(data: [{{ model }}])
46
+ func present(error: Error)
47
+ }
48
+
49
+ // MARK: PRESENTER -> VIEW
50
+ protocol {{ module_name }}ViewProtocol: Loadable {
51
+ func render()
52
+ }
53
+
54
+ // MARK: PRESENTER -> WIREFRAME
55
+ protocol {{ module_name }}WireFrameProtocol: class {
56
+ static func prepareModule() -> UIViewController
57
+ func navigate(to object: {{ model }}, from view: {{ module_name }}ViewProtocol)
58
+ }
@@ -0,0 +1,60 @@
1
+ //
2
+ // {{ module_name }}View.swift
3
+ {% include 'header' %}
4
+ import UIKit
5
+
6
+ class {{ module_name }}View: UIViewController {
7
+
8
+ var presenter: {{ module_name }}PresenterProtocol?
9
+
10
+ @IBOutlet weak var tableView: UITableView!
11
+
12
+ override func viewDidLoad() {
13
+ super.viewDidLoad()
14
+ tableView.tableFooterView = UIView()
15
+ tableView.register({{ entity}}Cell.nib, forCellReuseIdentifier: {{ entity}}Cell.id)
16
+ presenter?.viewDidLoad()
17
+ }
18
+
19
+ override func viewWillAppear(_ animated: Bool) {
20
+ super.viewWillAppear(animated)
21
+ if let selectedRow = tableView.indexPathForSelectedRow {
22
+ tableView.deselectRow(at: selectedRow, animated: true)
23
+ }
24
+ }
25
+ }
26
+
27
+ // MARK: CALLED BY PRESENTER
28
+ extension {{ module_name }}View: {{ module_name }}ViewProtocol {
29
+
30
+ func render() {
31
+ tableView.reloadData()
32
+ }
33
+ }
34
+
35
+ // MARK: UITABLEVIEW DATASOURCE
36
+ extension {{ module_name }}View: UITableViewDataSource {
37
+
38
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
39
+ return presenter?.numberOfRows(in: section) ?? 0
40
+ }
41
+
42
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
43
+ guard let content = presenter?.content(at: indexPath.row),
44
+ let cell = tableView.dequeueReusableCell(withIdentifier: {{ entity}}Cell.id, for: indexPath) as? {{ entity}}Cell else {
45
+ return tableView.dequeueReusableCell(withIdentifier: {{ entity}}Cell.id, for: indexPath)
46
+ }
47
+
48
+ cell.configure(with: content)
49
+ return cell
50
+ }
51
+ }
52
+
53
+ // MARK: UITABLEVIEW DELEGATE
54
+ extension {{ module_name }}View: UITableViewDelegate {
55
+
56
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
57
+ guard let content = presenter?.content(at: indexPath.row) else { return }
58
+ presenter?.process(object: content)
59
+ }
60
+ }
@@ -0,0 +1,43 @@
1
+ //
2
+ // {{ module_name }}WireFrame.swift
3
+ {% include 'header' %}
4
+ import UIKit
5
+
6
+ final class {{ module_name }}WireFrame {
7
+
8
+ static func prepareModule() -> UIViewController {
9
+ let navController = UINavigationController.instantiate(from: .main, identifier: "mainNavigationController")
10
+
11
+ guard let view = navController.childViewControllers.first as? {{ module_name }}View else {
12
+ return UIViewController()
13
+ }
14
+
15
+ let presenter: {{ module_name }}PresenterProtocol & {{ module_name }}InteractorOutputProtocol = {{ module_name }}Presenter()
16
+ let interactor: {{ module_name }}InteractorProtocol = {{ module_name }}Interactor()
17
+ let wireFrame: {{ module_name }}WireFrameProtocol = {{ module_name }}WireFrame()
18
+ let localDataManager: {{ module_name }}LocalDataManagerProtocol = {{ module_name }}LocalDataManager()
19
+ let remoteDataManager: {{ module_name }}RemoteDataManagerProtocol = {{ module_name }}RemoteDataManager()
20
+
21
+ // INTEGRATION
22
+ view.presenter = presenter
23
+ presenter.view = view
24
+ presenter.wireFrame = wireFrame
25
+ presenter.interactor = interactor
26
+ interactor.presenter = presenter
27
+ interactor.localDataManager = localDataManager
28
+ interactor.remoteDataManager = remoteDataManager
29
+
30
+ return navController
31
+ }
32
+ }
33
+
34
+ // MARK: NAVIGATION
35
+ extension {{ module_name }}WireFrame: {{ module_name }}WireFrameProtocol {
36
+
37
+ func navigate(to object: {{ model }}, from view: {{ module_name }}ViewProtocol) {
38
+ guard let sourceView = view as? UIViewController else { return }
39
+
40
+ let detailVC = {{ module_name }}DetailWireFrame.prepareModule(with: object)
41
+ sourceView.navigationController?.pushViewController(detailVC, animated: true)
42
+ }
43
+ }
@@ -0,0 +1,31 @@
1
+ # Borrowed from Egor Tolstoy, Beniamin Sarkisyan, Andrey Zarembo et al (Generamba/Rambler)
2
+ class String
3
+
4
+ def colorize(color_code)
5
+ "\e[#{color_code}m#{self}\e[0m"
6
+ end
7
+
8
+ def red
9
+ colorize(31)
10
+ end
11
+
12
+ def green
13
+ colorize(32)
14
+ end
15
+
16
+ def yellow
17
+ colorize(33)
18
+ end
19
+
20
+ def blue
21
+ colorize(34)
22
+ end
23
+
24
+ def pink
25
+ colorize(35)
26
+ end
27
+
28
+ def light_blue
29
+ colorize(36)
30
+ end
31
+ end