molt 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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