Package: igen
igen - A code generator for iOS appInstallation:Install using pip:Open Terminal and run:$ pip3 install igenUpdate:$ pip3 install -U igenor$ pip3 uninstall igen
$ pip3 install igen --no-cache-dirUninstall:$ pip3 uninstall igenHow to install pip3:pip3 is already installed if you are using Python 3 (>=3.4)In order to install Python 3, you need to install Homebrew, run the following command in Terminal:$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"Then install Python 3:$ brew install python1. Create Template:1.1. Base Template:The Base Template contains necessary files for a screen using theClean Architecturepattern.Open Terminal, navigate to the folder you want to save the files and run:$ igen template base <Scene_Name> [--window]Options:--window: use UIWindow instead of UINavigationController in the Navigator.The first time you use thetemplatecommand, you need to enter your project information:Enter project name: Your Project
Enter developer name: Your Name
Enter company name: Your CompanyLater, if you want to update the information you can run:$ igen config projectExample:$ igen template base LoginOutput:Successfully created files:
    Login/LoginViewModel.swift
    Login/LoginNavigator.swift
    Login/LoginUseCase.swift
    Login/LoginViewController.swift
    Login/LoginAssembler.swift
    Login/Test/LoginViewModelTests.swift
    Login/Test/LoginUseCaseMock.swift
    Login/Test/LoginNavigatorMock.swift
    Login/Test/LoginViewControllerTests.swift1.2. Skeleton Template:To create a Clean Architecture skeleton project, run:$ igen template skeleton <Folder_Name>Example:Run the following command in Terminal:$ igen template skeleton DemoAppOutput:Successfully created files:
    DemoApp/Podfile
    DemoApp/gitignore
    DemoApp/Localizable.strings
    DemoApp/pull_request_template.md
    DemoApp/swiftlint.yml
    DemoApp/DemoApp-Bridging-Header.h
    DemoApp/Sources/UnitTestViewController.swift
    DemoApp/Sources/AppDelegate.swift
    DemoApp/Sources/Assembler.swift
    DemoApp/Sources/Support/Utils.swift
    DemoApp/Sources/Support/Extensions/UIViewController+.swift
    DemoApp/Sources/Support/Extensions/UIViewController+Rx.swift
    DemoApp/Sources/Data/Gateways/GatewaysAssembler.swift
    DemoApp/Sources/Data/API/APIError.swift
    DemoApp/Sources/Data/API/APIService.swift
    DemoApp/Sources/Data/API/APIInput.swift
    DemoApp/Sources/Data/API/APIOutput.swift
    DemoApp/Sources/Config/APIUrls.swift
    DemoApp/Sources/Scenes/App/AppAssembler.swift
    DemoApp/Sources/Scenes/App/AppNavigator.swift
    DemoApp/Sources/Scenes/App/AppUseCase.swift
    DemoApp/Sources/Scenes/App/AppViewModel.swift
    DemoApp/Sources/Scenes/Storyboards/Storyboards.swift1.3. List Template:The List Template shows a list of objects in a UITableView or a UICollectionView.Copy the model to the pasteboard (clipboard) then run:$ igen template list <Scene_Name> [--section] [--collection] [--window] [--paging]Options:--paging: use pagination.--section: show the list with header sections.--collection: use UICollectionView instead of UITableView.--window: use UIWindow instead of UINavigationController in the Navigator.Example:Copy the model:structProduct{letid:Intletname:Stringletprice:Double}then run:$ igen template list ProductListOutput:Successfully created files:
    ProductList/ProductListViewModel.swift
    ProductList/ProductItemViewModel.swift
    ProductList/ProductListNavigator.swift
    ProductList/ProductListUseCase.swift
    ProductList/ProductListViewController.swift
    ProductList/ProductCell.swift
    ProductList/ProductListAssembler.swift
    ProductList/Test/ProductListViewModelTests.swift
    ProductList/Test/ProductListUseCaseMock.swift
    ProductList/Test/ProductListNavigatorMock.swift
    ProductList/Test/ProductListViewControllerTests.swift
    ProductList/Test/ProductCellTests.swift1.4. Detail Template:The Detail Template shows details of an object in a UITableView.Copy the model then run:$ igen template detail <Scene_Name> [--static] [--window]Options:--static: display details of the object in a static UITableViewController.--window: use UIWindow instead of UINavigationController in the Navigator.Example:Copy the model:structProduct{letid:Intletname:Stringletprice:Double}then run:$ igen template detail ProductDetailOutput:Successfully created files:
    ProductDetail/ProductDetailViewModel.swift
    ProductDetail/ProductDetailNavigator.swift
    ProductDetail/ProductDetailUseCase.swift
    ProductDetail/ProductDetailViewController.swift
    ProductDetail/ProductIdCell.swift
    ProductDetail/ProductNameCell.swift
    ProductDetail/ProductPriceCell.swift
    ProductDetail/ProductDetailAssembler.swift
    ProductDetail/Test/ProductDetailViewModelTests.swift
    ProductDetail/Test/ProductDetailUseCaseMock.swift
    ProductDetail/Test/ProductDetailNavigatorMock.swift
    ProductDetail/Test/ProductDetailViewControllerTests.swift
    ProductDetail/Test/ProductDetailCellsTests.swift1.5. Form Input Template:To create a form input template for a model, copy the model then run:$ igen template form <Scene_Name> [--submit SUBMIT] [--dynamic] [--window]Options:--submit: set the name of the submit action.--dynamic: use the dynamic form instead of the static form.--window: use UIWindow instead of UINavigationController in the Navigator.Example:Copy the model:structProduct{varid:Intvarname:Stringvarprice:Double}then run:$ igen template form CreateProduct --submit CreateOutput:Successfully created files:
    CreateProduct/CreateProductAssembler.swift
    CreateProduct/CreateProductNavigator.swift
    CreateProduct/CreateProductViewModel.swift
    CreateProduct/CreateProductUseCase.swift
    CreateProduct/CreateProductViewController.swift
    CreateProduct/Test/CreateProductUseCaseMock.swift
    CreateProduct/Test/CreateProductNavigatorMock.swift
    CreateProduct/Test/CreateProductViewModelTests.swift
    CreateProduct/Test/CreateProductViewControllerTests.swift1.6. Setting Template:To create a setting template, copy the setting enum then run:$ igen template setting <Scene_Name> [--section] [--window]Options:--section: show the list with header sections.--window: use UIWindow instead of UINavigationController in the Navigator.Example:Copy the enum:enumSettingMenu{caseaboutcasesupportcasefacebookcaseemailcaserating}then run:$ igen template setting SettingOutput:Successfully created files:
    Setting/SettingAssembler.swift
    Setting/SettingNavigator.swift
    Setting/SettingViewModel.swift
    Setting/SettingUseCase.swift
    Setting/SettingViewController.swift
    Setting/SettingMenuCell.swift
    Setting/Test/SettingUseCaseMock.swift
    Setting/Test/SettingNavigatorMock.swift
    Setting/Test/SettingViewModelTests.swift
    Setting/Test/SettingViewControllerTests.swift
    Setting/Test/SettingMenuCellTests.swift1.7. Login template:To create a login template, run:$ igen template login <Scene_Name> [--window]Options:--window: use UIWindow instead of UINavigationController in the Navigator.Example:Run:$ igen template login LoginOutput:Successfully created files:
    Login/LoginAssembler.swift
    Login/LoginNavigator.swift
    Login/LoginViewModel.swift
    Login/LoginUseCase.swift
    Login/LoginViewController.swift
    Login/LoginDto.swift
    Login/Test/LoginUseCaseMock.swift
    Login/Test/LoginNavigatorMock.swift
    Login/Test/LoginViewModelTests.swift
    Login/Test/LoginViewControllerTests.swift2. Create a mock class for a protocol/function:Copy the protocol/function then run:$ igen mock [-p]Options:-p,--print: print the result.Example:Copy the protocol:protocolProductsNavigatorType{functoProducts()functoProductDetail(product:Product)functoEditProduct(_product:Product)->Driver<EditProductDelegate>}then run:$ igen mockOutput:The result has been copied to the pasteboard.Content in the pasteboard:finalclassProductsNavigatorMock:ProductsNavigatorType{//MARK:- toProductsvartoProductsCalled=falsefunctoProducts(){toProductsCalled=true}//MARK:- toProductDetailvartoProductDetailCalled=falsefunctoProductDetail(product:Product){toProductDetailCalled=true}//MARK:- toEditProductvartoEditProductCalled=falsevartoEditProductReturnValue=Driver<EditProductDelegate>.empty()functoEditProduct(_product:Product)->Driver<EditProductDelegate>{toEditProductCalled=truereturntoEditProductReturnValue}}3. Create unit tests for a view model:Copy the view model then run:$ igen test [-p]Options:-p,--print: print the result.Example:Copy the view model:structLoginViewModel:ViewModel{structInput{letusernameTrigger:Driver<String>letpasswordTrigger:Driver<String>letloginTrigger:Driver<Void>}structOutput{@PropertyvarusernameValidationMessage=""@PropertyvarpasswordValidationMessage=""@PropertyvarisLoginEnabled=true@PropertyvarisLoading=false@Propertyvarerror:Error?}then run:$ igen testOutput:The result has been copied to the pasteboard.Content in the pasteboard:finalclassLoginViewModelTests:XCTestCase{privatevarviewModel:LoginViewModel!privatevarnavigator:LoginNavigatorMock!privatevaruseCase:LoginUseCaseMock!privatevarinput:LoginViewModel.Input!privatevaroutput:LoginViewModel.Output!privatevardisposeBag:DisposeBag!// TriggersprivateletusernameTriggerTrigger=PublishSubject<String>()privateletpasswordTriggerTrigger=PublishSubject<String>()privateletloginTriggerTrigger=PublishSubject<Void>()overridefuncsetUp(){super.setUp()navigator=LoginNavigatorMock()useCase=LoginUseCaseMock()viewModel=LoginViewModel(navigator:navigator,useCase:useCase)input=LoginViewModel.Input(usernameTrigger:usernameTrigger.asDriverOnErrorJustComplete(),passwordTrigger:passwordTrigger.asDriverOnErrorJustComplete(),loginTrigger:loginTrigger.asDriverOnErrorJustComplete())disposeBag=DisposeBag()output=viewModel.transform(input,disposeBag:disposeBag)}functest_usernameTriggerTrigger_(){// arrange// act// assertXCTAssert(true)}functest_passwordTriggerTrigger_(){// arrange// act// assertXCTAssert(true)}functest_loginTriggerTrigger_(){// arrange// act// assertXCTAssert(true)}}4. Create an initialize method for a class/struct:Copy the class/struct then run the command:$ igen init [-p]Options:-p,--print: print the result.Example:Copy the model:structProduct{varid:Intvarname:Stringvarprice:Double}then run:$ igen initOutput:The result has been copied to the pasteboard.Content in the pasteboard:extensionProduct{init(){self.init(id:0,name:"",price:0.0)}}5. Create models from JSON:Copy the json then run the command:$ igen json <Model_Name> [-p]Options:—-return-classes: return classes instead of structs.-p,--print: print the result.Example:Copy the json:{"id":989,"content":"Hello world!","is_read":false,"created_at":"2018-06-29T17:15:36+09:00"}then run:$ igen json NoticeOutput:The result has been copied to the pasteboard.Content in the pasteboard:structNotice{varid=0varcontent=""varisRead=falsevarcreatedAt=Date()}extensionNotice:Then{}extensionNotice:Mappable{init?(map:Map){self.init()}mutatingfuncmapping(map:Map){id<-map["id"]content<-map["content"]isRead<-map["is_read"]createdAt<-(map["created_at"],DateTransform())}}6. File header command:To update files’ headers, run:$ igen header [--file-name] [--project] [--developer] [--created-date] [--copyright-year] [--company] <File_Paths>Options:--file-name: update file name.--project: update project.--developer: update developer.--created-date: update created date.--copyright-year: update copyright year.--company: update company.If you don’t set any options, the tool will update all header information base on its configuration file.Example:Update the company and the developer in AppDelegate’s header.$ igen header AppDelegate.swift --company --developerYou can use wildcard as well:Update all Swift files:$ igen header *.swiftUpdate all Swift files in the Domain folder and its child folders (recursive) :$ igen header Domain/**/*.swift7. Configuration:7.1. Configure the project information:To update the project information, run:$ igen config project [--global]Options:--global: global configuration.7.2. View the configuration:To view the configuration, run:$ igen config [--global]Options:--global: global configuration.7.3. Update a configuration:$ igen config key value [--global] [--unset]Options:--global: global configuration.--unset: delete a configuration.Configure the project id:$ igen config project.id <Project_ID>Use the special value@projectif you want to use the MD5 encoded project name as the project id.$ igen config project.id @projectThe project id will be used in file headers.////  AppDelegate.swift//  MGiGen (d18ea2a2902863a858af4f0e0911ed35)////  Created by Tuan Truong on 3/27/19.//  Copyright © 2019 Sun Asterisk. All rights reserved.//Configure the output path:$ igen config output.path <Path>Example:Set the current working directory as the output path (relative path):$ igen config output.path .Set the desktop as the output path:$ igen config output.path /Users/<Your_Name>/Desktop/You can use a special value@hereto set the current working directory as the output path (absolute path):$ igen config output.path @hereOther special values:@desktop,@downloads,@documents7.4. View the available configurations:To view the available configurations, run:$ igen config keysOutput:Available configuration keys:
    project.name
    project.developer
    project.company
    project.id
    output.path7.5. Delete the configuration file:To delete the configuration file, run:$ igen config delete [--global]Options:--global: global configuration.8. Install Xcode templates:Install Clean Architecture templates for Xcode:$ igen xcode install-templatesUninstall templates:$ igen xcode uninstall-templates9. Other commands:Run:$ igen -hLinks:Clean Architecture