├── .gitignore ├── .rubocop.yml ├── .ruby-version ├── .travis.yml ├── Cartfile ├── ExampleProject └── CodeGenerationExample │ ├── CodeGenerationExample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── CodeGenerationExample.xcscheme │ └── xcuserdata │ │ └── admin.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist │ ├── CodeGenerationExample │ ├── AnimalType.swift │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Cat.swift │ ├── CodeGenerationDefinition.csv │ ├── Dog.swift │ ├── Horse.swift │ ├── Info.plist │ ├── InjectablePerson.swift │ ├── PersonType.swift │ ├── PetOwner.swift │ ├── Turle.swift │ └── ViewController.swift │ ├── CodeGenerationExampleTests │ ├── CodeGenerationExampleTests.swift │ └── Info.plist │ ├── Podfile │ └── Podfile.lock ├── ExampleScript ├── example.csv ├── example.yml └── generateCode.sh ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Support ├── README.erb └── updateReadme.sh ├── Swinject-CodeGen.podspec ├── Tests ├── Examples │ ├── Bug_51_A.csv │ ├── Bug_51_B.csv │ ├── Bug_58_A.csv │ ├── Bug_58_B.csv │ ├── ExampleA.csv │ ├── ExampleB.csv │ ├── ExampleC.csv │ ├── ExampleD.csv │ ├── ExampleE.csv │ ├── ExampleF.csv │ ├── bug_50_A.csv │ └── bug_50_B.csv ├── ExpectedCode │ ├── ExampleA.swift │ ├── ExampleB.swift │ ├── ExampleC.swift │ ├── ExampleD.swift │ ├── ExampleE.swift │ └── ExampleF.swift └── test.rb ├── bin └── swinject_codegen ├── bootstrap.sh ├── erb ├── container.erb ├── csv.erb └── migration.erb ├── fastlane ├── Fastfile └── README.md └── source ├── csv_parser.rb ├── yml_parser.rb └── yml_serializer.rb /.gitignore: -------------------------------------------------------------------------------- 1 | ## Mac 2 | .DS_Store 3 | 4 | ## Bundler bin files (binstubs) 5 | .bundle 6 | bin/xcodeproj 7 | bin/sandbox-pod 8 | bin/pod 9 | bin/fuzzy_match 10 | bin/bundler 11 | 12 | # Generated Code, does not need to checked in 13 | ExampleScript/containerExtension.swift.migration.sh 14 | ExampleScript/containerExtension.swift 15 | ExampleScript/containerExtension2.swift 16 | ExampleScript/containerExtension2.swift.migration.sh 17 | ExampleScript/containerExtension3.swift 18 | ExampleScript/containerExtension3.swift.migration.sh 19 | ExampleScript/containerExtension4.swift 20 | ExampleScript/containerExtension4.swift.migration.sh 21 | ExampleScript/example.csv.yml 22 | ExampleScript/example.yml.csv 23 | ExampleProject/CodeGenerationExample/CodeGenerationExample.xcworkspace 24 | ExampleProject/CodeGenerationExample/CodeGenerationExample/ExampleContainer.swift 25 | ExampleProject/CodeGenerationExample/Pods 26 | ExampleProject/CodeGenerationExample/test_output 27 | test_output 28 | ExampleScript/csvMigration.sh 29 | ExampleScript/ymlMigration.sh 30 | /ExampleProject/CodeGenerationExample/CodeGenerationExample.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate 31 | /fastlane/report.xml 32 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 2.0 3 | Exclude: 4 | - '*.podspec' 5 | - 'ExampleProject/**/**' 6 | 7 | Style/StringLiterals: 8 | EnforcedStyle: double_quotes 9 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.3 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode8.1 3 | branches: 4 | only: 5 | - master 6 | install: 7 | - bundle install 8 | - bundle exec pod repo update 9 | - bundle exec pod install --project-directory=ExampleProject/CodeGenerationExample 10 | script: 11 | - ruby -X Tests test.rb 12 | - fastlane scan --scheme CodeGenerationExample --workspace ExampleProject/CodeGenerationExample/CodeGenerationExample.xcworkspace 13 | rvm: 14 | - 2.0 15 | - 2.3.3 16 | notifications: 17 | email: 18 | on_success: never 19 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "Swinject/Swinject" ~> 2.0 2 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 33CAAEB6C179A144128BF84F /* Pods_CodeGenerationExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD73605662ECA84FC3EAF4D4 /* Pods_CodeGenerationExample.framework */; }; 11 | 840B7FE11CDBA373008CA97E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840B7FE01CDBA373008CA97E /* AppDelegate.swift */; }; 12 | 840B7FE31CDBA373008CA97E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840B7FE21CDBA373008CA97E /* ViewController.swift */; }; 13 | 840B7FE61CDBA373008CA97E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 840B7FE41CDBA373008CA97E /* Main.storyboard */; }; 14 | 840B7FE81CDBA373008CA97E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 840B7FE71CDBA373008CA97E /* Assets.xcassets */; }; 15 | 840B7FEB1CDBA373008CA97E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 840B7FE91CDBA373008CA97E /* LaunchScreen.storyboard */; }; 16 | 8431D8921CDBA8B600BB0679 /* AnimalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D8911CDBA8B600BB0679 /* AnimalType.swift */; }; 17 | 8431D8951CDBA91A00BB0679 /* Cat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D8941CDBA91A00BB0679 /* Cat.swift */; }; 18 | 8431D8971CDBA92700BB0679 /* PersonType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D8961CDBA92700BB0679 /* PersonType.swift */; }; 19 | 8431D8991CDBA93600BB0679 /* PetOwner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D8981CDBA93600BB0679 /* PetOwner.swift */; }; 20 | 8431D89B1CDBA94300BB0679 /* Dog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D89A1CDBA94300BB0679 /* Dog.swift */; }; 21 | 8431D89D1CDBA95300BB0679 /* InjectablePerson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D89C1CDBA95300BB0679 /* InjectablePerson.swift */; }; 22 | 8431D89F1CDBA98800BB0679 /* Horse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D89E1CDBA98800BB0679 /* Horse.swift */; }; 23 | 8431D8A11CDBAAFE00BB0679 /* Turle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D8A01CDBAAFE00BB0679 /* Turle.swift */; }; 24 | 8431D8A31CDBAB4800BB0679 /* CodeGenerationDefinition.csv in Resources */ = {isa = PBXBuildFile; fileRef = 8431D8A21CDBAB4800BB0679 /* CodeGenerationDefinition.csv */; }; 25 | 8431D8A61CDBAC7100BB0679 /* ExampleContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D8A51CDBAC7100BB0679 /* ExampleContainer.swift */; }; 26 | 8431D8AE1CDBB47E00BB0679 /* CodeGenerationExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8431D8AD1CDBB47E00BB0679 /* CodeGenerationExampleTests.swift */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 8431D8B01CDBB47E00BB0679 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 840B7FD51CDBA373008CA97E /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 840B7FDC1CDBA373008CA97E; 35 | remoteInfo = CodeGenerationExample; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 278CB160078A5F46226D1DF1 /* Pods-CodeGenerationExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CodeGenerationExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CodeGenerationExample/Pods-CodeGenerationExample.debug.xcconfig"; sourceTree = ""; }; 41 | 840B7FDD1CDBA373008CA97E /* CodeGenerationExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CodeGenerationExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 840B7FE01CDBA373008CA97E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 43 | 840B7FE21CDBA373008CA97E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 44 | 840B7FE51CDBA373008CA97E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 45 | 840B7FE71CDBA373008CA97E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 46 | 840B7FEA1CDBA373008CA97E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 47 | 840B7FEC1CDBA373008CA97E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 8431D8911CDBA8B600BB0679 /* AnimalType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimalType.swift; sourceTree = ""; }; 49 | 8431D8941CDBA91A00BB0679 /* Cat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cat.swift; sourceTree = ""; }; 50 | 8431D8961CDBA92700BB0679 /* PersonType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonType.swift; sourceTree = ""; }; 51 | 8431D8981CDBA93600BB0679 /* PetOwner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PetOwner.swift; sourceTree = ""; }; 52 | 8431D89A1CDBA94300BB0679 /* Dog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dog.swift; sourceTree = ""; }; 53 | 8431D89C1CDBA95300BB0679 /* InjectablePerson.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InjectablePerson.swift; sourceTree = ""; }; 54 | 8431D89E1CDBA98800BB0679 /* Horse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Horse.swift; sourceTree = ""; }; 55 | 8431D8A01CDBAAFE00BB0679 /* Turle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Turle.swift; sourceTree = ""; }; 56 | 8431D8A21CDBAB4800BB0679 /* CodeGenerationDefinition.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CodeGenerationDefinition.csv; sourceTree = ""; }; 57 | 8431D8A51CDBAC7100BB0679 /* ExampleContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleContainer.swift; sourceTree = ""; }; 58 | 8431D8AB1CDBB47E00BB0679 /* CodeGenerationExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CodeGenerationExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 8431D8AD1CDBB47E00BB0679 /* CodeGenerationExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeGenerationExampleTests.swift; sourceTree = ""; }; 60 | 8431D8AF1CDBB47E00BB0679 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | B53C73B83EE93F03F8DBFE12 /* Pods-CodeGenerationExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CodeGenerationExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-CodeGenerationExample/Pods-CodeGenerationExample.release.xcconfig"; sourceTree = ""; }; 62 | FD73605662ECA84FC3EAF4D4 /* Pods_CodeGenerationExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CodeGenerationExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 840B7FDA1CDBA373008CA97E /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | 33CAAEB6C179A144128BF84F /* Pods_CodeGenerationExample.framework in Frameworks */, 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | 8431D8A81CDBB47E00BB0679 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 325EACE6E3F7363A4A78F5E4 /* Frameworks */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | FD73605662ECA84FC3EAF4D4 /* Pods_CodeGenerationExample.framework */, 88 | ); 89 | name = Frameworks; 90 | sourceTree = ""; 91 | }; 92 | 840B7FD41CDBA373008CA97E = { 93 | isa = PBXGroup; 94 | children = ( 95 | 840B7FDF1CDBA373008CA97E /* CodeGenerationExample */, 96 | 8431D8AC1CDBB47E00BB0679 /* CodeGenerationExampleTests */, 97 | 840B7FDE1CDBA373008CA97E /* Products */, 98 | CA9544A51692E2D855FCF3C4 /* Pods */, 99 | 325EACE6E3F7363A4A78F5E4 /* Frameworks */, 100 | ); 101 | sourceTree = ""; 102 | }; 103 | 840B7FDE1CDBA373008CA97E /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 840B7FDD1CDBA373008CA97E /* CodeGenerationExample.app */, 107 | 8431D8AB1CDBB47E00BB0679 /* CodeGenerationExampleTests.xctest */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | 840B7FDF1CDBA373008CA97E /* CodeGenerationExample */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 8431D8A51CDBAC7100BB0679 /* ExampleContainer.swift */, 116 | 8431D8931CDBA90800BB0679 /* Classes */, 117 | 840B7FE01CDBA373008CA97E /* AppDelegate.swift */, 118 | 840B7FE21CDBA373008CA97E /* ViewController.swift */, 119 | 840B7FE41CDBA373008CA97E /* Main.storyboard */, 120 | 840B7FE71CDBA373008CA97E /* Assets.xcassets */, 121 | 840B7FE91CDBA373008CA97E /* LaunchScreen.storyboard */, 122 | 840B7FEC1CDBA373008CA97E /* Info.plist */, 123 | 8431D8A21CDBAB4800BB0679 /* CodeGenerationDefinition.csv */, 124 | ); 125 | path = CodeGenerationExample; 126 | sourceTree = ""; 127 | }; 128 | 8431D8931CDBA90800BB0679 /* Classes */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 8431D8911CDBA8B600BB0679 /* AnimalType.swift */, 132 | 8431D8941CDBA91A00BB0679 /* Cat.swift */, 133 | 8431D8961CDBA92700BB0679 /* PersonType.swift */, 134 | 8431D8981CDBA93600BB0679 /* PetOwner.swift */, 135 | 8431D89A1CDBA94300BB0679 /* Dog.swift */, 136 | 8431D89C1CDBA95300BB0679 /* InjectablePerson.swift */, 137 | 8431D89E1CDBA98800BB0679 /* Horse.swift */, 138 | 8431D8A01CDBAAFE00BB0679 /* Turle.swift */, 139 | ); 140 | name = Classes; 141 | sourceTree = ""; 142 | }; 143 | 8431D8AC1CDBB47E00BB0679 /* CodeGenerationExampleTests */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 8431D8AD1CDBB47E00BB0679 /* CodeGenerationExampleTests.swift */, 147 | 8431D8AF1CDBB47E00BB0679 /* Info.plist */, 148 | ); 149 | path = CodeGenerationExampleTests; 150 | sourceTree = ""; 151 | }; 152 | CA9544A51692E2D855FCF3C4 /* Pods */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 278CB160078A5F46226D1DF1 /* Pods-CodeGenerationExample.debug.xcconfig */, 156 | B53C73B83EE93F03F8DBFE12 /* Pods-CodeGenerationExample.release.xcconfig */, 157 | ); 158 | name = Pods; 159 | sourceTree = ""; 160 | }; 161 | /* End PBXGroup section */ 162 | 163 | /* Begin PBXNativeTarget section */ 164 | 840B7FDC1CDBA373008CA97E /* CodeGenerationExample */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 840B7FEF1CDBA373008CA97E /* Build configuration list for PBXNativeTarget "CodeGenerationExample" */; 167 | buildPhases = ( 168 | 225D6A5931B94CC443608E88 /* [CP] Check Pods Manifest.lock */, 169 | 8431D8A41CDBAB5F00BB0679 /* Swinject Codegeneration */, 170 | 840B7FD91CDBA373008CA97E /* Sources */, 171 | 840B7FDA1CDBA373008CA97E /* Frameworks */, 172 | 840B7FDB1CDBA373008CA97E /* Resources */, 173 | 33554BBDD15CA7B6D2A92324 /* [CP] Embed Pods Frameworks */, 174 | 8C9F43EDFD8315E965D0C7D6 /* [CP] Copy Pods Resources */, 175 | ); 176 | buildRules = ( 177 | ); 178 | dependencies = ( 179 | ); 180 | name = CodeGenerationExample; 181 | productName = CodeGenerationExample; 182 | productReference = 840B7FDD1CDBA373008CA97E /* CodeGenerationExample.app */; 183 | productType = "com.apple.product-type.application"; 184 | }; 185 | 8431D8AA1CDBB47E00BB0679 /* CodeGenerationExampleTests */ = { 186 | isa = PBXNativeTarget; 187 | buildConfigurationList = 8431D8B41CDBB47E00BB0679 /* Build configuration list for PBXNativeTarget "CodeGenerationExampleTests" */; 188 | buildPhases = ( 189 | 8431D8A71CDBB47E00BB0679 /* Sources */, 190 | 8431D8A81CDBB47E00BB0679 /* Frameworks */, 191 | 8431D8A91CDBB47E00BB0679 /* Resources */, 192 | ); 193 | buildRules = ( 194 | ); 195 | dependencies = ( 196 | 8431D8B11CDBB47E00BB0679 /* PBXTargetDependency */, 197 | ); 198 | name = CodeGenerationExampleTests; 199 | productName = CodeGenerationExampleTests; 200 | productReference = 8431D8AB1CDBB47E00BB0679 /* CodeGenerationExampleTests.xctest */; 201 | productType = "com.apple.product-type.bundle.unit-test"; 202 | }; 203 | /* End PBXNativeTarget section */ 204 | 205 | /* Begin PBXProject section */ 206 | 840B7FD51CDBA373008CA97E /* Project object */ = { 207 | isa = PBXProject; 208 | attributes = { 209 | LastSwiftUpdateCheck = 0730; 210 | LastUpgradeCheck = 0810; 211 | ORGANIZATIONNAME = swinject; 212 | TargetAttributes = { 213 | 840B7FDC1CDBA373008CA97E = { 214 | CreatedOnToolsVersion = 7.3; 215 | LastSwiftMigration = 0800; 216 | ProvisioningStyle = Manual; 217 | }; 218 | 8431D8AA1CDBB47E00BB0679 = { 219 | CreatedOnToolsVersion = 7.3; 220 | LastSwiftMigration = 0800; 221 | TestTargetID = 840B7FDC1CDBA373008CA97E; 222 | }; 223 | }; 224 | }; 225 | buildConfigurationList = 840B7FD81CDBA373008CA97E /* Build configuration list for PBXProject "CodeGenerationExample" */; 226 | compatibilityVersion = "Xcode 3.2"; 227 | developmentRegion = English; 228 | hasScannedForEncodings = 0; 229 | knownRegions = ( 230 | en, 231 | Base, 232 | ); 233 | mainGroup = 840B7FD41CDBA373008CA97E; 234 | productRefGroup = 840B7FDE1CDBA373008CA97E /* Products */; 235 | projectDirPath = ""; 236 | projectRoot = ""; 237 | targets = ( 238 | 840B7FDC1CDBA373008CA97E /* CodeGenerationExample */, 239 | 8431D8AA1CDBB47E00BB0679 /* CodeGenerationExampleTests */, 240 | ); 241 | }; 242 | /* End PBXProject section */ 243 | 244 | /* Begin PBXResourcesBuildPhase section */ 245 | 840B7FDB1CDBA373008CA97E /* Resources */ = { 246 | isa = PBXResourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | 840B7FEB1CDBA373008CA97E /* LaunchScreen.storyboard in Resources */, 250 | 840B7FE81CDBA373008CA97E /* Assets.xcassets in Resources */, 251 | 8431D8A31CDBAB4800BB0679 /* CodeGenerationDefinition.csv in Resources */, 252 | 840B7FE61CDBA373008CA97E /* Main.storyboard in Resources */, 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | }; 256 | 8431D8A91CDBB47E00BB0679 /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | ); 261 | runOnlyForDeploymentPostprocessing = 0; 262 | }; 263 | /* End PBXResourcesBuildPhase section */ 264 | 265 | /* Begin PBXShellScriptBuildPhase section */ 266 | 225D6A5931B94CC443608E88 /* [CP] Check Pods Manifest.lock */ = { 267 | isa = PBXShellScriptBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | inputPaths = ( 272 | ); 273 | name = "[CP] Check Pods Manifest.lock"; 274 | outputPaths = ( 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | shellPath = /bin/sh; 278 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 279 | showEnvVarsInLog = 0; 280 | }; 281 | 33554BBDD15CA7B6D2A92324 /* [CP] Embed Pods Frameworks */ = { 282 | isa = PBXShellScriptBuildPhase; 283 | buildActionMask = 2147483647; 284 | files = ( 285 | ); 286 | inputPaths = ( 287 | ); 288 | name = "[CP] Embed Pods Frameworks"; 289 | outputPaths = ( 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | shellPath = /bin/sh; 293 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CodeGenerationExample/Pods-CodeGenerationExample-frameworks.sh\"\n"; 294 | showEnvVarsInLog = 0; 295 | }; 296 | 8431D8A41CDBAB5F00BB0679 /* Swinject Codegeneration */ = { 297 | isa = PBXShellScriptBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | ); 301 | inputPaths = ( 302 | ); 303 | name = "Swinject Codegeneration"; 304 | outputPaths = ( 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | shellPath = /bin/sh; 308 | shellScript = "# Uncomment this for usage with cocoapods\n#$PODS_ROOT/Swinject-CodeGen/swinject_codegen -i \"${SRCROOT}/CodeGenerationExample/CodeGenerationDefinition.csv\" -o \"${SRCROOT}/CodeGenerationExample/ExampleContainer.swift\"\n\n# Use local bin\n../../bin/swinject_codegen -i \"${SRCROOT}/CodeGenerationExample/CodeGenerationDefinition.csv\" -o \"${SRCROOT}/CodeGenerationExample/ExampleContainer.swift\""; 309 | }; 310 | 8C9F43EDFD8315E965D0C7D6 /* [CP] Copy Pods Resources */ = { 311 | isa = PBXShellScriptBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | ); 315 | inputPaths = ( 316 | ); 317 | name = "[CP] Copy Pods Resources"; 318 | outputPaths = ( 319 | ); 320 | runOnlyForDeploymentPostprocessing = 0; 321 | shellPath = /bin/sh; 322 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CodeGenerationExample/Pods-CodeGenerationExample-resources.sh\"\n"; 323 | showEnvVarsInLog = 0; 324 | }; 325 | /* End PBXShellScriptBuildPhase section */ 326 | 327 | /* Begin PBXSourcesBuildPhase section */ 328 | 840B7FD91CDBA373008CA97E /* Sources */ = { 329 | isa = PBXSourcesBuildPhase; 330 | buildActionMask = 2147483647; 331 | files = ( 332 | 8431D8951CDBA91A00BB0679 /* Cat.swift in Sources */, 333 | 8431D89D1CDBA95300BB0679 /* InjectablePerson.swift in Sources */, 334 | 8431D8A61CDBAC7100BB0679 /* ExampleContainer.swift in Sources */, 335 | 8431D89B1CDBA94300BB0679 /* Dog.swift in Sources */, 336 | 840B7FE31CDBA373008CA97E /* ViewController.swift in Sources */, 337 | 8431D8A11CDBAAFE00BB0679 /* Turle.swift in Sources */, 338 | 8431D8971CDBA92700BB0679 /* PersonType.swift in Sources */, 339 | 8431D8991CDBA93600BB0679 /* PetOwner.swift in Sources */, 340 | 8431D89F1CDBA98800BB0679 /* Horse.swift in Sources */, 341 | 840B7FE11CDBA373008CA97E /* AppDelegate.swift in Sources */, 342 | 8431D8921CDBA8B600BB0679 /* AnimalType.swift in Sources */, 343 | ); 344 | runOnlyForDeploymentPostprocessing = 0; 345 | }; 346 | 8431D8A71CDBB47E00BB0679 /* Sources */ = { 347 | isa = PBXSourcesBuildPhase; 348 | buildActionMask = 2147483647; 349 | files = ( 350 | 8431D8AE1CDBB47E00BB0679 /* CodeGenerationExampleTests.swift in Sources */, 351 | ); 352 | runOnlyForDeploymentPostprocessing = 0; 353 | }; 354 | /* End PBXSourcesBuildPhase section */ 355 | 356 | /* Begin PBXTargetDependency section */ 357 | 8431D8B11CDBB47E00BB0679 /* PBXTargetDependency */ = { 358 | isa = PBXTargetDependency; 359 | target = 840B7FDC1CDBA373008CA97E /* CodeGenerationExample */; 360 | targetProxy = 8431D8B01CDBB47E00BB0679 /* PBXContainerItemProxy */; 361 | }; 362 | /* End PBXTargetDependency section */ 363 | 364 | /* Begin PBXVariantGroup section */ 365 | 840B7FE41CDBA373008CA97E /* Main.storyboard */ = { 366 | isa = PBXVariantGroup; 367 | children = ( 368 | 840B7FE51CDBA373008CA97E /* Base */, 369 | ); 370 | name = Main.storyboard; 371 | sourceTree = ""; 372 | }; 373 | 840B7FE91CDBA373008CA97E /* LaunchScreen.storyboard */ = { 374 | isa = PBXVariantGroup; 375 | children = ( 376 | 840B7FEA1CDBA373008CA97E /* Base */, 377 | ); 378 | name = LaunchScreen.storyboard; 379 | sourceTree = ""; 380 | }; 381 | /* End PBXVariantGroup section */ 382 | 383 | /* Begin XCBuildConfiguration section */ 384 | 840B7FED1CDBA373008CA97E /* Debug */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | ALWAYS_SEARCH_USER_PATHS = NO; 388 | CLANG_ANALYZER_NONNULL = YES; 389 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 390 | CLANG_CXX_LIBRARY = "libc++"; 391 | CLANG_ENABLE_MODULES = YES; 392 | CLANG_ENABLE_OBJC_ARC = YES; 393 | CLANG_WARN_BOOL_CONVERSION = YES; 394 | CLANG_WARN_CONSTANT_CONVERSION = YES; 395 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 396 | CLANG_WARN_EMPTY_BODY = YES; 397 | CLANG_WARN_ENUM_CONVERSION = YES; 398 | CLANG_WARN_INFINITE_RECURSION = YES; 399 | CLANG_WARN_INT_CONVERSION = YES; 400 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 401 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 402 | CLANG_WARN_UNREACHABLE_CODE = YES; 403 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 404 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 405 | COPY_PHASE_STRIP = NO; 406 | DEBUG_INFORMATION_FORMAT = dwarf; 407 | ENABLE_STRICT_OBJC_MSGSEND = YES; 408 | ENABLE_TESTABILITY = YES; 409 | GCC_C_LANGUAGE_STANDARD = gnu99; 410 | GCC_DYNAMIC_NO_PIC = NO; 411 | GCC_NO_COMMON_BLOCKS = YES; 412 | GCC_OPTIMIZATION_LEVEL = 0; 413 | GCC_PREPROCESSOR_DEFINITIONS = ( 414 | "DEBUG=1", 415 | "$(inherited)", 416 | ); 417 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 418 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 419 | GCC_WARN_UNDECLARED_SELECTOR = YES; 420 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 421 | GCC_WARN_UNUSED_FUNCTION = YES; 422 | GCC_WARN_UNUSED_VARIABLE = YES; 423 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 424 | MTL_ENABLE_DEBUG_INFO = YES; 425 | ONLY_ACTIVE_ARCH = YES; 426 | SDKROOT = iphoneos; 427 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 428 | TARGETED_DEVICE_FAMILY = "1,2"; 429 | }; 430 | name = Debug; 431 | }; 432 | 840B7FEE1CDBA373008CA97E /* Release */ = { 433 | isa = XCBuildConfiguration; 434 | buildSettings = { 435 | ALWAYS_SEARCH_USER_PATHS = NO; 436 | CLANG_ANALYZER_NONNULL = YES; 437 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 438 | CLANG_CXX_LIBRARY = "libc++"; 439 | CLANG_ENABLE_MODULES = YES; 440 | CLANG_ENABLE_OBJC_ARC = YES; 441 | CLANG_WARN_BOOL_CONVERSION = YES; 442 | CLANG_WARN_CONSTANT_CONVERSION = YES; 443 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 444 | CLANG_WARN_EMPTY_BODY = YES; 445 | CLANG_WARN_ENUM_CONVERSION = YES; 446 | CLANG_WARN_INFINITE_RECURSION = YES; 447 | CLANG_WARN_INT_CONVERSION = YES; 448 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 449 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 450 | CLANG_WARN_UNREACHABLE_CODE = YES; 451 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 452 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 453 | COPY_PHASE_STRIP = NO; 454 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 455 | ENABLE_NS_ASSERTIONS = NO; 456 | ENABLE_STRICT_OBJC_MSGSEND = YES; 457 | GCC_C_LANGUAGE_STANDARD = gnu99; 458 | GCC_NO_COMMON_BLOCKS = YES; 459 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 460 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 461 | GCC_WARN_UNDECLARED_SELECTOR = YES; 462 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 463 | GCC_WARN_UNUSED_FUNCTION = YES; 464 | GCC_WARN_UNUSED_VARIABLE = YES; 465 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 466 | MTL_ENABLE_DEBUG_INFO = NO; 467 | SDKROOT = iphoneos; 468 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 469 | TARGETED_DEVICE_FAMILY = "1,2"; 470 | VALIDATE_PRODUCT = YES; 471 | }; 472 | name = Release; 473 | }; 474 | 840B7FF01CDBA373008CA97E /* Debug */ = { 475 | isa = XCBuildConfiguration; 476 | baseConfigurationReference = 278CB160078A5F46226D1DF1 /* Pods-CodeGenerationExample.debug.xcconfig */; 477 | buildSettings = { 478 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 479 | DEVELOPMENT_TEAM = ""; 480 | INFOPLIST_FILE = CodeGenerationExample/Info.plist; 481 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 482 | PRODUCT_BUNDLE_IDENTIFIER = swinject.CodeGenerationExample; 483 | PRODUCT_NAME = "$(TARGET_NAME)"; 484 | SWIFT_VERSION = 3.0; 485 | }; 486 | name = Debug; 487 | }; 488 | 840B7FF11CDBA373008CA97E /* Release */ = { 489 | isa = XCBuildConfiguration; 490 | baseConfigurationReference = B53C73B83EE93F03F8DBFE12 /* Pods-CodeGenerationExample.release.xcconfig */; 491 | buildSettings = { 492 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 493 | DEVELOPMENT_TEAM = ""; 494 | INFOPLIST_FILE = CodeGenerationExample/Info.plist; 495 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 496 | PRODUCT_BUNDLE_IDENTIFIER = swinject.CodeGenerationExample; 497 | PRODUCT_NAME = "$(TARGET_NAME)"; 498 | SWIFT_VERSION = 3.0; 499 | }; 500 | name = Release; 501 | }; 502 | 8431D8B21CDBB47E00BB0679 /* Debug */ = { 503 | isa = XCBuildConfiguration; 504 | buildSettings = { 505 | BUNDLE_LOADER = "$(TEST_HOST)"; 506 | INFOPLIST_FILE = CodeGenerationExampleTests/Info.plist; 507 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 508 | PRODUCT_BUNDLE_IDENTIFIER = swinject.CodeGenerationExampleTests; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | SWIFT_VERSION = 3.0; 511 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CodeGenerationExample.app/CodeGenerationExample"; 512 | }; 513 | name = Debug; 514 | }; 515 | 8431D8B31CDBB47E00BB0679 /* Release */ = { 516 | isa = XCBuildConfiguration; 517 | buildSettings = { 518 | BUNDLE_LOADER = "$(TEST_HOST)"; 519 | INFOPLIST_FILE = CodeGenerationExampleTests/Info.plist; 520 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 521 | PRODUCT_BUNDLE_IDENTIFIER = swinject.CodeGenerationExampleTests; 522 | PRODUCT_NAME = "$(TARGET_NAME)"; 523 | SWIFT_VERSION = 3.0; 524 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CodeGenerationExample.app/CodeGenerationExample"; 525 | }; 526 | name = Release; 527 | }; 528 | /* End XCBuildConfiguration section */ 529 | 530 | /* Begin XCConfigurationList section */ 531 | 840B7FD81CDBA373008CA97E /* Build configuration list for PBXProject "CodeGenerationExample" */ = { 532 | isa = XCConfigurationList; 533 | buildConfigurations = ( 534 | 840B7FED1CDBA373008CA97E /* Debug */, 535 | 840B7FEE1CDBA373008CA97E /* Release */, 536 | ); 537 | defaultConfigurationIsVisible = 0; 538 | defaultConfigurationName = Release; 539 | }; 540 | 840B7FEF1CDBA373008CA97E /* Build configuration list for PBXNativeTarget "CodeGenerationExample" */ = { 541 | isa = XCConfigurationList; 542 | buildConfigurations = ( 543 | 840B7FF01CDBA373008CA97E /* Debug */, 544 | 840B7FF11CDBA373008CA97E /* Release */, 545 | ); 546 | defaultConfigurationIsVisible = 0; 547 | defaultConfigurationName = Release; 548 | }; 549 | 8431D8B41CDBB47E00BB0679 /* Build configuration list for PBXNativeTarget "CodeGenerationExampleTests" */ = { 550 | isa = XCConfigurationList; 551 | buildConfigurations = ( 552 | 8431D8B21CDBB47E00BB0679 /* Debug */, 553 | 8431D8B31CDBB47E00BB0679 /* Release */, 554 | ); 555 | defaultConfigurationIsVisible = 0; 556 | defaultConfigurationName = Release; 557 | }; 558 | /* End XCConfigurationList section */ 559 | }; 560 | rootObject = 840B7FD51CDBA373008CA97E /* Project object */; 561 | } 562 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample.xcodeproj/xcshareddata/xcschemes/CodeGenerationExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CodeGenerationExample.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 840B7FDC1CDBA373008CA97E 16 | 17 | primary 18 | 19 | 20 | 8431D8AA1CDBB47E00BB0679 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/AnimalType.swift: -------------------------------------------------------------------------------- 1 | public protocol AnimalType { 2 | var name: String? { get set } 3 | func sound() -> String 4 | } 5 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // CodeGenerationExample 4 | // 5 | // Created by Wolfgang Lutz on 05.05.16. 6 | // Copyright © 2016 swinject. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Swinject 11 | 12 | let appModule = Container() { 13 | container in 14 | 15 | // container.register(AnimalType.self) { _ in Cat(name: "Mimi") } 16 | container.registerCat { _ in Cat(name: "Mimi") } 17 | 18 | // container.register(PersonType.self) { r in PetOwner(pet: r.resolve(AnimalType.self)!) } 19 | container.registerPersonType { r in PetOwner(pet: r.resolve(AnimalType.self)!) } 20 | 21 | // container.register(AnimalType.self, name: "dog") { _ in Dog(name: "Hachi") } 22 | container.registerAnimalType_dog { _ in Dog(name: "Hachi") } 23 | 24 | // container.register(PersonType.self, name: "doggy") { r in PetOwner(pet: r.resolve(AnimalType.self, name: "dog")!) } 25 | container.registerPersonType_doggy { r in PetOwner(pet: r.resolve(AnimalType.self, name: "dog")!) } 26 | 27 | // container.register(AnimalType.self, name: "cb") { _ in Cat(name: "Mew") } 28 | container.registerAnimalType_cb { _ in Cat(name: "Mew") } 29 | 30 | // container.register(PersonType.self, name: "initializer") { r in 31 | container.registerPersonType_initializer { r in 32 | InjectablePerson(pet: r.resolve(AnimalType.self)!) 33 | } 34 | 35 | // container.register(PersonType.self, name: "property1") { r in 36 | container.registerPersonType_property1 { r in 37 | let person = InjectablePerson() 38 | person.pet = r.resolve(AnimalType.self) 39 | return person 40 | } 41 | // container.register(PersonType.self, name: "property2") { _ in InjectablePerson() } 42 | container.registerPersonType_property2 { _ in InjectablePerson() } 43 | .initCompleted { r, p in 44 | let injectablePerson = p as! InjectablePerson 45 | injectablePerson.pet = r.resolve(AnimalType.self) 46 | } 47 | 48 | // container.register(PersonType.self, name: "method1") { r in 49 | container.registerPersonType_method1 { r in 50 | let person = InjectablePerson() 51 | person.setPet(r.resolve(AnimalType.self)!) 52 | return person 53 | } 54 | 55 | // container.register(PersonType.self, name: "method2") { _ in InjectablePerson() } 56 | container.registerPersonType_method2 { _ in InjectablePerson() } 57 | .initCompleted { r, p in 58 | let injectablePerson = p as! InjectablePerson 59 | injectablePerson.setPet(r.resolve(AnimalType.self)!) 60 | } 61 | 62 | // container.register(AnimalType.self) { _, name in Horse(name: name) } 63 | container.registerHorse { _, name in Horse(name: name) } 64 | 65 | // container.register(AnimalType.self) { _, name, running in Horse(name: name, running: running) } 66 | container.registerHorse { _, name, running in Horse(name: name, running: running) } 67 | 68 | // container.register(AnimalType.self) { _ in Turtle(name: "Reo") } 69 | container.registerTurtle { _ in Turtle(name: "Reo") } 70 | .inObjectScope(.container) 71 | 72 | 73 | } 74 | 75 | 76 | @UIApplicationMain 77 | class AppDelegate: UIResponder, UIApplicationDelegate { 78 | 79 | var window: UIWindow? 80 | 81 | 82 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 83 | 84 | // let person = appModule.resolve(PersonType.self)! 85 | let person = appModule.resolvePersonType() 86 | 87 | // let doggyPerson = appModule.resolve(PersonType.self, name:"doggy")! 88 | let doggyPerson = appModule.resolvePersonType_doggy() 89 | 90 | // let catWithCallback = appModule.resolve(AnimalType.self, name: "cb") 91 | let catWithCallback = appModule.resolveAnimalType_cb() 92 | 93 | // let initializerInjection = appModule.resolve(PersonType.self, name:"initializer")! 94 | let initializerInjection = appModule.resolvePersonType_initializer() 95 | 96 | // let propertyInjection1 = appModule.resolve(PersonType.self, name:"property1")! 97 | let propertyInjection1 = appModule.resolvePersonType_property1() 98 | 99 | // let propertyInjection2 = appModule.resolve(PersonType.self, name:"property2")! 100 | let propertyInjection2 = appModule.resolvePersonType_property2() 101 | 102 | // let methodInjection1 = appModule.resolve(PersonType.self, name:"method1")! 103 | let methodInjection1 = appModule.resolvePersonType_method1() 104 | 105 | // let methodInjection2 = appModule.resolve(PersonType.self, name:"method2")! 106 | let methodInjection2 = appModule.resolvePersonType_method2() 107 | 108 | //let horse1 = appModule.resolve(AnimalType.self, argument: "Spirit") as! Horse 109 | let horse1 = appModule.resolveHorse(name: "Spirit") 110 | 111 | // let horse2 = appModule.resolve(AnimalType.self, arguments: ("Lucky", true)) as! Horse 112 | let horse2 = appModule.resolveHorse(name: "Lucky", running: true) 113 | 114 | 115 | // let dog = appModule.resolve(AnimalType.self, name: "dog") 116 | let dog = appModule.resolveAnimalType_dog() 117 | 118 | // var turtle1 = appModule.resolve(AnimalType.self)! 119 | let turtle1 = appModule.resolveTurtle() 120 | 121 | print(person) 122 | print(doggyPerson) 123 | print(catWithCallback) 124 | print(initializerInjection) 125 | print(propertyInjection1) 126 | print(propertyInjection2) 127 | print(methodInjection1) 128 | print(methodInjection2) 129 | print(horse1) 130 | print(horse2) 131 | print(dog) 132 | print(turtle1) 133 | 134 | return true 135 | } 136 | 137 | func applicationWillResignActive(_ application: UIApplication) { 138 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 139 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 140 | } 141 | 142 | func applicationDidEnterBackground(_ application: UIApplication) { 143 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 144 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 145 | } 146 | 147 | func applicationWillEnterForeground(_ application: UIApplication) { 148 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 149 | } 150 | 151 | func applicationDidBecomeActive(_ application: UIApplication) { 152 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 153 | } 154 | 155 | func applicationWillTerminate(_ application: UIApplication) { 156 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 157 | } 158 | 159 | 160 | } 161 | 162 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/Cat.swift: -------------------------------------------------------------------------------- 1 | public class Cat: AnimalType { 2 | public var name: String? 3 | 4 | init(name: String?) { 5 | self.name = name 6 | } 7 | 8 | public func sound() -> String { 9 | return "Meow!" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/CodeGenerationDefinition.csv: -------------------------------------------------------------------------------- 1 | AnimalType; Cat 2 | PersonType 3 | AnimalType; AnimalType ;dog 4 | PersonType; PersonType ;doggy 5 | AnimalType; AnimalType ;cb 6 | PersonType; PersonType ;initializer 7 | PersonType; PersonType ;property1 8 | PersonType; PersonType ;property2 9 | PersonType; PersonType ;method1 10 | PersonType; PersonType ;method2 11 | AnimalType; Horse ; ; name:String 12 | AnimalType; Horse ; ; name:String ; running:Bool 13 | AnimalType; Turtle -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/Dog.swift: -------------------------------------------------------------------------------- 1 | public class Dog: AnimalType { 2 | public var name: String? 3 | 4 | init(name: String?) { 5 | self.name = name 6 | } 7 | 8 | public func sound() -> String { 9 | return "Bow wow!" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/Horse.swift: -------------------------------------------------------------------------------- 1 | public class Horse: AnimalType { 2 | public var name: String? 3 | var running: Bool 4 | 5 | convenience init(name: String) { 6 | self.init(name: name, running: false) 7 | } 8 | 9 | init(name: String, running: Bool) { 10 | self.name = name 11 | self.running = running 12 | } 13 | 14 | public func sound() -> String { 15 | return "Whinny!" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 2.0.0-beta.3 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/InjectablePerson.swift: -------------------------------------------------------------------------------- 1 | public class InjectablePerson: PersonType { 2 | var pet: AnimalType? { 3 | didSet { 4 | log = "Injected by property." 5 | } 6 | } 7 | var log = "" 8 | 9 | init() { } 10 | 11 | init(pet: AnimalType) { 12 | self.pet = pet 13 | log = "Injected by initializer." 14 | } 15 | 16 | func setPet(_ pet: AnimalType) { 17 | self.pet = pet 18 | log = "Injected by method." 19 | } 20 | 21 | public func play() -> String { 22 | return log 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/PersonType.swift: -------------------------------------------------------------------------------- 1 | public protocol PersonType { 2 | func play() -> String 3 | } 4 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/PetOwner.swift: -------------------------------------------------------------------------------- 1 | public class PetOwner: PersonType { 2 | let pet: AnimalType 3 | 4 | init(pet: AnimalType) { 5 | self.pet = pet 6 | } 7 | 8 | public func play() -> String { 9 | let name = pet.name ?? "someone" 10 | return "I'm playing with \(name). \(pet.sound())" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/Turle.swift: -------------------------------------------------------------------------------- 1 | public struct Turtle: AnimalType { 2 | public var name: String? 3 | 4 | init(name: String?) { 5 | self.name = name 6 | } 7 | 8 | public func sound() -> String { 9 | return "Ninja!" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // CodeGenerationExample 4 | // 5 | // Created by Wolfgang Lutz on 05.05.16. 6 | // Copyright © 2016 swinject. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExampleTests/CodeGenerationExampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeGenerationExampleTests.swift 3 | // CodeGenerationExampleTests 4 | // 5 | // Created by Wolfgang Lutz on 05.05.16. 6 | // Copyright © 2016 swinject. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class CodeGenerationExampleTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testExample() { 24 | // This is an example of a functional test case. 25 | // Use XCTAssert and related functions to verify your tests produce the correct results. 26 | } 27 | 28 | func testPerformanceExample() { 29 | // This is an example of a performance test case. 30 | self.measure { 31 | // Put the code you want to measure the time of here. 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/CodeGenerationExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, "8.0" 3 | # Uncomment this line if you're using Swift 4 | use_frameworks! 5 | 6 | target "CodeGenerationExample" do 7 | pod 'Swinject', '= 2.0.0-beta.3' 8 | #pod "Swinject-CodeGen", git: "https://github.com/Swinject/Swinject-CodeGen.git" 9 | end 10 | -------------------------------------------------------------------------------- /ExampleProject/CodeGenerationExample/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Swinject (2.0.0-beta.3) 3 | 4 | DEPENDENCIES: 5 | - Swinject (= 2.0.0-beta.3) 6 | 7 | SPEC CHECKSUMS: 8 | Swinject: a94dd23e05c7b557e53ee4e0f795f15cba19c7df 9 | 10 | PODFILE CHECKSUM: 25ea31cdf4e07cb292354476c6e39c7cac018744 11 | 12 | COCOAPODS: 1.1.1 13 | -------------------------------------------------------------------------------- /ExampleScript/example.csv: -------------------------------------------------------------------------------- 1 | #= import ADependency 2 | PersonType; InjectablePerson; initializer 3 | PersonType; InjectablePerson 4 | PersonType; PersonType 5 | AnotherPersonType 6 | PersonType; InjectablePerson; ; argumentName:ArgumentType 7 | PersonType; InjectablePerson; ; argumentName:ArgumentType; ArgumentTypeWithoutSpecificName; title:String; String 8 | PersonType; InjectablePerson; initializer; argumentName:ArgumentType; ArgumentTypeWithoutSpecificName; title:String; String 9 | -------------------------------------------------------------------------------- /ExampleScript/example.yml: -------------------------------------------------------------------------------- 1 | --- 2 | HEADERS: 3 | - import ADependency 4 | DEFINITIONS: 5 | - service: PersonType 6 | component: InjectablePerson 7 | name: initializer 8 | - service: PersonType 9 | component: InjectablePerson 10 | - service: PersonType 11 | component: PersonType 12 | - service: AnotherPersonType 13 | component: AnotherPersonType 14 | - service: PersonType 15 | component: InjectablePerson 16 | arguments: 17 | - argument_name: argument_name 18 | argument_type: argument_type 19 | - service: PersonType 20 | component: InjectablePerson 21 | arguments: 22 | - argument_name: argument_name 23 | argument_type: argument_type 24 | - argument_name: argument_typewithoutspecificname 25 | argument_type: argument_typeWithoutSpecificName 26 | - argument_name: title 27 | argument_type: String 28 | - argument_name: string 29 | argument_type: String 30 | - service: PersonType 31 | component: InjectablePerson 32 | name: initializer 33 | arguments: 34 | - argument_name: argument_name 35 | argument_type: argument_type 36 | - argument_name: argument_typewithoutspecificname 37 | argument_type: argument_typeWithoutSpecificName 38 | - argument_name: title 39 | argument_type: String 40 | - argument_name: string 41 | argument_type: String 42 | -------------------------------------------------------------------------------- /ExampleScript/generateCode.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | ../bin/swinject_codegen -i example.csv -o containerExtension.swift 3 | ../bin/swinject_codegen -i example.yml -o containerExtension2.swift 4 | ../bin/swinject_codegen -i example.csv -c -o example.csv.yml 5 | ../bin/swinject_codegen -i example.yml -c -o example.yml.csv 6 | ../bin/swinject_codegen -i example.csv -m > csvMigration.sh 7 | ../bin/swinject_codegen -i example.yml -m > ymlMigration.sh 8 | ../bin/swinject_codegen -i example.csv.yml -o containerExtension3.swift 9 | ../bin/swinject_codegen -i example.yml.csv -o containerExtension4.swift 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # A sample Gemfile 2 | source "https://rubygems.org" 3 | 4 | gem "cocoapods" 5 | gem "fastlane" 6 | 7 | require "rubygems" 8 | gem "minitest" # ensures you're using the gem, and not the built in MT 9 | gem "minitest-reporters" 10 | gem "rubocop" 11 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (2.3.5) 5 | activesupport (4.2.7.1) 6 | i18n (~> 0.7) 7 | json (~> 1.7, >= 1.7.7) 8 | minitest (~> 5.1) 9 | thread_safe (~> 0.3, >= 0.3.4) 10 | tzinfo (~> 1.1) 11 | addressable (2.5.0) 12 | public_suffix (~> 2.0, >= 2.0.2) 13 | ansi (1.5.0) 14 | ast (2.3.0) 15 | babosa (1.0.2) 16 | builder (3.2.3) 17 | claide (1.0.1) 18 | cocoapods (1.2.0) 19 | activesupport (>= 4.0.2, < 5) 20 | claide (>= 1.0.1, < 2.0) 21 | cocoapods-core (= 1.2.0) 22 | cocoapods-deintegrate (>= 1.0.1, < 2.0) 23 | cocoapods-downloader (>= 1.1.3, < 2.0) 24 | cocoapods-plugins (>= 1.0.0, < 2.0) 25 | cocoapods-search (>= 1.0.0, < 2.0) 26 | cocoapods-stats (>= 1.0.0, < 2.0) 27 | cocoapods-trunk (>= 1.1.2, < 2.0) 28 | cocoapods-try (>= 1.1.0, < 2.0) 29 | colored (~> 1.2) 30 | escape (~> 0.0.4) 31 | fourflusher (~> 2.0.1) 32 | gh_inspector (~> 1.0) 33 | molinillo (~> 0.5.5) 34 | nap (~> 1.0) 35 | ruby-macho (~> 0.2.5) 36 | xcodeproj (>= 1.4.1, < 2.0) 37 | cocoapods-core (1.2.0) 38 | activesupport (>= 4.0.2, < 5) 39 | fuzzy_match (~> 2.0.4) 40 | nap (~> 1.0) 41 | cocoapods-deintegrate (1.0.1) 42 | cocoapods-downloader (1.1.3) 43 | cocoapods-plugins (1.0.0) 44 | nap 45 | cocoapods-search (1.0.0) 46 | cocoapods-stats (1.0.0) 47 | cocoapods-trunk (1.1.2) 48 | nap (>= 0.8, < 2.0) 49 | netrc (= 0.7.8) 50 | cocoapods-try (1.1.0) 51 | colored (1.2) 52 | commander (4.4.3) 53 | highline (~> 1.7.2) 54 | domain_name (0.5.20161129) 55 | unf (>= 0.0.5, < 1.0.0) 56 | dotenv (2.2.0) 57 | escape (0.0.4) 58 | excon (0.55.0) 59 | faraday (0.11.0) 60 | multipart-post (>= 1.2, < 3) 61 | faraday-cookie_jar (0.0.6) 62 | faraday (>= 0.7.4) 63 | http-cookie (~> 1.0.0) 64 | faraday_middleware (0.11.0.1) 65 | faraday (>= 0.7.4, < 1.0) 66 | fastimage (2.0.1) 67 | addressable (~> 2) 68 | fastlane (2.14.2) 69 | activesupport (< 5) 70 | addressable (>= 2.3, < 3.0.0) 71 | babosa (>= 1.0.2, < 2.0.0) 72 | bundler (>= 1.12.0, < 2.0.0) 73 | colored 74 | commander (>= 4.4.0, < 5.0.0) 75 | dotenv (>= 2.1.1, < 3.0.0) 76 | excon (>= 0.45.0, < 1.0.0) 77 | faraday (~> 0.9) 78 | faraday-cookie_jar (~> 0.0.6) 79 | faraday_middleware (~> 0.9) 80 | fastimage (>= 1.6) 81 | gh_inspector (>= 1.0.1, < 2.0.0) 82 | google-api-client (~> 0.9.2) 83 | highline (>= 1.7.2, < 2.0.0) 84 | json (< 3.0.0) 85 | mini_magick (~> 4.5.1) 86 | multi_json 87 | multi_xml (~> 0.5) 88 | multipart-post (~> 2.0.0) 89 | plist (>= 3.1.0, < 4.0.0) 90 | rubyzip (>= 1.1.0, < 2.0.0) 91 | security (= 0.1.3) 92 | slack-notifier (>= 1.3, < 2.0.0) 93 | terminal-notifier (>= 1.6.2, < 2.0.0) 94 | terminal-table (>= 1.4.5, < 2.0.0) 95 | word_wrap (~> 1.0.0) 96 | xcodeproj (>= 0.20, < 2.0.0) 97 | xcpretty (>= 0.2.4, < 1.0.0) 98 | xcpretty-travis-formatter (>= 0.0.3) 99 | fourflusher (2.0.1) 100 | fuzzy_match (2.0.4) 101 | gh_inspector (1.0.3) 102 | google-api-client (0.9.28) 103 | addressable (~> 2.3) 104 | googleauth (~> 0.5) 105 | httpclient (~> 2.7) 106 | hurley (~> 0.1) 107 | memoist (~> 0.11) 108 | mime-types (>= 1.6) 109 | representable (~> 2.3.0) 110 | retriable (~> 2.0) 111 | googleauth (0.5.1) 112 | faraday (~> 0.9) 113 | jwt (~> 1.4) 114 | logging (~> 2.0) 115 | memoist (~> 0.12) 116 | multi_json (~> 1.11) 117 | os (~> 0.9) 118 | signet (~> 0.7) 119 | highline (1.7.8) 120 | http-cookie (1.0.3) 121 | domain_name (~> 0.5) 122 | httpclient (2.8.3) 123 | hurley (0.2) 124 | i18n (0.8.0) 125 | json (1.8.6) 126 | jwt (1.5.6) 127 | little-plugger (1.1.4) 128 | logging (2.1.0) 129 | little-plugger (~> 1.1) 130 | multi_json (~> 1.10) 131 | memoist (0.15.0) 132 | mime-types (3.1) 133 | mime-types-data (~> 3.2015) 134 | mime-types-data (3.2016.0521) 135 | mini_magick (4.5.1) 136 | minitest (5.10.1) 137 | minitest-reporters (1.1.14) 138 | ansi 139 | builder 140 | minitest (>= 5.0) 141 | ruby-progressbar 142 | molinillo (0.5.6) 143 | multi_json (1.12.1) 144 | multi_xml (0.6.0) 145 | multipart-post (2.0.0) 146 | nanaimo (0.2.3) 147 | nap (1.1.0) 148 | netrc (0.7.8) 149 | os (0.9.6) 150 | parser (2.4.0.0) 151 | ast (~> 2.2) 152 | plist (3.2.0) 153 | powerpack (0.1.1) 154 | public_suffix (2.0.5) 155 | rainbow (2.2.1) 156 | representable (2.3.0) 157 | uber (~> 0.0.7) 158 | retriable (2.1.0) 159 | rouge (1.11.1) 160 | rubocop (0.47.1) 161 | parser (>= 2.3.3.1, < 3.0) 162 | powerpack (~> 0.1) 163 | rainbow (>= 1.99.1, < 3.0) 164 | ruby-progressbar (~> 1.7) 165 | unicode-display_width (~> 1.0, >= 1.0.1) 166 | ruby-macho (0.2.6) 167 | ruby-progressbar (1.8.1) 168 | rubyzip (1.2.1) 169 | security (0.1.3) 170 | signet (0.7.3) 171 | addressable (~> 2.3) 172 | faraday (~> 0.9) 173 | jwt (~> 1.5) 174 | multi_json (~> 1.10) 175 | slack-notifier (1.5.1) 176 | terminal-notifier (1.7.1) 177 | terminal-table (1.7.3) 178 | unicode-display_width (~> 1.1.1) 179 | thread_safe (0.3.5) 180 | tzinfo (1.2.2) 181 | thread_safe (~> 0.1) 182 | uber (0.0.15) 183 | unf (0.1.4) 184 | unf_ext 185 | unf_ext (0.0.7.2) 186 | unicode-display_width (1.1.3) 187 | word_wrap (1.0.0) 188 | xcodeproj (1.4.2) 189 | CFPropertyList (~> 2.3.3) 190 | activesupport (>= 3) 191 | claide (>= 1.0.1, < 2.0) 192 | colored (~> 1.2) 193 | nanaimo (~> 0.2.3) 194 | xcpretty (0.2.4) 195 | rouge (~> 1.8) 196 | xcpretty-travis-formatter (0.0.4) 197 | xcpretty (~> 0.2, >= 0.0.7) 198 | 199 | PLATFORMS 200 | ruby 201 | 202 | DEPENDENCIES 203 | cocoapods 204 | fastlane 205 | minitest 206 | minitest-reporters 207 | rubocop 208 | 209 | BUNDLED WITH 210 | 1.14.3 211 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Swinject Contributors 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swinject Code Generation 2 | 3 | [![Build Status](https://travis-ci.org/Swinject/Swinject-CodeGen.svg?branch=master)](https://travis-ci.org/Swinject/Swinject-CodeGen) 4 | 5 | Swinject-CodeGen provides a method to get rid of duplicate use of class values and namestrings, by generating explicit functions for registering and resolving using Swinject. 6 | Doing this, we also can generate typed tuples to use when resolving, thus allowing better documented and less error-prone code. 7 | 8 | ## Installation 9 | ### Cocoapods 10 | 11 | Add 12 | 13 | ``` 14 | pod 'Swinject-CodeGen' 15 | ``` 16 | 17 | to your podfile. 18 | 19 | ### Carthage 20 | 21 | Add 22 | 23 | ``` 24 | github "Swinject/Swinject-CodeGeneration" 25 | ``` 26 | 27 | to your Cartfile. 28 | 29 | ## Integration 30 | 1. Define your dependencies in a .csv or .yml file (see below and example file) 31 | 2. Add a call to generate the code as build script phase: 32 | 33 | For Cocoapods: 34 | ```Shell 35 | $PODS_ROOT/Swinject-CodeGen/bin/swinject_codegen -i baseInput.csv -o extensions/baseContainerExtension.swift 36 | ``` 37 | 38 | For Carthage: 39 | ```Shell 40 | $SRCROOT/Carthage/Checkouts/Swinject-CodeGen/bin/swinject_codegen -i baseInput.csv -o extensions/baseContainerExtension.swift 41 | ``` 42 | 43 | 3. Add the generated file (here: `extensions/baseContainerExtension.swift`) to xcode 44 | 4. Repeat if you need to support multiple targets/have multiple input files. 45 | 46 | The code is then generated at every build run. 47 | 48 | ## The Issue 49 | 50 | When using Swinject, lots of duplicate definitions appear, whenever we do a 51 | 52 | ```Swift 53 | container.register(PersonType.self, name: "initializer") { r in 54 | InjectablePerson(pet: r.resolve(AnimalType.self)!) 55 | } 56 | 57 | let initializerInjection = container.resolve(PersonType.self, name:"initializer")! 58 | ``` 59 | 60 | the tuple (PersonType.self, name:"initializer") becomes very redundant across the code. 61 | 62 | Furthermore, when using arguments, as done in 63 | 64 | ```Swift 65 | container.register(AnimalType.self) { _, name in Horse(name: name) } 66 | let horse1 = container.resolve(AnimalType.self, argument: "Spirit") as! Horse 67 | ``` 68 | 69 | the `argument: "Spirit"` part is not strictly typed when calling it. 70 | 71 | We propose a solution to both these problems by using CodeGeneration 72 | 73 | ## Input Format 74 | Input can be given as .csv or .yml 75 | 76 | The call 77 | ``` 78 | ./swinject_codegen -i example.csv -c 79 | ``` 80 | 81 | can be used to convert example.csv into example.csv.yml (also works for .yml). 82 | 83 | ### CSV 84 | 85 | #### Basic Structure 86 | 87 | Our basic csv structure is defined as follows: 88 | 89 | ```CSV 90 | SourceClassName; TargetClassName; Identifier; Argument 1 ... 9 91 | ``` 92 | 93 | The example above would translate to 94 | 95 | ```CSV 96 | PersonType; InjectablePerson; initializer 97 | ``` 98 | 99 | to generate both a `registerPersonType_initializer` and a `resolvePersonType_initializer` function. 100 | 101 | See the examples below for more examples. 102 | 103 | We decided to use `;` as delimiter instead of `,` to allow the use of tuples as types. 104 | 105 | #### Additional Commands 106 | The ruby parser allows using `//` and `#` for comments. 107 | Empty lines are ignored and can be used for grouping. 108 | 109 | `#=
` can be used to specify additional lines, e.g. `#= import KeychainAccess` 110 | 111 | #### Dictionaries and Arrays as Parameters 112 | When using typed dictionaries or arrays as parameters, use `Array` instead of `[Type]` and `Dictionary` instead of `[TypeA:TypeB]`: 113 | 114 | ```CSV 115 | PersonType; InjectablePerson; initializer; additionalNames:Array; family:Dictionary; 116 | ``` 117 | 118 | ### YAML 119 | 120 | Example for a .yml definition: 121 | ```yml 122 | --- 123 | HEADERS: 124 | - import ADependency 125 | DEFINITIONS: 126 | - service: PersonType 127 | component: InjectablePerson 128 | name: initializer 129 | - service: PersonType 130 | component: InjectablePerson 131 | - service: PersonType 132 | component: PersonType 133 | - service: AnotherPersonType 134 | component: AnotherPersonType 135 | - service: PersonType 136 | component: InjectablePerson 137 | arguments: 138 | - argument_name: argument_name 139 | argument_type: argument_type 140 | - service: PersonType 141 | component: InjectablePerson 142 | arguments: 143 | - argument_name: argument_name 144 | argument_type: argument_type 145 | - argument_name: argument_typewithoutspecificname 146 | argument_type: argument_typeWithoutSpecificName 147 | - argument_name: title 148 | argument_type: String 149 | - argument_name: string 150 | argument_type: String 151 | - service: PersonType 152 | component: InjectablePerson 153 | name: initializer 154 | arguments: 155 | - argument_name: argument_name 156 | argument_type: argument_type 157 | - argument_name: argument_typewithoutspecificname 158 | argument_type: argument_typeWithoutSpecificName 159 | - argument_name: title 160 | argument_type: String 161 | - argument_name: string 162 | argument_type: String 163 | ``` 164 | 165 | ## Generation Examples 166 | 167 | 168 | ### Example A: Same class as source and target 169 | 170 | #### Input 171 | ```CSV 172 | PersonType 173 | ``` 174 | 175 | #### Output 176 | ```Swift 177 | // this code is autogenerated, do not modify! 178 | 179 | import Swinject 180 | 181 | extension Resolver { 182 | 183 | func resolvePersonType() -> PersonType { 184 | return self.resolve(PersonType.self)! 185 | } 186 | } 187 | 188 | extension Container { 189 | 190 | @discardableResult func registerPersonType(registerClosure: @escaping (_ resolver: Resolver) -> (PersonType)) -> ServiceEntry { 191 | return self.register(PersonType.self, factory: registerClosure) 192 | } 193 | } 194 | ``` 195 | 196 | ### Example B: Different source and target 197 | 198 | #### Input 199 | ```CSV 200 | PersonType; InjectablePerson 201 | ``` 202 | 203 | #### Output 204 | ```Swift 205 | // this code is autogenerated, do not modify! 206 | 207 | import Swinject 208 | 209 | extension Resolver { 210 | 211 | func resolveInjectablePerson() -> InjectablePerson { 212 | return self.resolve(PersonType.self) as! InjectablePerson 213 | } 214 | } 215 | 216 | extension Container { 217 | 218 | @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver) -> (InjectablePerson)) -> ServiceEntry { 219 | return self.register(PersonType.self, factory: registerClosure) 220 | } 221 | } 222 | ``` 223 | 224 | ### Example C: Different source and target class with name 225 | 226 | #### Input 227 | ```CSV 228 | PersonType; InjectablePerson; initializer 229 | ``` 230 | 231 | #### Output 232 | ```Swift 233 | // this code is autogenerated, do not modify! 234 | 235 | import Swinject 236 | 237 | extension Resolver { 238 | 239 | func resolveInjectablePerson_initializer() -> InjectablePerson { 240 | return self.resolve(PersonType.self, name: "initializer") as! InjectablePerson 241 | } 242 | } 243 | 244 | extension Container { 245 | 246 | @discardableResult func registerInjectablePerson_initializer(registerClosure: @escaping (_ resolver: Resolver) -> (InjectablePerson)) -> ServiceEntry { 247 | return self.register(PersonType.self, name: "initializer", factory: registerClosure) 248 | } 249 | } 250 | ``` 251 | 252 | ### Example D: Different source and target with a single, explicitly named argument 253 | #### Input 254 | ```CSV 255 | PersonType; InjectablePerson; ; argumentName:ArgumentType 256 | ``` 257 | 258 | #### Output 259 | ```Swift 260 | // this code is autogenerated, do not modify! 261 | 262 | import Swinject 263 | 264 | extension Resolver { 265 | 266 | func resolveInjectablePerson(argumentName: ArgumentType) -> InjectablePerson { 267 | return self.resolve(PersonType.self, argument: argumentName) as! InjectablePerson 268 | } 269 | } 270 | 271 | extension Container { 272 | 273 | @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType) -> (InjectablePerson)) -> ServiceEntry { 274 | return self.register(PersonType.self, factory: registerClosure) 275 | } 276 | } 277 | ``` 278 | 279 | ### Example E: Different source and target with multiple arguments, both explicitly named and not 280 | If no explicit name is given, the lowercase type is used as argumentname. 281 | 282 | #### Input 283 | ```CSV 284 | PersonType; InjectablePerson; ; argumentName:ArgumentType; ArgumentTypeWithoutSpecificName; title:String; String 285 | ``` 286 | 287 | #### Output 288 | ```Swift 289 | // this code is autogenerated, do not modify! 290 | 291 | import Swinject 292 | 293 | extension Resolver { 294 | 295 | func resolveInjectablePerson(argumentName: ArgumentType, argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, title: String, string: String) -> InjectablePerson { 296 | return self.resolve(PersonType.self, arguments: argumentName, argumenttypewithoutspecificname, title, string) as! InjectablePerson 297 | } 298 | } 299 | 300 | extension Container { 301 | 302 | @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType, _ argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, _ title: String, _ string: String) -> (InjectablePerson)) -> ServiceEntry { 303 | return self.register(PersonType.self, factory: registerClosure) 304 | } 305 | } 306 | ``` 307 | 308 | ### Example F: Different source and target with name with multiple arguments, both explicitly named and not 309 | #### Input 310 | ```CSV 311 | PersonType; InjectablePerson; initializer; argumentName:ArgumentType; ArgumentTypeWithoutSpecificName; title:String; String 312 | ``` 313 | 314 | #### Output 315 | ```Swift 316 | // this code is autogenerated, do not modify! 317 | 318 | import Swinject 319 | 320 | extension Resolver { 321 | 322 | func resolveInjectablePerson_initializer(argumentName: ArgumentType, argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, title: String, string: String) -> InjectablePerson { 323 | return self.resolve(PersonType.self, name: "initializer", arguments: argumentName, argumenttypewithoutspecificname, title, string) as! InjectablePerson 324 | } 325 | } 326 | 327 | extension Container { 328 | 329 | @discardableResult func registerInjectablePerson_initializer(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType, _ argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, _ title: String, _ string: String) -> (InjectablePerson)) -> ServiceEntry { 330 | return self.register(PersonType.self, name: "initializer", factory: registerClosure) 331 | } 332 | } 333 | ``` 334 | 335 | ## Usage Examples 336 | 337 | Using the examples given at the beginning, we can now instead of 338 | 339 | ```Swift 340 | container.register(PersonType.self, name: "initializer") { r in 341 | InjectablePerson(pet: r.resolve(AnimalType.self)!) 342 | } 343 | 344 | let initializerInjection = container.resolve(PersonType.self, name:"initializer")! 345 | ``` 346 | 347 | write: 348 | 349 | ```Swift 350 | container.registerPersonType_initializer { r in 351 | InjectablePerson(pet: r.resolve(AnimalType.self)!) 352 | } 353 | 354 | let initializerInjection = container.resolvePersonType_initializer() 355 | ``` 356 | 357 | Also 358 | 359 | ```Swift 360 | container.register(AnimalType.self) { _, name in Horse(name: name) } 361 | let horse1 = container.resolve(AnimalType.self, argument: "Spirit") 362 | ``` 363 | 364 | becomes 365 | 366 | ```Swift 367 | container.registerAnimalType { (_, name:String) in 368 | Horse(name: name) 369 | } 370 | let horse1 = container.resolveAnimalType("Spirit") 371 | ``` 372 | 373 | ## Migration 374 | The script also generates migration.sh files (when using the -m switch), which use sed to go through the code and replace simple cases (i.e. no arguments) of resolve and register. 375 | No automatic migration is available for cases with arguments, yet. 376 | Simply call the .sh file from the root of the project and compare the results in a git-GUI. 377 | 378 | ## Results 379 | We currently use the code generation in two medium-sized apps across tvOS and iOS. 380 | 381 | We found our code to become much more convenient to read and write, due to reduced duplication and autocompletion. 382 | We also have a much better overview the classes available through dependency injection. 383 | Changing some definition immediately leads to information, where an error will occur. 384 | We were able to replace all our occurrences of `.resolve(` and `.register(` using the current implementation. 385 | 386 | ## Contributors 387 | The original idea for combining CodeGeneration and Swinject came from [Daniel Dengler](https://github.com/ddengler), [David Kraus](https://github.com/davidkraus) and [Wolfgang Lutz](https://github.com/lutzifer). 388 | -------------------------------------------------------------------------------- /Support/README.erb: -------------------------------------------------------------------------------- 1 | # Swinject Code Generation 2 | 3 | [![Build Status](https://travis-ci.org/Swinject/Swinject-CodeGen.svg?branch=master)](https://travis-ci.org/Swinject/Swinject-CodeGen) 4 | 5 | Swinject-CodeGen provides a method to get rid of duplicate use of class values and namestrings, by generating explicit functions for registering and resolving using Swinject. 6 | Doing this, we also can generate typed tuples to use when resolving, thus allowing better documented and less error-prone code. 7 | 8 | ## Installation 9 | ### Cocoapods 10 | 11 | Add 12 | 13 | ``` 14 | pod 'Swinject-CodeGen' 15 | ``` 16 | 17 | to your podfile. 18 | 19 | ### Carthage 20 | 21 | Add 22 | 23 | ``` 24 | github "Swinject/Swinject-CodeGeneration" 25 | ``` 26 | 27 | to your Cartfile. 28 | 29 | ## Integration 30 | 1. Define your dependencies in a .csv or .yml file (see below and example file) 31 | 2. Add a call to generate the code as build script phase: 32 | 33 | For Cocoapods: 34 | ```Shell 35 | $PODS_ROOT/Swinject-CodeGen/bin/swinject_codegen -i baseInput.csv -o extensions/baseContainerExtension.swift 36 | ``` 37 | 38 | For Carthage: 39 | ```Shell 40 | $SRCROOT/Carthage/Checkouts/Swinject-CodeGen/bin/swinject_codegen -i baseInput.csv -o extensions/baseContainerExtension.swift 41 | ``` 42 | 43 | 3. Add the generated file (here: `extensions/baseContainerExtension.swift`) to xcode 44 | 4. Repeat if you need to support multiple targets/have multiple input files. 45 | 46 | The code is then generated at every build run. 47 | 48 | ## The Issue 49 | 50 | When using Swinject, lots of duplicate definitions appear, whenever we do a 51 | 52 | ```Swift 53 | container.register(PersonType.self, name: "initializer") { r in 54 | InjectablePerson(pet: r.resolve(AnimalType.self)!) 55 | } 56 | 57 | let initializerInjection = container.resolve(PersonType.self, name:"initializer")! 58 | ``` 59 | 60 | the tuple (PersonType.self, name:"initializer") becomes very redundant across the code. 61 | 62 | Furthermore, when using arguments, as done in 63 | 64 | ```Swift 65 | container.register(AnimalType.self) { _, name in Horse(name: name) } 66 | let horse1 = container.resolve(AnimalType.self, argument: "Spirit") as! Horse 67 | ``` 68 | 69 | the `argument: "Spirit"` part is not strictly typed when calling it. 70 | 71 | We propose a solution to both these problems by using CodeGeneration 72 | 73 | ## Input Format 74 | Input can be given as .csv or .yml 75 | 76 | The call 77 | ``` 78 | ./swinject_codegen -i example.csv -c 79 | ``` 80 | 81 | can be used to convert example.csv into example.csv.yml (also works for .yml). 82 | 83 | ### CSV 84 | 85 | #### Basic Structure 86 | 87 | Our basic csv structure is defined as follows: 88 | 89 | ```CSV 90 | SourceClassName; TargetClassName; Identifier; Argument 1 ... 9 91 | ``` 92 | 93 | The example above would translate to 94 | 95 | ```CSV 96 | PersonType; InjectablePerson; initializer 97 | ``` 98 | 99 | to generate both a `registerPersonType_initializer` and a `resolvePersonType_initializer` function. 100 | 101 | See the examples below for more examples. 102 | 103 | We decided to use `;` as delimiter instead of `,` to allow the use of tuples as types. 104 | 105 | #### Additional Commands 106 | The ruby parser allows using `//` and `#` for comments. 107 | Empty lines are ignored and can be used for grouping. 108 | 109 | `#=
` can be used to specify additional lines, e.g. `#= import KeychainAccess` 110 | 111 | #### Dictionaries and Arrays as Parameters 112 | When using typed dictionaries or arrays as parameters, use `Array` instead of `[Type]` and `Dictionary` instead of `[TypeA:TypeB]`: 113 | 114 | ```CSV 115 | PersonType; InjectablePerson; initializer; additionalNames:Array; family:Dictionary; 116 | ``` 117 | 118 | ### YAML 119 | 120 | Example for a .yml definition: 121 | ```yml 122 | <%= File.read("../ExampleScript/example.yml").chomp %> 123 | ``` 124 | 125 | ## Generation Examples 126 | 127 | 128 | ### Example A: Same class as source and target 129 | 130 | #### Input 131 | ```CSV 132 | <%= File.read("../Tests/Examples/ExampleA.csv").chomp %> 133 | ``` 134 | 135 | #### Output 136 | ```Swift 137 | <%= %x(./../bin/swinject_codegen -i ../Tests/Examples/ExampleA.csv).chomp %> 138 | ``` 139 | 140 | ### Example B: Different source and target 141 | 142 | #### Input 143 | ```CSV 144 | <%= File.read("../Tests/Examples/ExampleB.csv").chomp %> 145 | ``` 146 | 147 | #### Output 148 | ```Swift 149 | <%= %x(./../bin/swinject_codegen -i ../Tests/Examples/ExampleB.csv).chomp %> 150 | ``` 151 | 152 | ### Example C: Different source and target class with name 153 | 154 | #### Input 155 | ```CSV 156 | <%= File.read("../Tests/Examples/ExampleC.csv").chomp %> 157 | ``` 158 | 159 | #### Output 160 | ```Swift 161 | <%= %x(./../bin/swinject_codegen -i ../Tests/Examples/ExampleC.csv).chomp %> 162 | ``` 163 | 164 | ### Example D: Different source and target with a single, explicitly named argument 165 | #### Input 166 | ```CSV 167 | <%= File.read("../Tests/Examples/ExampleD.csv").chomp %> 168 | ``` 169 | 170 | #### Output 171 | ```Swift 172 | <%= %x(./../bin/swinject_codegen -i ../Tests/Examples/ExampleD.csv).chomp %> 173 | ``` 174 | 175 | ### Example E: Different source and target with multiple arguments, both explicitly named and not 176 | If no explicit name is given, the lowercase type is used as argumentname. 177 | 178 | #### Input 179 | ```CSV 180 | <%= File.read("../Tests/Examples/ExampleE.csv").chomp %> 181 | ``` 182 | 183 | #### Output 184 | ```Swift 185 | <%= %x(./../bin/swinject_codegen -i ../Tests/Examples/ExampleE.csv).chomp %> 186 | ``` 187 | 188 | ### Example F: Different source and target with name with multiple arguments, both explicitly named and not 189 | #### Input 190 | ```CSV 191 | <%= File.read("../Tests/Examples/ExampleF.csv").chomp %> 192 | ``` 193 | 194 | #### Output 195 | ```Swift 196 | <%= %x(./../bin/swinject_codegen -i ../Tests/Examples/ExampleF.csv).chomp %> 197 | ``` 198 | 199 | ## Usage Examples 200 | 201 | Using the examples given at the beginning, we can now instead of 202 | 203 | ```Swift 204 | container.register(PersonType.self, name: "initializer") { r in 205 | InjectablePerson(pet: r.resolve(AnimalType.self)!) 206 | } 207 | 208 | let initializerInjection = container.resolve(PersonType.self, name:"initializer")! 209 | ``` 210 | 211 | write: 212 | 213 | ```Swift 214 | container.registerPersonType_initializer { r in 215 | InjectablePerson(pet: r.resolve(AnimalType.self)!) 216 | } 217 | 218 | let initializerInjection = container.resolvePersonType_initializer() 219 | ``` 220 | 221 | Also 222 | 223 | ```Swift 224 | container.register(AnimalType.self) { _, name in Horse(name: name) } 225 | let horse1 = container.resolve(AnimalType.self, argument: "Spirit") 226 | ``` 227 | 228 | becomes 229 | 230 | ```Swift 231 | container.registerAnimalType { (_, name:String) in 232 | Horse(name: name) 233 | } 234 | let horse1 = container.resolveAnimalType("Spirit") 235 | ``` 236 | 237 | ## Migration 238 | The script also generates migration.sh files (when using the -m switch), which use sed to go through the code and replace simple cases (i.e. no arguments) of resolve and register. 239 | No automatic migration is available for cases with arguments, yet. 240 | Simply call the .sh file from the root of the project and compare the results in a git-GUI. 241 | 242 | ## Results 243 | We currently use the code generation in two medium-sized apps across tvOS and iOS. 244 | 245 | We found our code to become much more convenient to read and write, due to reduced duplication and autocompletion. 246 | We also have a much better overview the classes available through dependency injection. 247 | Changing some definition immediately leads to information, where an error will occur. 248 | We were able to replace all our occurrences of `.resolve(` and `.register(` using the current implementation. 249 | 250 | ## Contributors 251 | The original idea for combining CodeGeneration and Swinject came from [Daniel Dengler](https://github.com/ddengler), [David Kraus](https://github.com/davidkraus) and [Wolfgang Lutz](https://github.com/lutzifer). 252 | -------------------------------------------------------------------------------- /Support/updateReadme.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | erb Readme.erb > ../Readme.md 3 | -------------------------------------------------------------------------------- /Swinject-CodeGen.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Swinject-CodeGen" 3 | s.version = "2.0.0" 4 | s.summary = "Generates extensions on the container class, to make use of swinject less error prone and more typesafe." 5 | 6 | s.description = <<-DESC 7 | Generates extensions on the container class, to make use of swinject less error prone and more typesafe. 8 | 9 | These extensions contain functions to match the specific resolve, using one resolve function per registered class, instead of the generic calls. 10 | DESC 11 | 12 | s.homepage = "https://github.com/Swinject/Swinject-CodeGeneration" 13 | s.license = 'MIT' 14 | s.author = 'Swinject Contributors' 15 | s.source = { :git => "https://github.com/Swinject/Swinject-CodeGeneration.git", :tag => s.version.to_s } 16 | 17 | s.ios.deployment_target = '8.0' 18 | s.tvos.deployment_target = '9.0' 19 | s.preserve_paths = ['erb', 'source', 'bin'] 20 | 21 | s.dependency "Swinject", '~> 2.0.0' 22 | 23 | end 24 | -------------------------------------------------------------------------------- /Tests/Examples/Bug_51_A.csv: -------------------------------------------------------------------------------- 1 | A; A; A.B 2 | -------------------------------------------------------------------------------- /Tests/Examples/Bug_51_B.csv: -------------------------------------------------------------------------------- 1 | A; A; A_B 2 | -------------------------------------------------------------------------------- /Tests/Examples/Bug_58_A.csv: -------------------------------------------------------------------------------- 1 | A;; 2 | -------------------------------------------------------------------------------- /Tests/Examples/Bug_58_B.csv: -------------------------------------------------------------------------------- 1 | A;A; 2 | -------------------------------------------------------------------------------- /Tests/Examples/ExampleA.csv: -------------------------------------------------------------------------------- 1 | PersonType 2 | -------------------------------------------------------------------------------- /Tests/Examples/ExampleB.csv: -------------------------------------------------------------------------------- 1 | PersonType; InjectablePerson 2 | -------------------------------------------------------------------------------- /Tests/Examples/ExampleC.csv: -------------------------------------------------------------------------------- 1 | PersonType; InjectablePerson; initializer 2 | -------------------------------------------------------------------------------- /Tests/Examples/ExampleD.csv: -------------------------------------------------------------------------------- 1 | PersonType; InjectablePerson; ; argumentName:ArgumentType 2 | -------------------------------------------------------------------------------- /Tests/Examples/ExampleE.csv: -------------------------------------------------------------------------------- 1 | PersonType; InjectablePerson; ; argumentName:ArgumentType; ArgumentTypeWithoutSpecificName; title:String; String 2 | -------------------------------------------------------------------------------- /Tests/Examples/ExampleF.csv: -------------------------------------------------------------------------------- 1 | PersonType; InjectablePerson; initializer; argumentName:ArgumentType; ArgumentTypeWithoutSpecificName; title:String; String 2 | -------------------------------------------------------------------------------- /Tests/Examples/bug_50_A.csv: -------------------------------------------------------------------------------- 1 | A; A; name 2 | -------------------------------------------------------------------------------- /Tests/Examples/bug_50_B.csv: -------------------------------------------------------------------------------- 1 | A; A; name; 2 | -------------------------------------------------------------------------------- /Tests/ExpectedCode/ExampleA.swift: -------------------------------------------------------------------------------- 1 | // this code is autogenerated, do not modify! 2 | 3 | import Swinject 4 | 5 | extension Resolver { 6 | 7 | func resolvePersonType() -> PersonType { 8 | return self.resolve(PersonType.self)! 9 | } 10 | } 11 | 12 | extension Container { 13 | 14 | @discardableResult func registerPersonType(registerClosure: @escaping (_ resolver: Resolver) -> (PersonType)) -> ServiceEntry { 15 | return self.register(PersonType.self, factory: registerClosure) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/ExpectedCode/ExampleB.swift: -------------------------------------------------------------------------------- 1 | // this code is autogenerated, do not modify! 2 | 3 | import Swinject 4 | 5 | extension Resolver { 6 | 7 | func resolveInjectablePerson() -> InjectablePerson { 8 | return self.resolve(PersonType.self) as! InjectablePerson 9 | } 10 | } 11 | 12 | extension Container { 13 | 14 | @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver) -> (InjectablePerson)) -> ServiceEntry { 15 | return self.register(PersonType.self, factory: registerClosure) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/ExpectedCode/ExampleC.swift: -------------------------------------------------------------------------------- 1 | // this code is autogenerated, do not modify! 2 | 3 | import Swinject 4 | 5 | extension Resolver { 6 | 7 | func resolveInjectablePerson_initializer() -> InjectablePerson { 8 | return self.resolve(PersonType.self, name: "initializer") as! InjectablePerson 9 | } 10 | } 11 | 12 | extension Container { 13 | 14 | @discardableResult func registerInjectablePerson_initializer(registerClosure: @escaping (_ resolver: Resolver) -> (InjectablePerson)) -> ServiceEntry { 15 | return self.register(PersonType.self, name: "initializer", factory: registerClosure) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/ExpectedCode/ExampleD.swift: -------------------------------------------------------------------------------- 1 | // this code is autogenerated, do not modify! 2 | 3 | import Swinject 4 | 5 | extension Resolver { 6 | 7 | func resolveInjectablePerson(argumentName: ArgumentType) -> InjectablePerson { 8 | return self.resolve(PersonType.self, argument: argumentName) as! InjectablePerson 9 | } 10 | } 11 | 12 | extension Container { 13 | 14 | @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType) -> (InjectablePerson)) -> ServiceEntry { 15 | return self.register(PersonType.self, factory: registerClosure) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/ExpectedCode/ExampleE.swift: -------------------------------------------------------------------------------- 1 | // this code is autogenerated, do not modify! 2 | 3 | import Swinject 4 | 5 | extension Resolver { 6 | 7 | func resolveInjectablePerson(argumentName: ArgumentType, argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, title: String, string: String) -> InjectablePerson { 8 | return self.resolve(PersonType.self, arguments: argumentName, argumenttypewithoutspecificname, title, string) as! InjectablePerson 9 | } 10 | } 11 | 12 | extension Container { 13 | 14 | @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType, _ argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, _ title: String, _ string: String) -> (InjectablePerson)) -> ServiceEntry { 15 | return self.register(PersonType.self, factory: registerClosure) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/ExpectedCode/ExampleF.swift: -------------------------------------------------------------------------------- 1 | // this code is autogenerated, do not modify! 2 | 3 | import Swinject 4 | 5 | extension Resolver { 6 | 7 | func resolveInjectablePerson_initializer(argumentName: ArgumentType, argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, title: String, string: String) -> InjectablePerson { 8 | return self.resolve(PersonType.self, name: "initializer", arguments: argumentName, argumenttypewithoutspecificname, title, string) as! InjectablePerson 9 | } 10 | } 11 | 12 | extension Container { 13 | 14 | @discardableResult func registerInjectablePerson_initializer(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType, _ argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, _ title: String, _ string: String) -> (InjectablePerson)) -> ServiceEntry { 15 | return self.register(PersonType.self, name: "initializer", factory: registerClosure) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/test.rb: -------------------------------------------------------------------------------- 1 | require "minitest/autorun" 2 | require "minitest/reporters" 3 | 4 | 5 | reporter_options = { color: true } 6 | default_reporter = Minitest::Reporters::DefaultReporter.new(reporter_options) 7 | Minitest::Reporters.use! [default_reporter] 8 | 9 | # code generation tests 10 | class TestCodegeneration < Minitest::Test 11 | def build_csv(file_name) 12 | `./../bin/swinject_codegen -i #{file_name}`.chomp 13 | end 14 | 15 | def read_file(file_name) 16 | File.read(file_name).chomp 17 | end 18 | 19 | def run_test(base_file_name) 20 | output = build_csv("Examples/#{base_file_name}.csv") 21 | example = read_file("ExpectedCode/#{base_file_name}.swift") 22 | assert_equal output, example 23 | end 24 | 25 | def test_example_a 26 | run_test("ExampleA") 27 | end 28 | 29 | def test_example_b 30 | run_test("ExampleB") 31 | end 32 | 33 | def test_example_c 34 | run_test("ExampleC") 35 | end 36 | 37 | def test_example_d 38 | run_test("ExampleD") 39 | end 40 | 41 | def test_example_e 42 | run_test("ExampleE") 43 | end 44 | 45 | def test_example_f 46 | run_test("ExampleF") 47 | end 48 | 49 | def test_bug_50 50 | outputA = build_csv("Examples/bug_50_A.csv") 51 | outputB = build_csv("Examples/bug_50_B.csv") 52 | assert_equal outputA, outputB 53 | end 54 | 55 | def test_Bug_51 56 | outputA = build_csv("Examples/Bug_51_A.csv") 57 | outputB = build_csv("Examples/Bug_51_B.csv") 58 | assert_equal outputA, outputB 59 | end 60 | 61 | def test_Bug_58 62 | outputA = build_csv("Examples/Bug_58_A.csv") 63 | outputB = build_csv("Examples/Bug_58_B.csv") 64 | assert_equal outputA, outputB 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /bin/swinject_codegen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "erb" 3 | require "Shellwords" 4 | require "optparse" 5 | require_relative "../source/csv_parser" 6 | require_relative "../source/yml_parser" 7 | require_relative "../source/yml_serializer" 8 | 9 | @options = { 10 | MIGRATION: false, 11 | CONVERT: false, 12 | INPUT_FILE: nil, 13 | OUTPUT_FILE: nil 14 | } 15 | 16 | @parser = OptionParser.new do |opts| 17 | opts.banner = "Usage: #{__FILE__} [options]" 18 | 19 | opts.on("-iINPUT", "--input=INPUT", "The file containing the definitions, currently .yml and .csv are supported (separated by semicolon).") do |i| 20 | @options[:INPUT_FILE] = i 21 | end 22 | 23 | opts.on("-oOUTPUT", "--output=OUTPUT", "The file to write to. Use STDOUT if not given") do |o| 24 | @options[:OUTPUT_FILE] = o 25 | end 26 | 27 | opts.on("-m", "--migration", "Generate migration.sh files to automatically replace existing calls in swift code.") do 28 | @options[:MIGRATION] = true 29 | end 30 | 31 | opts.on("-c", "--convert", "Convert the input file into the other format") do 32 | @options[:CONVERT] = true 33 | end 34 | 35 | opts.on("-h", "--help", "Prints this help") do 36 | puts opts 37 | exit 38 | end 39 | end 40 | 41 | def main 42 | @parser.parse! 43 | 44 | input_filename = @options[:INPUT_FILE] 45 | 46 | definition_hash = parse_input_file(input_filename) 47 | 48 | if @options[:CONVERT] 49 | 50 | output_filename = @options[:OUTPUT_FILE] 51 | 52 | if input_filename.end_with?("csv") 53 | YMLSerializer.new.serialize_hash_to_yml(definition_hash, output_filename) 54 | elsif input_filename.end_with?("yml") 55 | serialize_hash_to_CSV(definition_hash, output_filename) 56 | end 57 | 58 | unless output_filename.nil? 59 | puts "Converted #{input_filename} to #{output_filename}" 60 | end 61 | 62 | exit 0 63 | end 64 | 65 | prepare_definitions(definition_hash) 66 | 67 | if @options[:MIGRATION] 68 | write_migration_file(definition_hash, @options[:OUTPUT_FILE]) 69 | end 70 | 71 | unless @options[:CONVERT] || @options[:MIGRATION] 72 | write_container_file(definition_hash, @options[:OUTPUT_FILE]) 73 | end 74 | end 75 | 76 | def parse_input_file(input_filename) 77 | if input_filename.end_with?("csv") 78 | return CSVParser.new.parse_csv(input_filename) 79 | elsif input_filename.end_with?("yml") 80 | return YMLParser.new.parse_yml(input_filename) 81 | else 82 | puts "unknown input format for file #{input_filename}" 83 | exit 84 | end 85 | end 86 | 87 | def templates_folder 88 | "#{File.expand_path(File.dirname(__FILE__))}/../erb" 89 | end 90 | 91 | def write_container_file(input_hash, output_filename) 92 | @content_array = input_hash[:DEFINITIONS] 93 | @headers = input_hash[:HEADERS] 94 | 95 | code = ERB.new(File.read("#{templates_folder}/container.erb"), nil, "-").result 96 | 97 | if output_filename.nil? 98 | puts code 99 | else 100 | File.open(output_filename, "w") do |file_to_write_to| 101 | file_to_write_to.puts code 102 | puts "Generated code in #{output_filename}" 103 | end 104 | end 105 | end 106 | 107 | def write_migration_file(input_hash, output_filename) 108 | @migration_array = [] 109 | 110 | input_hash[:DEFINITIONS].each do |definition| 111 | register_function_call_without_last_comma = definition[:register_function_call].reverse.sub(",", "").reverse 112 | 113 | migration_hash = { 114 | resolve_function_signature_regex: Shellwords.escape(".#{definition[:resolve_function_signature].split('->').first.strip}"), 115 | resolve_function_call: Shellwords.escape("#{definition[:resolve_function_call]})!"), 116 | register_function_signature_regex: Shellwords.escape(".#{definition[:register_function_signature].split('(').first}"), 117 | register_function_call: Shellwords.escape("#{register_function_call_without_last_comma})") 118 | } 119 | 120 | @migration_array.push migration_hash 121 | end 122 | 123 | migration_code = ERB.new(File.read("#{templates_folder}/migration.erb"), nil, "-").result 124 | 125 | if output_filename.nil? 126 | puts migration_code 127 | else 128 | migration_file_name = "#{output_filename}.migration.sh" 129 | File.open(migration_file_name, "w") do |file_to_write_to| 130 | file_to_write_to.puts migration_code 131 | puts "Generated migration code in #{migration_file_name}" 132 | end 133 | end 134 | end 135 | 136 | def prepare_definitions(hash) 137 | definitions = hash[:DEFINITIONS] 138 | 139 | definitions.each do |definition| 140 | name = definition[:name] 141 | name = name.gsub(/[^0-9a-zA-Z]/i, '_') unless name.nil? 142 | 143 | has_no_name = (name.nil? || name.empty?) 144 | argument_hashes = definition[:arguments] 145 | 146 | register_function_signature = "register" 147 | register_function_signature << definition[:component].delete("<").delete(">").delete(".") 148 | register_function_signature << "_#{name}" unless has_no_name 149 | register_function_signature << "(registerClosure: @escaping (_ resolver: Resolver" 150 | register_function_signature << ", " unless argument_hashes.nil? || argument_hashes.empty? 151 | register_function_signature << argument_hashes.map { |a| "_ #{a[:argument_name]}: #{a[:argument_type]}" }.join(", ") unless argument_hashes.nil? || argument_hashes.empty? 152 | register_function_signature << ") -> (#{definition[:component]})) -> ServiceEntry<#{definition[:service]}>" 153 | 154 | register_function_call = ".register(" 155 | register_function_call << "#{definition[:service]}.self," 156 | register_function_call << " name: \"#{name}\"," unless has_no_name 157 | 158 | resolve_function_signature = "resolve" 159 | resolve_function_signature << definition[:component].delete("<").delete(">").delete(".") 160 | resolve_function_signature << "_#{name}" unless has_no_name 161 | resolve_function_signature << "(" 162 | resolve_function_signature << argument_hashes.each_with_index.map { |a, i| "#{a[:argument_name]}: #{a[:argument_type]}" }.join(", ") unless argument_hashes.nil? || argument_hashes.empty? 163 | resolve_function_signature << ") -> #{definition[:component]}" 164 | 165 | resolve_function_call = ".resolve(" 166 | resolve_function_call << "#{definition[:service]}.self" 167 | resolve_function_call << ", name: \"#{name}\"" unless has_no_name 168 | 169 | definition[:resolve_function_signature] = resolve_function_signature 170 | definition[:resolve_function_call] = resolve_function_call 171 | definition[:register_function_signature] = register_function_signature 172 | definition[:register_function_call] = register_function_call 173 | end 174 | end 175 | 176 | def serialize_hash_to_CSV(hash, output_filename) 177 | @content_array = hash[:DEFINITIONS] 178 | @headers = hash[:HEADERS] 179 | 180 | code = ERB.new(File.read("#{templates_folder}/csv.erb"), nil, "-").result 181 | 182 | if output_filename.nil? 183 | puts code 184 | else 185 | File.open(output_filename, "w") do |file_to_write_to| 186 | file_to_write_to.puts code 187 | end 188 | end 189 | end 190 | 191 | main if __FILE__ == $PROGRAM_NAME 192 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # exit script, if error 4 | set -e 5 | 6 | # defne colors 7 | RED=`tput setaf 1` 8 | GREEN=`tput setaf 2` 9 | NOCOLOR=`tput sgr0` 10 | 11 | BOOTSTRAP_SOURCE="https://raw.githubusercontent.com/num42/n42-ios-bootstrap-shell/master/bootstrap.sh" 12 | 13 | echo "${GREEN}Running N42 Bootstrap v1.13 (2017-02-12)${NOCOLOR}" 14 | echo "${GREEN}If the script fails, there might be a newer Version on $BOOTSTRAP_SOURCE ${NOCOLOR}" 15 | echo "${GREEN}You can directly download it with 'curl -L $BOOTSTRAP_SOURCE -o bootstrap.sh' ${NOCOLOR}" 16 | echo "${GREEN}You can update the script by running "sh bootstrap.sh -u"' ${NOCOLOR}" 17 | 18 | 19 | if [[ $1 == "-u" ]] ; then 20 | echo 'Updating bootstrap.sh' 21 | curl -L $BOOTSTRAP_SOURCE?$(date +%s) -o $0 22 | exit 1 23 | fi 24 | 25 | 26 | installDependencyWithBrew(){ 27 | # install dependency, if is not installed 28 | brew list $1 || brew install $1 || echo "${RED} FAILED TO INSTALL $1 ${NOCOLOR}"; 29 | 30 | # upgrade dependency, if it is outdated 31 | brew outdated $1 || brew upgrade $1 || echo "${RED} FAILED TO UPGRADE $1 ${NOCOLOR}"; 32 | } 33 | 34 | # updaet brew to keep dependencies up to date 35 | brew update || echo "${RED} FAILED TO UPDATE BREW ${NOCOLOR}"; 36 | 37 | installDependencyWithBrew rbenv 38 | installDependencyWithBrew ruby-build 39 | 40 | # install ruby version from .ruby-version, skipping if already installed (-s) 41 | rbenv install -s 42 | 43 | # install bundler gem for ruby dependency management 44 | gem install bundler || echo "${RED} FAILED TO INSTALL BUNDLER ${NOCOLOR}"; 45 | bundle install || echo "${RED} FAILED TO INSTALL BUNDLE ${NOCOLOR}"; 46 | 47 | if [ -e "podfile" ]; then 48 | # install cocoapods dependencies 49 | bundle exec pod repo update 50 | bundle exec pod install || echo "${RED} FAILED TO INSTALL PODS ${NOCOLOR}"; 51 | fi 52 | 53 | installDependencyWithBrew carthage 54 | 55 | # keep submodules up to date, see https://git-scm.com/book/en/v2/Git-Tools-Submodules 56 | git submodule init || echo "${RED} FAILED TO INIT SUBMODULES ${NOCOLOR}"; 57 | git submodule update || echo "${RED} FAILED TO UPDATE SUBMODULES ${NOCOLOR}"; 58 | 59 | if [ -e "fastlane/Fastfile" ]; then 60 | if bundle exec fastlane lanes | grep "match_all"; then 61 | # Run fastlane to ensure certs and profiles are installed 62 | bundle exec fastlane ios match_all || echo "${RED} FAILED TO RUN MATCH ${NOCOLOR}"; 63 | fi 64 | fi 65 | -------------------------------------------------------------------------------- /erb/container.erb: -------------------------------------------------------------------------------- 1 | <%# Ignore the following line in the erb, the erb is not autogenerated and can be modified -%> 2 | // this code is autogenerated, do not modify! 3 | 4 | import Swinject 5 | <% @headers.uniq.each do |header| %> 6 | <%= header %> 7 | <% end -%> 8 | 9 | extension Resolver { 10 | <% @content_array.each do |hash| %> 11 | func <%= hash[:resolve_function_signature] %> { 12 | return self<%= hash[:resolve_function_call] %><%= ", argument: #{hash[:arguments][0][:argument_name]}" if !hash[:arguments].nil? && hash[:arguments].count == 1 -%><%= ", arguments: #{hash[:arguments].map {|a| a[:argument_name]}.join(", ")}" if !hash[:arguments].nil? && hash[:arguments].count > 1 -%>)<%=hash[:service] != hash[:component] ? " as! #{hash[:component]}" : "!"%> 13 | } 14 | <% end -%> 15 | } 16 | 17 | extension Container { 18 | <% @content_array.each do |hash| %> 19 | @discardableResult func <%= hash[:register_function_signature] %> { 20 | return self<%= hash[:register_function_call] %> factory: registerClosure) 21 | } 22 | <% end -%> 23 | } 24 | -------------------------------------------------------------------------------- /erb/csv.erb: -------------------------------------------------------------------------------- 1 | <% @headers.uniq.each do |header| -%> 2 | #= <%= "#{header}" %> 3 | <% end -%> 4 | <% @content_array.each do |hash| -%> 5 | <%=hash[:service] unless hash[:service].nil? %>; <%= hash[:component] unless hash[:component].nil? %> ; <%= hash[:name] unless hash[:name].nil? %> ; <%= hash[:arguments].map {|a| "#{a[:argument_name]}: #{a[:argument_type]}"}.join("; ") unless hash[:arguments].nil? %> 6 | <% end -%> 7 | -------------------------------------------------------------------------------- /erb/migration.erb: -------------------------------------------------------------------------------- 1 | find . -type f | grep ".swift" > swiftindex.temp 2 | 3 | while IFS= read -r filename 4 | do 5 | LC_ALL=C sed -i "" \ 6 | <% @migration_array.each do |hash| -%> 7 | -e s/<%=hash[:resolve_function_call]%>/<%=hash[:resolve_function_signature_regex]%>/g \ 8 | -e s/<%=hash[:register_function_call]%>/<%=hash[:register_function_signature_regex]%>/g \ 9 | <% end -%> "$filename" 10 | done < swiftindex.temp 11 | rm swiftindex.temp 12 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | # Customize this file, documentation can be found here: 2 | # https://github.com/fastlane/fastlane/tree/master/fastlane/docs 3 | # All available actions: https://docs.fastlane.tools/actions 4 | # can also be listed using the `fastlane actions` command 5 | 6 | # Change the syntax highlighting to Ruby 7 | # All lines starting with a # are ignored when running `fastlane` 8 | 9 | # If you want to automatically update fastlane if a new version is available: 10 | # update_fastlane 11 | 12 | # This is the minimum version number required. 13 | # Update this, if you use features of a newer version 14 | fastlane_version "2.14.2" 15 | 16 | default_platform :ios 17 | 18 | platform :ios do 19 | before_all do 20 | # ENV["SLACK_URL"] = "https://hooks.slack.com/services/..." 21 | end 22 | 23 | desc "Updates the Readme file with source examples" 24 | lane :updateReadme do 25 | sh("cd ../Support;sh updateReadme.sh") 26 | end 27 | 28 | desc "Run Tests" 29 | lane :runTests do 30 | sh("cd ../Tests;ruby test.rb") 31 | end 32 | 33 | desc "Release Pod Version" 34 | lane :podRelease do 35 | sh("cd ..; pod lib lint") 36 | 37 | prompt( 38 | text: "Please edit the Podspec, update the Version number, save and press a key. Do not commit!", 39 | multi_line_end_keyword: "END" 40 | ) 41 | 42 | versionToRelease = prompt( 43 | text: "Version to Release (x.x.x): ", 44 | multi_line_end_keyword: "END" 45 | ) 46 | 47 | git_commit(path: "../Swinject-CodeGen.podspec", message: "Release #{versionToRelease}") 48 | 49 | add_git_tag( 50 | tag: "#{versionToRelease}" 51 | ) 52 | 53 | push_to_git_remote() 54 | 55 | sh ("cd ..; pod trunk register wlborg@gmx.de 'Wolfgang Lutz' --description='macbook'") 56 | 57 | prompt( 58 | text: "A new session for pod trunk was requested. Activate it from email and press a key.", 59 | multi_line_end_keyword: "END" 60 | ) 61 | 62 | sh ("cd ..; pod trunk push Swinject-CodeGen.podspec") 63 | end 64 | 65 | after_all do |lane| 66 | # This block is called, only if the executed lane was successful 67 | 68 | # slack( 69 | # message: "Successfully deployed new App Update." 70 | # ) 71 | end 72 | 73 | error do |lane, exception| 74 | # slack( 75 | # message: exception.message, 76 | # success: false 77 | # ) 78 | end 79 | end 80 | 81 | 82 | # More information about multiple platforms in fastlane: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md 83 | # All available actions: https://docs.fastlane.tools/actions 84 | 85 | # fastlane reports which actions are used 86 | # No personal data is sent or shared. Learn more at https://github.com/fastlane/enhancer 87 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | 5 | Make sure you have the latest version of the Xcode command line tools installed: 6 | 7 | ``` 8 | xcode-select --install 9 | ``` 10 | 11 | ## Choose your installation method: 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
Homebrew 16 | Installer Script 17 | Rubygems 18 |
macOSmacOSmacOS or Linux with Ruby 2.0.0 or above
brew cask install fastlaneDownload the zip file. Then double click on the install script (or run it in a terminal window).sudo gem install fastlane -NV
30 | # Available Actions 31 | ## iOS 32 | ### ios updateReadme 33 | ``` 34 | fastlane ios updateReadme 35 | ``` 36 | Updates the Readme file with source examples 37 | ### ios runTests 38 | ``` 39 | fastlane ios runTests 40 | ``` 41 | Run Tests 42 | ### ios podRelease 43 | ``` 44 | fastlane ios podRelease 45 | ``` 46 | Release Pod Version 47 | 48 | ---- 49 | 50 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. 51 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). 52 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 53 | -------------------------------------------------------------------------------- /source/csv_parser.rb: -------------------------------------------------------------------------------- 1 | # responsible for parsing the csv files 2 | class CSVParser 3 | def parse_csv(input_filename) 4 | result_hash = { 5 | HEADERS: [], 6 | DEFINITIONS: [] 7 | } 8 | 9 | f = File.open(input_filename) 10 | 11 | f.each_line do |line| 12 | if line.nil? || line.chomp.empty? 13 | # ignores empty lines 14 | elsif line.start_with?("#") 15 | # detect command 16 | if line.start_with?("#= ") 17 | result_hash[:HEADERS].push(line.split(" ")[1..-1].join(" ")) 18 | end 19 | elsif line.start_with?("//") 20 | # ignores comments 21 | else 22 | array = line.split(";").map(&:strip) 23 | arguments = array[3..-1] 24 | arguments = arguments.reject { |a| a.empty? } unless arguments.nil? 25 | argument_hashes = nil 26 | unless arguments.nil? 27 | arguments.reject(&:empty?) 28 | argument_hashes = arguments.map do |a| 29 | hash = nil 30 | if a.include?(":") 31 | hash = { 32 | argument_name: a.split(":").first.strip, 33 | argument_type: a.split(":").last.strip 34 | } 35 | else 36 | hash = { 37 | argument_name: a.downcase, 38 | argument_type: a 39 | } 40 | end 41 | hash 42 | end 43 | end 44 | 45 | service = array[0] 46 | component = (!array[1].nil? && !array[1].empty?) ? array[1] : service 47 | name = array[2] 48 | 49 | hash = { 50 | service: service, 51 | component: component, 52 | name: name, 53 | arguments: argument_hashes 54 | } 55 | 56 | result_hash[:DEFINITIONS].push hash 57 | end 58 | end 59 | result_hash 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /source/yml_parser.rb: -------------------------------------------------------------------------------- 1 | require "yaml" 2 | 3 | # class responsible for parsing from yaml 4 | class YMLParser 5 | def parse_yml(input_filename) 6 | YAML.load_file(input_filename) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /source/yml_serializer.rb: -------------------------------------------------------------------------------- 1 | require "yaml" 2 | 3 | # class responsible for serializing to yaml 4 | class YMLSerializer 5 | def serialize_hash_to_yml(hash, output_filename) 6 | code = hash.to_yaml 7 | 8 | if output_filename.nil? 9 | puts code 10 | else 11 | File.open(output_filename, "w") do |file_to_write_to| 12 | file_to_write_to.puts code 13 | end 14 | end 15 | end 16 | end 17 | --------------------------------------------------------------------------------