-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow using collection accessors on strings #245
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs documentation update.
Sources/Variable.swift
Outdated
@@ -100,6 +100,20 @@ public struct Variable : Equatable, Resolvable { | |||
} else if bit == "count" { | |||
current = array.count | |||
} | |||
} else if let string = current as? String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why repeat this whole else if
branch, if you can just use the if branch above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to reuse it but you can't interchangeably use [Any]
and String
, using available collections type erasures causes other issues like accessing via subscript
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could use string.character
but it will give deprecation warning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about extracting the branch into something like func resolve<T: RandomAccessCollection>(items: T, bit: String) {
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this will probably work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick test in playgrounds:
func resolve<T: Collection>(items: T, bit: String) -> Any? {
if let index = Int(bit) {
if index >= 0 && index < items.count {
return items[items.index(items.startIndex, offsetBy: index)]
} else {
return nil
}
} else if bit == "first" {
return items.first
} else if bit == "last" {
return items[items.index(items.endIndex, offsetBy: -1)]
} else if bit == "count" {
return items.count
} else {
return nil
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good 👍, still needs the documentation update.
CHANGELOG.md
Outdated
@@ -26,6 +26,10 @@ | |||
[Ilya Puchka](https://github.com/ilyapuchka) | |||
[#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 }}` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing the .
at the end here.
} else if bit == "count" { | ||
current = array.count | ||
} | ||
current = resolveCollection(array, bit: bit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be worth changing the test to just if let collection = current as? Collection {
, or would that be too broad of a cast?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Collection
is a generic protocol so can't be used like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right 🤦♂️
Sources/Variable.swift
Outdated
@@ -75,6 +75,24 @@ public struct Variable : Equatable, Resolvable { | |||
return bool | |||
} | |||
|
|||
func resolveCollection<T: Collection>(_ collection: T, bit: String) -> Any? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd actually move this out of the body of resolve(
, I'm preparing another PR that adds swiftlint, and this will only worsen the situation. Maybe just a private func
right after this function?
Sources/Variable.swift
Outdated
@@ -136,6 +118,24 @@ public struct Variable : Equatable, Resolvable { | |||
} | |||
} | |||
|
|||
fileprivate func resolveCollection<T: Collection>(_ collection: T, bit: String) -> Any? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're in the same type (Variable
), so private
is enough, fileprivate
is for accessing from other types.
@djbe updated |
In the docs, I'd change (https://github.com/stencilproject/Stencil/blob/master/docs/templates.rst#variables):
To
|
No description provided.