Allow using collection accessors on strings (#245)
* allow using collection accessors on strings * refactored resolving collection accessors * refactored to fileprivate function * Update Variable.swift * Update templates.rst
This commit is contained in:
@@ -26,6 +26,10 @@
|
|||||||
[Ilya Puchka](https://github.com/ilyapuchka)
|
[Ilya Puchka](https://github.com/ilyapuchka)
|
||||||
[#243](https://github.com/stencilproject/Stencil/pull/243)
|
[#243](https://github.com/stencilproject/Stencil/pull/243)
|
||||||
|
|
||||||
|
- Now you can access string characters by index or get string length the same was as if it was an array, i.e. `{{ 'string'.first }}`, `{{ 'string'.last }}`, `{{ 'string'.1 }}`, `{{ 'string'.count }}`.
|
||||||
|
[Ilya Puchka](https://github.com/ilyapuchka)
|
||||||
|
[#245](https://github.com/stencilproject/Stencil/pull/245)
|
||||||
|
|
||||||
### Internal Changes
|
### Internal Changes
|
||||||
|
|
||||||
- Updated the codebase to use Swift 4 features.
|
- Updated the codebase to use Swift 4 features.
|
||||||
|
|||||||
@@ -87,19 +87,9 @@ public struct Variable : Equatable, Resolvable {
|
|||||||
current = dictionary[bit]
|
current = dictionary[bit]
|
||||||
}
|
}
|
||||||
} else if let array = current as? [Any] {
|
} else if let array = current as? [Any] {
|
||||||
if let index = Int(bit) {
|
current = resolveCollection(array, bit: bit)
|
||||||
if index >= 0 && index < array.count {
|
} else if let string = current as? String {
|
||||||
current = array[index]
|
current = resolveCollection(string, bit: bit)
|
||||||
} else {
|
|
||||||
current = nil
|
|
||||||
}
|
|
||||||
} else if bit == "first" {
|
|
||||||
current = array.first
|
|
||||||
} else if bit == "last" {
|
|
||||||
current = array.last
|
|
||||||
} else if bit == "count" {
|
|
||||||
current = array.count
|
|
||||||
}
|
|
||||||
} else if let object = current as? NSObject { // NSKeyValueCoding
|
} else if let object = current as? NSObject { // NSKeyValueCoding
|
||||||
#if os(Linux)
|
#if os(Linux)
|
||||||
return nil
|
return nil
|
||||||
@@ -128,6 +118,24 @@ public struct Variable : Equatable, Resolvable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func resolveCollection<T: Collection>(_ collection: T, bit: String) -> Any? {
|
||||||
|
if let index = Int(bit) {
|
||||||
|
if index >= 0 && index < collection.count {
|
||||||
|
return collection[collection.index(collection.startIndex, offsetBy: index)]
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else if bit == "first" {
|
||||||
|
return collection.first
|
||||||
|
} else if bit == "last" {
|
||||||
|
return collection[collection.index(collection.endIndex, offsetBy: -1)]
|
||||||
|
} else if bit == "count" {
|
||||||
|
return collection.count
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A structure used to represet range of two integer values expressed as `from...to`.
|
/// A structure used to represet range of two integer values expressed as `from...to`.
|
||||||
/// Values should be numbers (they will be converted to integers).
|
/// Values should be numbers (they will be converted to integers).
|
||||||
/// Rendering this variable produces array from range `from...to`.
|
/// Rendering this variable produces array from range `from...to`.
|
||||||
|
|||||||
@@ -86,42 +86,98 @@ func testVariable() {
|
|||||||
try expect(result) == "Kyle"
|
try expect(result) == "Kyle"
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can resolve an item from a dictionary") {
|
$0.context("given string") {
|
||||||
let variable = Variable("profiles.github")
|
$0.it("can resolve an item via it's index") {
|
||||||
let result = try variable.resolve(context) as? String
|
let variable = Variable("name.0")
|
||||||
try expect(result) == "kylef"
|
let result = try variable.resolve(context) as? Character
|
||||||
|
try expect(result) == "K"
|
||||||
|
|
||||||
|
let variable1 = Variable("name.1")
|
||||||
|
let result1 = try variable1.resolve(context) as? Character
|
||||||
|
try expect(result1) == "y"
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("can resolve an item via unknown index") {
|
||||||
|
let variable = Variable("name.5")
|
||||||
|
let result = try variable.resolve(context) as? Character
|
||||||
|
try expect(result).to.beNil()
|
||||||
|
|
||||||
|
let variable1 = Variable("name.-5")
|
||||||
|
let result1 = try variable1.resolve(context) as? Character
|
||||||
|
try expect(result1).to.beNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("can resolve the first item") {
|
||||||
|
let variable = Variable("name.first")
|
||||||
|
let result = try variable.resolve(context) as? Character
|
||||||
|
try expect(result) == "K"
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("can resolve the last item") {
|
||||||
|
let variable = Variable("name.last")
|
||||||
|
let result = try variable.resolve(context) as? Character
|
||||||
|
try expect(result) == "e"
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("can get the characters count") {
|
||||||
|
let variable = Variable("name.count")
|
||||||
|
let result = try variable.resolve(context) as? Int
|
||||||
|
try expect(result) == 4
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can resolve an item from an array via it's index") {
|
$0.context("given dictionary") {
|
||||||
let variable = Variable("contacts.0")
|
$0.it("can resolve an item") {
|
||||||
let result = try variable.resolve(context) as? String
|
let variable = Variable("profiles.github")
|
||||||
try expect(result) == "Katie"
|
let result = try variable.resolve(context) as? String
|
||||||
|
try expect(result) == "kylef"
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("can get the count") {
|
||||||
|
let variable = Variable("profiles.count")
|
||||||
|
let result = try variable.resolve(context) as? Int
|
||||||
|
try expect(result) == 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.context("given array") {
|
||||||
|
$0.it("can resolve an item via it's index") {
|
||||||
|
let variable = Variable("contacts.0")
|
||||||
|
let result = try variable.resolve(context) as? String
|
||||||
|
try expect(result) == "Katie"
|
||||||
|
|
||||||
let variable1 = Variable("contacts.1")
|
let variable1 = Variable("contacts.1")
|
||||||
let result1 = try variable1.resolve(context) as? String
|
let result1 = try variable1.resolve(context) as? String
|
||||||
try expect(result1) == "Carlton"
|
try expect(result1) == "Carlton"
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can resolve an item from an array via unknown index") {
|
$0.it("can resolve an item via unknown index") {
|
||||||
let variable = Variable("contacts.5")
|
let variable = Variable("contacts.5")
|
||||||
let result = try variable.resolve(context) as? String
|
let result = try variable.resolve(context) as? String
|
||||||
try expect(result).to.beNil()
|
try expect(result).to.beNil()
|
||||||
|
|
||||||
let variable1 = Variable("contacts.-5")
|
let variable1 = Variable("contacts.-5")
|
||||||
let result1 = try variable1.resolve(context) as? String
|
let result1 = try variable1.resolve(context) as? String
|
||||||
try expect(result1).to.beNil()
|
try expect(result1).to.beNil()
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can resolve the first item from an array") {
|
$0.it("can resolve the first item") {
|
||||||
let variable = Variable("contacts.first")
|
let variable = Variable("contacts.first")
|
||||||
let result = try variable.resolve(context) as? String
|
let result = try variable.resolve(context) as? String
|
||||||
try expect(result) == "Katie"
|
try expect(result) == "Katie"
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can resolve the last item from an array") {
|
$0.it("can resolve the last item") {
|
||||||
let variable = Variable("contacts.last")
|
let variable = Variable("contacts.last")
|
||||||
let result = try variable.resolve(context) as? String
|
let result = try variable.resolve(context) as? String
|
||||||
try expect(result) == "Carlton"
|
try expect(result) == "Carlton"
|
||||||
|
}
|
||||||
|
|
||||||
|
$0.it("can get the count") {
|
||||||
|
let variable = Variable("contacts.count")
|
||||||
|
let result = try variable.resolve(context) as? Int
|
||||||
|
try expect(result) == 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can resolve a property with reflection") {
|
$0.it("can resolve a property with reflection") {
|
||||||
@@ -130,12 +186,6 @@ func testVariable() {
|
|||||||
try expect(result) == "Kyle"
|
try expect(result) == "Kyle"
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can get the count of a dictionary") {
|
|
||||||
let variable = Variable("profiles.count")
|
|
||||||
let result = try variable.resolve(context) as? Int
|
|
||||||
try expect(result) == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#if os(OSX)
|
#if os(OSX)
|
||||||
$0.it("can resolve a value via KVO") {
|
$0.it("can resolve a value via KVO") {
|
||||||
let variable = Variable("object.title")
|
let variable = Variable("object.title")
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ following lookup:
|
|||||||
|
|
||||||
- Context lookup
|
- Context lookup
|
||||||
- Dictionary lookup
|
- Dictionary lookup
|
||||||
- Array lookup (first, last, count, index)
|
- Array and string lookup (first, last, count, by index)
|
||||||
- Key value coding lookup
|
- Key value coding lookup
|
||||||
- Type introspection
|
- Type introspection (via ``Mirror``)
|
||||||
|
|
||||||
For example, if `people` was an array:
|
For example, if `people` was an array:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user