{"id":13465645,"url":"https://github.com/kawoou/Deli","last_synced_at":"2025-03-25T16:32:32.637Z","repository":{"id":51612942,"uuid":"120608299","full_name":"kawoou/Deli","owner":"kawoou","description":"Deli is an easy-to-use Dependency Injection(DI).","archived":false,"fork":false,"pushed_at":"2021-12-29T19:03:12.000Z","size":1180,"stargazers_count":135,"open_issues_count":1,"forks_count":8,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-03-23T09:37:40.144Z","etag":null,"topics":["automatically","command-line","dependency-injection","di","inversion-of-control","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kawoou.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-07T11:47:26.000Z","updated_at":"2023-09-28T09:42:39.000Z","dependencies_parsed_at":"2022-08-21T23:40:29.009Z","dependency_job_id":null,"html_url":"https://github.com/kawoou/Deli","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kawoou%2FDeli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kawoou%2FDeli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kawoou%2FDeli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kawoou%2FDeli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kawoou","download_url":"https://codeload.github.com/kawoou/Deli/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245500407,"owners_count":20625574,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automatically","command-line","dependency-injection","di","inversion-of-control","swift"],"created_at":"2024-07-31T15:00:33.243Z","updated_at":"2025-03-25T16:32:32.314Z","avatar_url":"https://github.com/kawoou.png","language":"Swift","funding_links":[],"categories":["Libs","Dependency Injection [🔝](#readme)","Swift"],"sub_categories":["Dependency Injection"],"readme":"![Deli](https://github.com/kawoou/Deli/raw/screenshot/deli.png)\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"#\"\u003e\u003cimg src=\"https://img.shields.io/badge/Swift-5.1-orange.svg\" alt=\"Swift\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/Carthage/Carthage\"\u003e\u003cimg src=\"https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\"/\u003e\u003c/a\u003e\n\u003ca href=\"http://cocoadocs.org/docsets/Deli\"\u003e\u003cimg src=\"https://img.shields.io/cocoapods/v/Deli.svg?style=flat\" alt=\"Version\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/kawoou/Deli/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/cocoapods/l/Deli.svg?style=flat\" alt=\"License\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://travis-ci.org/kawoou/Deli\"\u003e\u003cimg src=\"https://travis-ci.org/kawoou/Deli.svg?branch=master\" alt=\"CI Status\"/\u003e\u003c/a\u003e\n\u003ca href=\"http://kawoou.kr/Deli\"\u003e\u003cimg src=\"http://kawoou.kr/Deli/badge.svg\" alt=\"Jazzy\"/\u003e\u003c/a\u003e\n\u003ca href=\"http://cocoadocs.org/docsets/Deli\"\u003e\u003cimg src=\"https://img.shields.io/cocoapods/p/Deli.svg?style=flat\" alt=\"Platform\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nDeli is an easy-to-use Dependency Injection Container that creates DI containers with all required registrations and corresponding factories.\n\n\u003e Language Switch: [English](https://github.com/kawoou/Deli/tree/master/README.md), [한국어](https://github.com/kawoou/Deli/tree/master/README_KR.md).\n\n\n\n\n## Table of Contents\n* [Overview](#overview)\n* [Getting Started](#getting-started)\n  - [Build Phases](#build-phases)\n* [Features](#features)\n  - [Component](#1-component)\n  - [Autowired](#2-autowired)\n  - [LazyAutowired](#3-lazyautowired)\n  - [Configuration](#4-configuration)\n  - [Inject](#5-inject)\n  - [Factory](#6-factory)\n  - [ModuleFactory](#7-modulefactory)\n    - [Multi-Container](#71-multi-container)\n    - [Unit Test](#72-unit-test)\n  - [Struct](#8-struct)\n  - [Configuration Property](#9-configuration-property)\n    - [Usage](#91-usage)\n    - [Group Value](#92-group-value)\n    - [Single Value](#93-single-value)\n    - [Qualifier by Property](#94-qualifier-by-property)\n  - [Property Wrapper](#10-propertywrapper)\n    - [Dependency](#101-dependecy)\n    - [PropertyValue](#102-propertyvalue)\n* [Installation](#installation)\n  - [Cocoapods](#cocoapods)\n  - [Carthage](#carthage)\n  - [Command Line](#command-line)\n* [Examples](#examples)\n* [Contributing](#contributing)\n* [Requirements](#requirements)\n* [Attributions](#attributions)\n* [License](#license)\n\n\n\n## Overview\n\nWanna spaghetti? or not.\nAs your project grows, will experience a complex. We can write the wrong code by mistake.\n\nIn [Spring framework](https://github.com/spring-projects/spring-framework) provides automatic registration using some code rules and throws the wrong Dependency Graph before running. I wanted these features to be in Swift.\n\n\n\n\n## Getting Started\n\nSimple setup for the automated configuration files, `deli.yml`.\n\nIf the configuration file does not exist, find the build target for a unique project in the current folders automatically. It works the same even if no `scheme`, `target` and `output` field is specified.\n\n```yaml\ntarget:\n  - MyProject\n\nconfig:\n  MyProject:\n    project: MyProject\n    scheme: MyScheme\n    include:\n      - Include files...\n    exclude:\n      - Exclude files...\n    className: DeilFactory\n    output: Sources/DeliFactory.swift\n    resolve:\n      output: Deli.resolved\n      generate: true\n    dependencies:\n      - path: Resolved files...\n        imports: UIKit\n    accessControl: public\n```\n\nYou’ll have to make your scheme `Shared`. To do this `Manage Schemes` and check the `Shared` areas:\n\n![shared-build-scheme](https://github.com/kawoou/Deli/raw/screenshot/shared-build-scheme.png)\n\nAlternatively, you can specify `target` instead of `scheme`. In this case, Deli will find the Build Target.\n\nThen build with the provided binaries.\n\n```bash\n$ deli build\n```\n\nDependency Graph is configured through source code analysis. It is saved as the file you specified earlier.\n\nFile contents as below:\n\n```swift\n//\n//  DeliFactory.swift\n//  Auto generated code.\n//\n\nimport Deli\n\nfinal class DeliFactory: ModuleFactory {\n    override func load(context: AppContextType) {\n        ...\n    }\n}\n```\n\nAdd the generated file to the project and call it from the app's launch point.\n\n![drag-and-drop](https://github.com/kawoou/Deli/raw/screenshot/drag-and-drop-deli-factory.png)\n\nAppDelegate.swift:\n\n```swift\nimport UIKit\nimport Deli\n\nclass AppDelegate {\n    \n    var window: UIWindow?\n\n    let context = AppContext.load([\n        DeliFactory.self\n    ])\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -\u003e Bool {\n        return true\n    }\n}\n```\n\n\n\n### Build Phases\n\nIntegrate Deli into an Xcode scheme to get warnings and errors displayed in the IDE.\nJust add a new \"Run Script Phase\" with:\n\n```bash\nif which deli \u003e/dev/null; then\n  deli build\nelse\n  echo \"error: Deli not installed, download from https://github.com/kawoou/Deli\"\nfi\n```\n\n![Build Phase](https://github.com/kawoou/Deli/raw/screenshot/xcode-run-script.png)\n\nAlternatively, if you've installed Deli via CocoaPods the script should look like this:\n\n```bash\n\"${PODS_ROOT}/DeliBinary/deli\" build\n```\n\n\n\n## Features\n### 1. Component\nThe class, struct, and protocol can extend the `Component` protocol and will be registered automatically in the DI container.\n\n`Component` can be used as below:\n\n```swift\nprotocol UserService {\n    func login(id: String, password: String) -\u003e User?\n    func logout()\n}\n\nclass UserServiceImpl: UserService, Component {\n    func login(id: String, password: String) -\u003e User? {\n        ...\n    }\n    func logout() {\n        ...\n    }\n\n    init() {}\n}\n```\n\nIf the above code is written, you can use the `UserService` or `UserServiceImpl` type to load the dependency instance.\n\n\n\n### 2. Autowired\n\nThe `Autowired` protocol is registered automatically, same as `Component` protocol. A difference, you can load the required dependencies from DI container.\n\n`Autowired` can be used as below:\n\n```swift\nclass LoginViewModel: Autowired {\n    let userService: UserService\n\n    required init(_ userService: UserService) {\n        self.userService = userService \n    }\n}\n```\n\nEasy right? So let's look at the code below.\n\n```swift\nprotocol Book {\n    var name: String { get }\n    var author: String { get }\n    var category: String { get }\n}\n\nclass Novel: Book {\n    var qualifier: String {\n        return \"Novel\"\n    }\n\n    var name: String {\n        return \"\"\n    }\n    \n    var author: String {\n        return \"\"\n    }\n    \n    var category: String {\n        return \"Novel\"\n    }\n}\n\nclass HarryPotter: Novel, Component {\n    override var name: String {\n        return \"Harry Potter\"\n    }\n    \n    override var author: String {\n        return \"J. K. Rowling\"\n    }\n}\n\nclass TroisiemeHumanite: Novel, Component {\n    override var name: String {\n        return \"Troisième humanité\"\n    }\n    \n    override var author: String {\n        return \"Bernard Werber\"\n    }\n}\n```\n\nThis code arranged the books through inheritance. You can get all of `Book` instances like below:\n\n```swift\nclass LibraryService: Autowired {\n    let books: [Book]\n\n    required init(_ books: [Book]) {\n        self.books = books\n    }\n}\n```\n\nFurthermore, What should do to get the books with the \"Novel\" qualifier?\nIn Deli, can be constructor injection in the below:\n\n```swift\nclass LibraryService: Autowired {\n    let books: [Book]\n\n    required init(Novel books: [Book]) {\n        self.books = books\n    }\n}\n```\n\n\n\n### 3. LazyAutowired\n\nIf we can remove whole Circular Dependency cases, the world will be better than before, but it cannot be ruled completely.\nA simple way to solve this problem is to initialize one of the dependency lazily.\n\nLet's try `LazyAutowired` protocol:\n\n```swift\nclass UserService: Autowired {\n    let messageService: MessageService\n\n    required init(_ messageService: MessageService) {\n        self.messageService = messageService\n    }\n}\nclass FriendService: Autowired {\n    let userService: UserService\n\n    required init(_ userService: UserService) {\n        self.userService = userService\n    }\n}\nclass MessageService: Autowired {\n    let friendService: FriendService\n\n    required init(_ friendService: FriendService) {\n        self.friendService = friendService\n    }\n}\n```\n\nIf you try to inject a MessageService, Circular Dependency will occurred.\n\n```bash\n$ deli validate\n\nError: The circular dependency exists. (MessageService -\u003e FriendService -\u003e UserService -\u003e MessageService)\n```\n\nWhat if UserService extends `LazyAutowired`?\n\n```swift\nclass UserService: LazyAutowired {\n    let messageService: MessageService!\n\n    func inject(_ messageService: MessageService) {\n        self.messageService = messageService\n    }\n\n    required init() {}\n}\n```\n\nThe cycle was broken and the issue was resolved!\nAfter MessageService instance successfully created, dependencies can be injected via `inject()` that UserService needed.\n\nIn addition, LazyAutowired can be specified qualifier like Autowired.\nBelow code injects a UserService instance with the \"facebook\" qualifier specified:\n\n```swift\nclass FacebookViewModel: LazyAutowired {\n    let userService: UserService!\n\n    func inject(facebook userService: UserService) {\n        self.userService = userService\n    }\n\n    required init() {}\n}\n```\n\n\n### 4. Configuration\n\nThe `Configuration` protocol makes the user can register `Resolver` directly.\n\nLet's look at the code:\n\n```swift\nclass UserConfiguration: Configuration {\n    let networkManager = Config(NetworkManager.self, ConfigurationManager.self) { configurationManager in\n        let privateKey = \"1234QwEr!@#$\"\n        return configurationManager.make(privateKey: privateKey)\n    }\n\n    init() {}\n}\n```\nYou can see privateKey is passed to ConfigurationManager on NetworkManager creation.\n\nThis NetworkManager instance is registered in DI container, and it will be managed as singleton.\n(However, instance behavior can be changed by updating scope argument.)\n\n\n\n### 5. Inject\n\nAs written, `Autowired` is registered in DI container. But you may want to use without registration. That's an `Inject`.\n\n```swift\nclass LoginView: Inject {\n    let viewModel = Inject(LoginViewModel.self)\n\n    init() {}\n}\n\nclass NovelBookView: Inject {\n    let novels: [Book] = Inject([Book].self, qualifier: \"Novel\")\n\n    init() {}\n}\n```\n\n\n\n### 6. Factory\n\nIn the front-end, often dynamically generating a model using the user's data. Let's take an example.\n\nYou must implement a friend list. When you select a cell from friends list, you need to present modal view of friend's information.\nIn this case, The friend data must be passed in the `Info Modal`.\n\nThis happens very often, `Factory` will help them.\n\nLet's try `AutowiredFactory` protocol:\n\n```swift\nclass FriendPayload: Payload {\n    let userID: String\n    let cachedName: String\n    \n    required init(with argument: (userID: String, cachedName: String)) {\n        userID = argument.userID\n        cachedName = argument.cachedName\n    }\n}\n\nclass FriendInfoViewModel: AutowiredFactory {\n    let accountService: AccountService\n    \n    let userID: String\n    var name: String\n    \n    required init(_ accountService: AccountService, payload: FriendPayload) {\n        self.accountService = accountService\n        self.userID = payload.userID\n        self.name = payload.cachedName\n    }\n}\n```\n\nTo pass a user-argument, you must implement a `Payload` protocol.\n(Naturally, factories work by prototype scope)\n\nImplemented `FriendInfoViewModel` can be used as below:\n\n```swift\nclass FriendListViewModel: Autowired {\n    let friendService: FriendService\n    \n    func generateInfo(by id: String) -\u003e FriendInfoViewModel? {\n        guard let friend = friendService.getFriend(by: id) else { return nil }\n        \n        return Inject(\n            FriendInfoViewModel.self,\n            with: (\n                userID: friend.id,\n                cachedName: friend.name\n            )\n        )\n    }\n    \n    required init(_ friendService: FriendService) {\n        self.friendService = friendService\n    }\n}\n```\n\nNext `LazyAutowiredFactory` protocol:\n\n```swift\nclass FriendInfoViewModel: LazyAutowiredFactory {\n    var accountService: AccountService!\n    \n    func inject(facebook accountService: AccountService) {\n        self.accountService = accountService\n    }\n    \n    required init(payload: TestPayload) {\n        ...\n    }\n}\n```\n\nThe difference between an AutowiredFactory and a LazyAutowiredFactory is that it is lazy injected with the relationship between Autowired and LazyAutowired.\nHowever, payload injects by the constructor because passed by the user.\n\n\n\n### 7. ModuleFactory\n\nWhen injecting the dependency, required blueprint.\nAs above, This blueprint is generated at `build`(ex. DeliFactory).\nWhen calling `AppContext#load()`, load container of generated class that inherited `ModuleFactory`.\n\nDeli supports Multi-Container.\nCan be used `ModuleFactory` as below.\n\n\n\n#### 7.1. Multi-Container\n\nWhen calling `AppContext#load()`, also load the `ModuleFactory` in the module.\n\nCan specify `LoadPriority` in this situation. This is the order for selecting the container to be used in dependency injection.\n\nPriority are `normal(500)` defaultly. Container's order for selecting as below:\n\n1. High priority first.\n\n```swift\nAppContext.shared.load([\n    OtherModule.DeliFactory.self,\n    DeliFactory.self\n])\n```\n\n2. If priority is same, In the loaded order.\n\n```swift\nAppContext.shared\n    .load(DeliFactory())\n    .load(OtherModule.DeliFactory(), priority: .high)\n```\n\n\n\n#### 7.2. Unit Test\n\nPriority loading that same as [7.1](#71-multi-container) used be Unit Test, too.\n\n``` swift\nimport Quick\nimport Nimble\n\n@testable import MyApp\n\nclass UserTests: QuickSpec {\n    override func spec() {\n        super.spec()\n\n        let testModule: ModuleFactory!\n        testModule.register(UserService.self) { MockUserService() }\n\n        let appContext = AppContext.shared\n        beforeEach {\n            appContext.load(testModule, priority: .high)\n        }\n        afterEach {\n            appContext.unload(testModule)\n        }\n        \n        ...\n    }\n}\n```\n\nAn example of a test code is `Deli.xcodeproj`.\n\n\n\n### 8. Struct\n\nSupport for Struct has been added since version `0.7.0`.\n\nThe basic behavior is the same as Class, but one difference is that cannot use `weak` Scope.\n\nBelow is an example of [Moya](https://github.com/Moya/Moya)'s plugin implementation.\n\n```swift\nstruct AuthPlugin: PluginType, LazyAutowired {\n\n    var scope: Scope = .weak\n\n    private let authService: AuthService!\n\n    func prepare(_ request: URLRequest, target: TargetType) -\u003e URLRequest {\n        var request = request\n\n        if let authToken = authService.authToken {\n            request.addValue(authToken.accessToken, forHTTPHeaderField: \"Authorization\")\n            request.addValue(authToken.refreshToken, forHTTPHeaderField: \"Refresh-Token\")\n        }\n\n        return request\n    }\n\n    mutating func inject(_ authService: AuthService) {\n        self.authService = authService\n    }\n\n    init() {}\n}\n```\n\n\n\n### 9. Configuration Property\n\nIt's often profit to use different configuration values depending on the running environment.\nFor example, you can specific that save the file log at development build and not save the file log at the Release build.\n\n**application-dev.yml:**\n```yaml\nlogger:\n    storage: file\n\nserver:\n    url: https://dev.example.com/api\n    isDebug: false\n```\n\n**application-prod.yml:**\n```yaml\nlogger:\n    storage: default\n\nserver:\n    url: https://www.example.com/api\n    isDebug: true\n```\n\n\n\n#### 9.1. Usage\n\nTwo ways solution to use the Configuration Property created above.\n\n 1. Change `deli.yml`.\n 2. Modify the build script\n\nChange the configuration file as below:\n\n```yaml\ntarget:\n- MyApp\n\nconfig:\n  MyApp:\n    - project: MyApp\n    - properties:\n      - Configurations/Common/*.yml\n      - Configurations/application-dev.yml\n```\n\nBuild script can do this:\n\n```bash\ndeli build \\\n  --property \"Configurations/Common/*.yml\" \\\n  --property \"Configurations/application-dev.yml\"\n```\n\nIf the same configuration information, it's overwritten with the last specified information.\n\n\n\n#### 9.2. Group Value\n\nYou can use `ConfigProperty` to safe retrieve the specified value in the configuration file.\n\n```swift\nstruct ServerConfig: ConfigProperty {\n    let target: String = \"server\"\n\n    let url: String\n    let isDebug: Bool\n}\n```\n\nWhen implementing the model as above, `ServerConfig` is registered in IoC Container.\n\nOne thing to keep in mind when defining the model, need to set the `target` value. This property represents the path to retrieve in the configuration file using JSONPath style.\n\nIf you do not have the required configuration values at build time, will occurred a compile error.\n\n```swift\nfinal class NetworkManager: Autowired {\n    let info: ServerConfig\n\n    required init(_ config: ServerConfig) {\n        info = config\n    }\n}\n```\n\n\n\n#### 9.3. Single Value\n\nWhen get a bundle value as above, implement the `ConfigProperty` protocol. So how to get a single value? You can use the `InjectProperty`.\n\n```swift\nfinal class NetworkManager: Inject {\n    let serverUrl = InjectProperty(\"server.url\")\n}\n```\n\n`InjectProperty` is similar to ` ConfigProperty`. It checks the configuration value at build time and inject data as String type.\n\nIf you want to retrieve configuration value optionally without validation, this is not a proper way.\n\nIn this case, recommend using the `AppContext#getProperty()` method.\n\n```swift\nfinal class NetworkManager {\n    let serverUrl = AppContext.getProperty(\"server.url\", type: String.self) ?? \"https://wtf.example.com\"\n}\n```\n\n\n\n#### 9.4. Qualifier by Property\n\nTo enhance usability of configuration property, Deli provides a way of injection using `qualifier` as configuration value.\n\nThere are two ways to use it. let's look first that constructor injection like `Autowired`.\n\nAs mentioned in the [Autowired](#2-autowired) paragraph, you can not use `.` for parts that specify `qualifier`. Unfortunately, swift do not has an annotation-like features. So I implemented to use `comment` as an alternative.\n\nHow it works:\n\n```swift\nfinal class UserService: Autowired {\n    required init(_/*logger.storage*/ logger: Logger) {\n    }\n}\n```\n\nWhen using the `Inject` method:\n\n```swift\nfinal class UserService: Inject {\n    func getLogger() -\u003e Logger {\n        return Inject(Logger.self, qualifierBy: \"logger.storage\")\n    }\n}\n```\n\n\n\n### 10. PropertyWrapper\n\nFor easier use, supports the [@propertyWrapper](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md) added in Swift 5.1.\n\nThere are two main features to be supported: dependency injection and [Configuration Property](#9-configuration-property).\n\n\n\n#### 10.1. Dependency\n\nThere are `@Dependency` and `@DependencyArray` for injection of dependencies.\n\n```swift\nclass Library {\n    @Dependency(qualifier \"logger.storage\")\n    var logger: Logger\n\n    @DependencyArray(qualifier: \"novel\")\n    var novels: [Book]\n}\n```\n\n\n\n#### 10.2. PropertyValue\n\n`@PropertyValue` is the same as [Configuration Property](#9-configuration-property) and the usage as below:\n\n```swift\nfinal class NetworkManager: Inject {\n    @PropertyValue(\"server.url\")\n    let serverUrl: String\n}\n```\n\n\n\n## Installation\n\n### [Cocoapods](https://cocoapods.org/):\n\nSimply add the following line to your Podfile:\n\n```ruby\npod 'Deli', '~\u003e 0.8.1'\n```\n\n\n\n### [Carthage](https://github.com/Carthage/Carthage):\n\n```\ngithub \"kawoou/Deli\"\n```\n\n\n\n### Command Line\n\n```\n$ deli help\nAvailable commands:\n\n   build      Build the Dependency Graph.\n   generate   Generate the Dependency Graph.\n   help       Display general or command-specific help\n   upgrade    Upgrade outdated.\n   validate   Validate the Dependency Graph.\n   version    Display the current version of Deli\n```\n\n\n\n## Examples\n\n * [DeliTodo](https://github.com/kawoou/DeliTodo): Todo application for iOS using Deli.\n * [GitHubSearch](https://github.com/kawoou/Deli/tree/master/Examples/GitHubSearch): GitHub Search example using Deli.\n * [Survey](https://github.com/kawoou/Deli/tree/master/Examples/Survey): Survey example using Deli.\n * [RobotFactory](https://github.com/kawoou/Deli/tree/master/Examples/RobotFactory): RobotFactory example using Deli.\n\n\n\n## Contributing\n\nAny discussions and pull requests are welcomed.\n\nIf you want to contribute, [submit a pull request](https://github.com/kawoou/Deli/compare).\n\n\n\n## Requirements\n\n* Swift 3.1+\n\n\n\n## Attributions\n\nThis project is powered by\n\n * [SourceKitten](https://github.com/jpsim/SourceKitten)\n   - MIT License\n   - Created by [JP Simard](https://github.com/jpsim)\n * [Yams](https://github.com/jpsim/Yams)\n   - MIT License\n   - Created by [JP Simard](https://github.com/jpsim)\n * [Regex](https://github.com/crossroadlabs/Regex)\n   - Apache License 2.0\n   - Created by [Crossroad Labs](https://github.com/crossroadlabs)\n * [Xcproj](https://github.com/xcodeswift/xcproj)\n   - MIT License\n   - Created by [xcode.swift](https://github.com/xcodeswift)\n * [Commandant](https://github.com/Carthage/Commandant)\n   - MIT License\n   - Created by [Carthage](https://github.com/Carthage)\n * [Quick](https://github.com/Quick/Quick)\n   - Apache License 2.0\n   - Created by [Quick Team](https://github.com/Quick)\n * [Nimble](https://github.com/Quick/Nimble)\n   - Apache License 2.0\n   - Created by [Quick Team](https://github.com/Quick)\n\n\n\n## License\n\nDeli is under MIT license. See the [LICENSE](https://github.com/kawoou/Deli/blob/master/LICENSE) file for more info.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkawoou%2FDeli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkawoou%2FDeli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkawoou%2FDeli/lists"}