From f78b4b238b39e57bdde6994e58ca6608320fd861 Mon Sep 17 00:00:00 2001 From: David Jennes Date: Wed, 16 Aug 2017 23:34:50 +0200 Subject: [PATCH 1/4] add basename filter --- Sources/Environment.swift | 11 ++++++----- Sources/Filters+Strings.swift | 10 ++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Sources/Environment.swift b/Sources/Environment.swift index 209ceb80..35f4ff32 100644 --- a/Sources/Environment.swift +++ b/Sources/Environment.swift @@ -13,19 +13,20 @@ public extension Extension { registerTag("call", parser: CallNode.parse) registerTag("map", parser: MapNode.parse) + registerFilter("basename", filter: Filters.Strings.basename) registerFilter("camelToSnakeCase", filter: Filters.Strings.camelToSnakeCase) + registerFilter("contains", filter: Filters.Strings.contains) registerFilter("escapeReservedKeywords", filter: Filters.Strings.escapeReservedKeywords) + registerFilter("hasPrefix", filter: Filters.Strings.hasPrefix) + registerFilter("hasSuffix", filter: Filters.Strings.hasSuffix) + registerFilter("lowerFirstLetter", filter: Filters.Strings.lowerFirstLetter) registerFilter("lowerFirstWord", filter: Filters.Strings.lowerFirstWord) registerFilter("removeNewlines", filter: Filters.Strings.removeNewlines) + registerFilter("replace", filter: Filters.Strings.replace) registerFilter("snakeToCamelCase", filter: Filters.Strings.snakeToCamelCase) registerFilter("swiftIdentifier", filter: Filters.Strings.swiftIdentifier) registerFilter("titlecase", filter: Filters.Strings.upperFirstLetter) registerFilter("upperFirstLetter", filter: Filters.Strings.upperFirstLetter) - registerFilter("lowerFirstLetter", filter: Filters.Strings.lowerFirstLetter) - registerFilter("contains", filter: Filters.Strings.contains) - registerFilter("hasPrefix", filter: Filters.Strings.hasPrefix) - registerFilter("hasSuffix", filter: Filters.Strings.hasSuffix) - registerFilter("replace", filter: Filters.Strings.replace) registerFilter("hexToInt", filter: Filters.Numbers.hexToInt) registerFilter("int255toFloat", filter: Filters.Numbers.int255toFloat) diff --git a/Sources/Filters+Strings.swift b/Sources/Filters+Strings.swift index ea818a29..61daada8 100644 --- a/Sources/Filters+Strings.swift +++ b/Sources/Filters+Strings.swift @@ -226,6 +226,16 @@ extension Filters { return string.hasSuffix(suffix) } + /// Converts a file path to just the filename, stripping any path components before it. + /// + /// - Parameter value: the value to be processed + /// - Returns: the basename of the path + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string + static func basename(_ value: Any?) throws -> Any? { + guard let string = value as? String else { throw Filters.Error.invalidInputType } + return (string as NSString).lastPathComponent + } + // MARK: - Private methods private static func removeLeadingWhitespaces(from string: String) -> String { From 1cc779d8760dd86b1207be37efe53123c9883083 Mon Sep 17 00:00:00 2001 From: David Jennes Date: Wed, 16 Aug 2017 23:42:08 +0200 Subject: [PATCH 2/4] add tests --- .../StencilSwiftKitTests/StringFiltersTests.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Tests/StencilSwiftKitTests/StringFiltersTests.swift b/Tests/StencilSwiftKitTests/StringFiltersTests.swift index 63dbd8ab..8d84870e 100644 --- a/Tests/StencilSwiftKitTests/StringFiltersTests.swift +++ b/Tests/StencilSwiftKitTests/StringFiltersTests.swift @@ -467,3 +467,18 @@ extension StringFiltersTests { } } } + +extension StringFiltersTests { + func testBasename() throws { + let expectations = [ + "test.jpg": "test.jpg", + "some/folder/test.jpg": "test.jpg", + "weird.name.here": "weird.name.here" + ] + + for (input, expected) in expectations { + let result = try Filters.Strings.basename(input) as? String + XCTAssertEqual(result, expected) + } + } +} From a76ad12ca0b46bbb0e4ad55d332d1ba00fb7cd3c Mon Sep 17 00:00:00 2001 From: David Jennes Date: Wed, 16 Aug 2017 23:51:31 +0200 Subject: [PATCH 3/4] add documentation & changelog entry --- CHANGELOG.md | 4 +- Documentation/filters-strings.md | 104 +++++++++++++++++-------------- README.md | 7 ++- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e97d07a..adcb58e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,9 @@ _None_ ### New Features -_None_ +* Added a `basename` string filter for getting a filename out of a path. + [David Jennes](https://github.com/djbe) + [#60](https://github.com/SwiftGen/StencilSwiftKit/pull/60) ### Internal Changes diff --git a/Documentation/filters-strings.md b/Documentation/filters-strings.md index 294254aa..2fccca0d 100644 --- a/Documentation/filters-strings.md +++ b/Documentation/filters-strings.md @@ -2,6 +2,16 @@ This is a list of filters that are added by StencilSwiftKit on top of the filters already provided by Stencil (which you can [find here](http://stencil.fuller.li/en/latest/builtins.html#built-in-filters)). +## Filter: `basename` + +Get the last component of a path, essentially the filename (and extension). + +| Input | Output | +|------------------------|----------------| +| `test.jpg` | `test.jpg` | +| `some/folder/test.jpg` | `test.jpg` | +| `file.txt.png` | `file.txt.png` | + ## Filter: `camelToSnakeCase` Transforms text from camelCase to snake_case. @@ -25,6 +35,15 @@ By default it converts to lower case, unless a single optional argument is set t | `URLChooser` | `URL_Chooser` | | `PLEASE_STOP_SCREAMING!` | `PLEASE_STOP_SCREAMING!` | +## Filter: `contains` + +Checks if the string contains given substring - works the same as Swift's `String.contains`. + +| Input | Output | +|-------------------|-----------------| +| `Hello` `el` | true | +| `Hi mates!` `yo` | false | + ## Filter: `escapeReservedKeywords` Checks if the given string matches a reserved Swift keyword. If it does, wrap the string in escape characters (backticks). @@ -35,6 +54,34 @@ Checks if the given string matches a reserved Swift keyword. If it does, wrap th | `self` | `` `self` `` | | `Any` | `` `Any` `` | +## Filter: `hasPrefix` + +Checks if the string has the given prefix - works the same as Swift's `String.hasPrefix`. + +| Input | Output | +|-------------------|-----------------| +| `Hello` `Hi` | false | +| `Hi mates!` `H` | true | + +## Filter: `hasSuffix` + +Checks if the string has the given suffix - works the same as Swift's `String.hasSuffix`. + +| Input | Output | +|-------------------|-----------------| +| `Hello` `llo` | true | +| `Hi mates!` `?` | false | + +## Filter: `lowerFirstLetter` + +Simply lowercases the first character, leaving the other characters untouched. + +| Input | Output | +|-----------------|-----------------| +| `Hello` | `hello` | +| `PeopleChooser` | `peopleChooser` | +| `Hi There!` | `hi There!` | + ## Filter: `lowerFirstWord` Transforms an arbitrary string so that only the first "word" is lowercased. @@ -71,6 +118,16 @@ This filter has a couple of modes that you can specifiy using an optional argume | `test, \ntest, \ntest` | `test, test, test` | | ` test test ` | `test test` | +## Filter: `replace` + +Replaces the given substring with the given replacement in the source string. +Works the same as Swift's `String.replacingOccurrences`. + +| Input | Output | +|-------------------|-----------------| +| `Hello` `l` `k` | `Hekko` | +| `Europe` `e` `a` | `Europa` | + ## Filter: `snakeToCamelCase` Transforms a string in "snake_case" format into one in "camelCase" format, following the steps below: @@ -128,50 +185,3 @@ Note that even if very similar, this filter differs from the `capitalized` filte |-----------------|-----------------| | `hello` | `Hello` | | `peopleChooser` | `PeopleChooser` | - -## Filter: `lowerFirstLetter` - -Simply lowercases the first character, leaving the other characters untouched. - -| Input | Output | -|-----------------|-----------------| -| `Hello` | `hello` | -| `PeopleChooser` | `peopleChooser` | -| `Hi There!` | `hi There!` | - -## Filter: `contains` - -Checks if the string contains given substring - works the same as Swift's `String.contains`. - -| Input | Output | -|-------------------|-----------------| -| `Hello` `el` | true | -| `Hi mates!` `yo` | false | - -## Filter: `hasPrefix` - -Checks if the string has the given prefix - works the same as Swift's `String.hasPrefix`. - -| Input | Output | -|-------------------|-----------------| -| `Hello` `Hi` | false | -| `Hi mates!` `H` | true | - -## Filter: `hasSuffix` - -Checks if the string has the given suffix - works the same as Swift's `String.hasSuffix`. - -| Input | Output | -|-------------------|-----------------| -| `Hello` `llo` | true | -| `Hi mates!` `?` | false | - -## Filter: `replace` - -Replaces the given substring with the given replacement in the source string. -Works the same as Swift's `String.replacingOccurrences`. - -| Input | Output | -|-------------------|-----------------| -| `Hello` `l` `k` | `Hekko` | -| `Europe` `e` `a` | `Europa` | diff --git a/README.md b/README.md index 9dce0496..e28d6ac3 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,18 @@ ## Filters * [String filters](Documentation/filters-strings.md): + * `basename`: Get the filename from a path. * `camelToSnakeCase`: Transforms text from camelCase to snake_case. By default it converts to lower case, unless a single optional argument is set to "false", "no" or "0". + * `contains`: Check if a string contains a specific substring. * `escapeReservedKeywords`: Escape keywords reserved in the Swift language, by wrapping them inside backticks so that the can be used as regular escape keywords in Swift code. + * `hasPrefix` / `hasSuffix`: Check if a string starts/ends with a specific substring. + * `lowerFirstLetter`: Lowercases only the first letter of a string. * `lowerFirstWord`: Lowercases only the first word of a string. * `removeNewlines`: Removes newlines and other whitespace characters, depending on the mode ("all" or "leading"). + * `replace`: Replaces instances of a substring with a new string. * `snakeToCamelCase`: Transforms text from snake_case to camelCase. By default it keeps leading underscores, unless a single optional argument is set to "true", "yes" or "1". * `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) - * `titlecase`: Uppercases only the first character + * `upperFirstLetter`: Uppercases only the first character * [Number filters](Documentation/filters-numbers.md): * `int255toFloat` * `hexToInt` From ba1ce56899c466522862f66bf5993ea3fe22c6ca Mon Sep 17 00:00:00 2001 From: David Jennes Date: Thu, 17 Aug 2017 11:45:41 +0200 Subject: [PATCH 4/4] add dirname filter --- CHANGELOG.md | 2 +- Documentation/filters-strings.md | 10 +++++++ README.md | 1 + Sources/Environment.swift | 1 + Sources/Filters+Strings.swift | 10 +++++++ .../StringFiltersTests.swift | 26 ++++++++++++++++--- 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adcb58e7..9e3de202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ _None_ ### New Features -* Added a `basename` string filter for getting a filename out of a path. +* Added the `basename` and `dirname` string filters for getting a filename, or parent folder (respectively), out of a path. [David Jennes](https://github.com/djbe) [#60](https://github.com/SwiftGen/StencilSwiftKit/pull/60) diff --git a/Documentation/filters-strings.md b/Documentation/filters-strings.md index 2fccca0d..194408ff 100644 --- a/Documentation/filters-strings.md +++ b/Documentation/filters-strings.md @@ -44,6 +44,16 @@ Checks if the string contains given substring - works the same as Swift's `Strin | `Hello` `el` | true | | `Hi mates!` `yo` | false | +## Filter: `dirname` + +Remove the last component of a path, essentially returning the path without the filename (and extension). + +| Input | Output | +|------------------------|---------------| +| `test.jpg` | `` | +| `some/folder/test.jpg` | `some/folder` | +| `file.txt.png` | `` | + ## Filter: `escapeReservedKeywords` Checks if the given string matches a reserved Swift keyword. If it does, wrap the string in escape characters (backticks). diff --git a/README.md b/README.md index e28d6ac3..32d78fc6 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ * `basename`: Get the filename from a path. * `camelToSnakeCase`: Transforms text from camelCase to snake_case. By default it converts to lower case, unless a single optional argument is set to "false", "no" or "0". * `contains`: Check if a string contains a specific substring. + * `dirname`: Get the path to the parent folder from a path. * `escapeReservedKeywords`: Escape keywords reserved in the Swift language, by wrapping them inside backticks so that the can be used as regular escape keywords in Swift code. * `hasPrefix` / `hasSuffix`: Check if a string starts/ends with a specific substring. * `lowerFirstLetter`: Lowercases only the first letter of a string. diff --git a/Sources/Environment.swift b/Sources/Environment.swift index 35f4ff32..2df9258b 100644 --- a/Sources/Environment.swift +++ b/Sources/Environment.swift @@ -16,6 +16,7 @@ public extension Extension { registerFilter("basename", filter: Filters.Strings.basename) registerFilter("camelToSnakeCase", filter: Filters.Strings.camelToSnakeCase) registerFilter("contains", filter: Filters.Strings.contains) + registerFilter("dirname", filter: Filters.Strings.dirname) registerFilter("escapeReservedKeywords", filter: Filters.Strings.escapeReservedKeywords) registerFilter("hasPrefix", filter: Filters.Strings.hasPrefix) registerFilter("hasSuffix", filter: Filters.Strings.hasSuffix) diff --git a/Sources/Filters+Strings.swift b/Sources/Filters+Strings.swift index 61daada8..a6133dbc 100644 --- a/Sources/Filters+Strings.swift +++ b/Sources/Filters+Strings.swift @@ -236,6 +236,16 @@ extension Filters { return (string as NSString).lastPathComponent } + /// Converts a file path to just the path without the filename. + /// + /// - Parameter value: the value to be processed + /// - Returns: the dirname of the path + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string + static func dirname(_ value: Any?) throws -> Any? { + guard let string = value as? String else { throw Filters.Error.invalidInputType } + return (string as NSString).deletingLastPathComponent + } + // MARK: - Private methods private static func removeLeadingWhitespaces(from string: String) -> String { diff --git a/Tests/StencilSwiftKitTests/StringFiltersTests.swift b/Tests/StencilSwiftKitTests/StringFiltersTests.swift index 8d84870e..caafecba 100644 --- a/Tests/StencilSwiftKitTests/StringFiltersTests.swift +++ b/Tests/StencilSwiftKitTests/StringFiltersTests.swift @@ -471,9 +471,11 @@ extension StringFiltersTests { extension StringFiltersTests { func testBasename() throws { let expectations = [ - "test.jpg": "test.jpg", - "some/folder/test.jpg": "test.jpg", - "weird.name.here": "weird.name.here" + "/tmp/scratch.tiff": "scratch.tiff", + "/tmp/scratch": "scratch", + "/tmp/": "tmp", + "scratch///": "scratch", + "/": "/" ] for (input, expected) in expectations { @@ -482,3 +484,21 @@ extension StringFiltersTests { } } } + +extension StringFiltersTests { + func testDirname() throws { + let expectations = [ + "/tmp/scratch.tiff": "/tmp", + "/tmp/lock/": "/tmp", + "/tmp/": "/", + "/tmp": "/", + "/": "/", + "scratch.tiff": "" + ] + + for (input, expected) in expectations { + let result = try Filters.Strings.dirname(input) as? String + XCTAssertEqual(result, expected) + } + } +}