Skip to content

Commit

Permalink
Merge pull request #56 from scribd/55-remove-runtime
Browse files Browse the repository at this point in the history
[#55] Remove runtime registration/resolution
  • Loading branch information
trupin authored Jul 26, 2018
2 parents 7712ca6 + 412421b commit d5e9818
Show file tree
Hide file tree
Showing 116 changed files with 3,896 additions and 7,799 deletions.
1 change: 0 additions & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ coverage:
ignore:
- Sources/WeaverCommand
- "Sources/WeaverCodeGen/*.generated.swift"
- Sources/WeaverDI/Instance.swift
- Tests
status:
patch: false
Expand Down
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,3 @@ script:
- swift test
- make install
- bash -c "cd Sample && fastlane test"
- ./tools/check_carthage.sh
- pod lib lint
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION := $(shell /usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" WeaverDI.xcodeproj/WeaverCodeGen_Info.plist)
VERSION := $(shell /usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" Weaver.xcodeproj/WeaverCodeGen_Info.plist)
PREFIX=/usr/local
SWIFT_BUILD_FLAGS=--configuration release

Expand All @@ -25,7 +25,7 @@ package: build
cd ./build/package/ && zip -r ../../weaver-$(VERSION).zip ./weaver

codecov: build
xcodebuild test -scheme Tests -enableCodeCoverage YES
xcodebuild test -scheme WeaverCodeGen -enableCodeCoverage YES
bash -c "bash <(curl -s https://codecov.io/bash) -J Weaver -t eaa7c4af-5ca2-4e08-8f07-38a44671e5e0"
rm *.coverage.txt

Expand Down
18 changes: 9 additions & 9 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,6 @@
"version": "0.8.0"
}
},
{
"package": "Differ",
"repositoryURL": "https://github.com/tonyarnold/Differ.git",
"state": {
"branch": null,
"revision": "a3252fbc44b6fbc2a87539dc555a8e014233fe20",
"version": "1.2.3"
}
},
{
"package": "Nimble",
"repositoryURL": "https://github.com/Quick/Nimble.git",
Expand Down Expand Up @@ -109,6 +100,15 @@
"version": "0.11.0"
}
},
{
"package": "StencilSwiftKit",
"repositoryURL": "https://github.com/SwiftGen/StencilSwiftKit.git",
"state": {
"branch": null,
"revision": "f15c445ec3c7c5ad44814285e828330bc255bda3",
"version": "2.5.0"
}
},
{
"package": "SWXMLHash",
"repositoryURL": "https://github.com/drmohundro/SWXMLHash.git",
Expand Down
14 changes: 5 additions & 9 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,16 @@
import PackageDescription

let package = Package(
name: "WeaverDI",
products: [
.library(name: "WeaverDI", targets: ["WeaverDI"])
],
name: "Weaver",
dependencies: [
.package(url: "https://github.com/jpsim/SourceKitten.git", from: "0.21.0"),
.package(url: "https://github.com/kylef/Commander.git", from: "0.6.0"),
.package(url: "https://github.com/kylef/Stencil.git", from: "0.11.0")
.package(url: "https://github.com/kylef/Stencil.git", from: "0.11.0"),
.package(url: "https://github.com/SwiftGen/StencilSwiftKit.git", from: "2.4.0")
],
targets: [
.target(name: "WeaverDI"),
.testTarget(name: "WeaverDITests", dependencies: ["WeaverDI"]),
.target(name: "WeaverCodeGen", dependencies: ["SourceKittenFramework", "Stencil", "WeaverDI"]),
.target(name: "WeaverCodeGen", dependencies: ["SourceKittenFramework", "Stencil", "StencilSwiftKit"]),
.testTarget(name: "WeaverCodeGenTests", dependencies: ["WeaverCodeGen"]),
.target(name: "WeaverCommand", dependencies: ["Commander", "WeaverCodeGen"])
]
)
)
54 changes: 11 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,59 +35,30 @@ Weaver is a declarative, easy-to-use and safe Dependency Injection framework for

- **Declarative** because it allows developers to **declare dependencies via annotations** directly in the Swift code.
- **Easy-to-use** because it **generates the necessary boilerplate code** to inject dependencies into Swift types.
- **Safe** because it **validates the dependency graph at compile time** and outputs a nice Xcode error when something's wrong.
- **Safe** because **it's all happening at compile time**. If it compiles, it works.

## How does Weaver work?

Even though Weaver makes dependency injection work out of the box, it's important to know what it does under the hood. There are two phases to be aware of; compile time and run time.

### At compile time

```
|-> link() -> dependency graph -> validate() -> valid/invalid
swift files -> scan() -> [Token] -> parse() -> AST -|
|-> generate() -> source code
|-> validate() -> valid/invalid
swift files -> scan() -> [Token] -> parse() -> AST -> link() -> Graph -> |
|-> generate() -> source code
```

Weaver's command line tool scans the Swift sources of the project, looking for annotations, and generates an AST (abstract syntax tree). It uses [SourceKitten](https://github.com/jpsim/SourceKitten) which is backed by Apple's [SourceKit](https://github.com/apple/swift/tree/master/tools/SourceKit), making this step pretty reliable.

This AST is then used to generate a dependency graph on which a bunch of safety checks are performed in order to make sure the code won't crash at run time. It checks for unresolvable dependencies and unsolvable cyclic dependencies. If any issue is found, no code is being generated, which means that the project will fail to compile.

The same AST is also used to generate the boilerplate code. It generates one dependency container per class/struct with injectable dependencies. It also generates a bunch of extensions and protocols in order to make the dependency injection almost transparent for the developer.
Weaver scans the Swift sources of the project, looking for annotations, and generates an AST (abstract syntax tree). It uses [SourceKitten](https://github.com/jpsim/SourceKitten) which is backed by Apple's [SourceKit](https://github.com/apple/swift/tree/master/tools/SourceKit), making this step pretty reliable.

### At run time
Then this AST goes through a linking phase, which generates a dependency graph.

Weaver implements a lightweight DI Container object which is able to register and resolve dependencies based on their scope, protocol or concrete type, name and parameters. Each container can have a parent, allowing to resolve dependencies throughout a hierarchy of containers.
A bunch of safety checks are then performed on the dependency graph. It checks for unresolvable dependencies and unsolvable cyclic dependencies. Issues are friendly reported in XCode to make their correction easier.

When an object registers a dependency, its associated DI Container stores a builder (and sometimes an instance). When another object declares a reference to this same dependency, its associated DI Container declares an accessor, which tries to resolve the dependency. Resolving a dependency basically means to look for a builder/instance while backtracking the hierarchy of containers. If no dependency is found or if this process gets trapped into an infinite recursion, it will crash at runtime, which is why checking the dependency graph at compile time is extremely important.
Finally, the same dependency graph is used to generate the boilerplate code. It generates one dependency container per class/struct with injectable dependencies. It also generates a bunch of extensions and protocols in order to make the dependency injection almost transparent for the developer.

## Installation

Weaver comes in 3 parts:
1. A Swift framework to include into your project
2. A command line tool to install on your machine
3. A build phase to add to your project

### (1) - Weaver framework installation

Weaver's Swift framework is available with `CocoaPods`, `Carthage` and `Swift Package Manager`.

#### CocoaPods
### (1) - Weaver command

Add `pod 'WeaverDI', '~> 0.9.12'` to the `Podfile`.

#### Carthage

Add `github "scribd/Weaver" ~> 0.9.12` to the `Cartfile`.

#### SwiftPM

Add `.package(url: "https://github.com/scribd/Weaver.git", from: "0.9.12")` to the dependencies section of the `Package.swift` file.

### (2) - Weaver command line tool installation

The Weaver command line tool can be installed using `Homebrew` or manually.
The Weaver can be installed using `Homebrew` or manually.

#### Binary form

Expand Down Expand Up @@ -126,10 +97,9 @@ Arguments:
Options:
--output_path [default: .] - Where the swift files will be generated.
--template_path - Custom template path.
--unsafe [default: false]
```

### (3) - Weaver build phase
### (2) - Weaver build phase

In Xcode, add the following command to a command line build phase:

Expand All @@ -139,8 +109,6 @@ weaver --output_path ${SOURCE_ROOT}/output/path `find ${SOURCE_ROOT} -name '*.sw

**Important - Move this build phase above the `Compile Source` phase so Weaver can generate the boilerplate code before compilation happens.**

**Warning - Using `--unsafe` is not recommended. It will deactivate the graph validation, meaning the generated code could crash if the dependency graph is invalid.** Only set it to false if the graph validation prevents the project from compiling even though it should not. If you find yourself in that situation, please, feel free to file a bug.

## Basic Usage

*For a more complete usage example, please check out the [sample project](./Sample).*
Expand Down
Loading

0 comments on commit d5e9818

Please sign in to comment.