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

Basename / Dirname filters #60

Merged
merged 4 commits into from
Aug 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ _None_

### New Features

_None_
* 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)

### Internal Changes

Expand Down
114 changes: 67 additions & 47 deletions Documentation/filters-strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -25,6 +35,25 @@ 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: `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).
Expand All @@ -35,6 +64,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.
Expand Down Expand Up @@ -71,6 +128,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:
Expand Down Expand Up @@ -128,50 +195,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` |
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,19 @@
## 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.
* `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.
* `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`
Expand Down
12 changes: 7 additions & 5 deletions Sources/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ 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("dirname", filter: Filters.Strings.dirname)
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)
Expand Down
20 changes: 20 additions & 0 deletions Sources/Filters+Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,26 @@ 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
}

/// 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 {
Expand Down
35 changes: 35 additions & 0 deletions Tests/StencilSwiftKitTests/StringFiltersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,38 @@ extension StringFiltersTests {
}
}
}

extension StringFiltersTests {
func testBasename() throws {
let expectations = [
"/tmp/scratch.tiff": "scratch.tiff",
"/tmp/scratch": "scratch",
"/tmp/": "tmp",
"scratch///": "scratch",
"/": "/"
]

for (input, expected) in expectations {
let result = try Filters.Strings.basename(input) as? String
XCTAssertEqual(result, expected)
}
}
}

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