Skip to content
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

Merged
merged 5 commits into from
Sep 22, 2018
Merged

Conversation

ilyapuchka
Copy link
Collaborator

No description provided.

Copy link
Contributor

@djbe djbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs documentation update.

@@ -100,6 +100,20 @@ public struct Variable : Equatable, Resolvable {
} else if bit == "count" {
current = array.count
}
} else if let string = current as? String {
Copy link
Contributor

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?

Copy link
Collaborator Author

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

Copy link
Collaborator Author

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

Copy link
Contributor

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) {?

Copy link
Collaborator Author

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

Copy link
Contributor

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
	}
}

Copy link
Contributor

@djbe djbe left a 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 }}`
Copy link
Contributor

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)
Copy link
Contributor

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?

Copy link
Collaborator Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right 🤦‍♂️

@@ -75,6 +75,24 @@ public struct Variable : Equatable, Resolvable {
return bool
}

func resolveCollection<T: Collection>(_ collection: T, bit: String) -> Any? {
Copy link
Contributor

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?

@@ -136,6 +118,24 @@ public struct Variable : Equatable, Resolvable {
}
}

fileprivate func resolveCollection<T: Collection>(_ collection: T, bit: String) -> Any? {
Copy link
Contributor

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.

@ilyapuchka
Copy link
Collaborator Author

@djbe updated

@djbe
Copy link
Contributor

djbe commented Sep 22, 2018

In the docs, I'd change (https://github.com/stencilproject/Stencil/blob/master/docs/templates.rst#variables):

Array lookup (first, last, count, index)

To

Collection lookup (first, last, count, index) for Array and String

@ilyapuchka ilyapuchka merged commit d238c25 into master Sep 22, 2018
@ilyapuchka ilyapuchka deleted the string-accessors branch September 22, 2018 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants