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

Added StringFilters.camelToSnakeCase filter #24

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ _TODO: [Write more extension Documentation](https://github.com/SwiftGen/StencilS
* `swiftIdentifier`: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference)
* `join`: Deprecated. Will be removed now that the same filter exists in Stencil proper.
* `lowerFirstWord`
* `snakeToCamelCase` / `snakeToCamelCaseNoPrefix`
* `snakeToCamelCase` / `snakeToCamelCaseNoPrefix` / `camelToSnakeCase`
* `titlecase`
* `hexToInt`
* `int255toFloat`
Expand Down
1 change: 1 addition & 0 deletions Sources/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public extension Extension {
registerFilter("lowerFirstWord", filter: StringFilters.lowerFirstWord)
registerFilter("snakeToCamelCase", filter: StringFilters.snakeToCamelCase)
registerFilter("snakeToCamelCaseNoPrefix", filter: StringFilters.snakeToCamelCaseNoPrefix)
registerFilter("camelToSnakeCase", filter: StringFilters.camelToSnakeCase)
registerFilter("titlecase", filter: StringFilters.titlecase)
registerFilter("hexToInt", filter: NumFilters.hexToInt)
registerFilter("int255toFloat", filter: NumFilters.int255toFloat)
Expand Down
5 changes: 5 additions & 0 deletions Sources/Filters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ struct StringFilters {
}
}

static func camelToSnakeCase(_ value: Any?) throws -> Any? {
guard let string = value as? String else { throw FilterError.invalidInputType }
return try snakecase(string).lowercased()
Copy link
Member

Choose a reason for hiding this comment

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

Is this to avoid URLChooser --> URL_Chooser?

Copy link
Member

Choose a reason for hiding this comment

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

According to https://en.wikipedia.org/wiki/Snake_case, Hello_world is valid output. No idea if that's what we want though.

Copy link
Author

Choose a reason for hiding this comment

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

Hmm, don't think I've ever seen snake case with caps. The scenario I'm trying to get to is auto-generating json_field_names from camelCase, which tend to be all lower case.

Should I break it out into two different ones? camelToSnakeCase and camelToLowerSnakeCase? Or does Stencil already provides a way to combine something like this: {{ "someTextHere"|camelToSnakeCase|lowercase }}?

Copy link
Member

@djbe djbe Feb 24, 2017

Choose a reason for hiding this comment

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

I haven't seen it either, I was just wondering what the correct / default behaviour should be. Looking at some libraries in other languages, the default seems to be lowercase, so let's do that 👍

You could always add a parameter to the filter to disable the lowercasing (see for example the stencil join filter http://stencil.fuller.li/en/latest/builtins.html#built-in-filters).

Copy link
Author

Choose a reason for hiding this comment

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

Unfortunately the Wikipedia page doesn't give any definitive rules for upper snake case. For instance, as the StringFilter.snakecase() function is currently written, URLChooser becomes URL_Chooser, not Url_Chooser. I couldn't really find anything that said that'd be right or wrong, so I think for now I'll just stick with that implementation. The filter itself will take one optional boolean parameter for lowercasing, defaults to true.

}

/**
This returns the string with its first parameter uppercased.
- note: This is quite similar to `capitalise` except that this filter doesn't lowercase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForRunning = "YES"
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason this was changed? I don't think it does much.

Copy link
Author

@ggrell ggrell Feb 26, 2017

Choose a reason for hiding this comment

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

Ah, probably AppCode made the change since I was running unit tests. Will revert.

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems to still be there?

Copy link
Author

Choose a reason for hiding this comment

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

Will fix, I must have checked it in inadvertently again

buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
Expand Down
33 changes: 33 additions & 0 deletions Tests/StencilSwiftKitTests/StringFiltersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,39 @@ class StringFiltersTests: XCTestCase {
}
}

func testCamelToSnakeCase() {
let expectations = [
"string": "string",
Copy link
Contributor

Choose a reason for hiding this comment

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

A little nitpicking, but could you ensure the indentation you use is consistent with the rest of the project? Thx
(Here even in your own code you have different indentation levels)

"String": "string",
"strIng": "str_ing",
"strING": "str_ing",
"X": "x",
"x": "x",
"SomeCapString": "some_cap_string",
"someCapString": "some_cap_string",
"string_with_words": "string_with_words",
"String_with_words": "string_with_words",
"String_With_Words": "string_with_words",
"String_With_WoRds": "string_with_wo_rds",
"STRing_with_words": "st_ring_with_words",
"string_wiTH_WOrds": "string_wi_th_w_ords",
"": "",
"URLChooser": "url_chooser",
"UrlChooser": "url_chooser",
"a__b__c": "a__b__c",
"__y_z!": "__y_z!",
"PLEASESTOPSCREAMING": "pleasestopscreaming",
"PLEASESTOPSCREAMING!": "pleasestopscreaming!",
"PLEASE_STOP_SCREAMING": "please_stop_screaming",
"PLEASE_STOP_SCREAMING!": "please_stop_screaming!"
]

for (input, expected) in expectations {
let result = try! StringFilters.camelToSnakeCase(input) as? String
XCTAssertEqual(result, expected)
}
}

func testEscapeReservedKeywords() {
let expectations = [
"self": "`self`",
Expand Down