-
Notifications
You must be signed in to change notification settings - Fork 316
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
Paywalls
: changed variable handling to use Swift Regex
#2811
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import Foundation | ||
import RegexBuilder | ||
import RevenueCat | ||
|
||
@available(iOS 16.0, macOS 13.0, tvOS 16.0, *) | ||
|
@@ -21,44 +22,51 @@ protocol VariableDataProvider { | |
} | ||
|
||
/// Processes strings, replacing `{{variable}}` with their associated content. | ||
@available(iOS 16.0, macOS 13.0, tvOS 16.0, *) | ||
enum VariableHandler { | ||
|
||
static func processVariables( | ||
in string: String, | ||
with provider: VariableDataProvider | ||
) -> String { | ||
let matches = Self.extractVariables(from: string) | ||
var replacedString = string | ||
let range = NSRange(string.startIndex..., in: string) | ||
let matches = Self.regex.matches(in: string, options: [], range: range) | ||
|
||
for match in matches.reversed() { | ||
let variableNameRange = match.range(at: 1) | ||
if let variableNameRange = Range(variableNameRange, in: string) { | ||
let variableName = String(string[variableNameRange]) | ||
let replacementValue = provider.value(for: variableName) | ||
|
||
let adjustedRange = NSRange( | ||
location: variableNameRange.lowerBound.utf16Offset(in: string) - Self.pattern.count / 2, | ||
length: string.distance(from: variableNameRange.lowerBound, | ||
to: variableNameRange.upperBound) + Self.pattern.count | ||
) | ||
let replacementRange = Range(adjustedRange, in: replacedString)! | ||
|
||
replacedString = replacedString.replacingCharacters(in: replacementRange, with: replacementValue) | ||
} | ||
for variableMatch in matches.reversed() { | ||
let replacementValue = provider.value(for: variableMatch.variable) | ||
replacedString = replacedString.replacingCharacters(in: variableMatch.range, with: replacementValue) | ||
Comment on lines
+36
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So. Much. Simpler. |
||
} | ||
|
||
return replacedString | ||
} | ||
|
||
private static let pattern = "{{ }}" | ||
// Fix-me: this can be implemented using the new Regex from Swift. | ||
// This regex is known at compile time and tested: | ||
// swiftlint:disable:next force_try | ||
private static let regex = try! NSRegularExpression(pattern: "\\{\\{ (\\w+) \\}\\}", options: []) | ||
private static func extractVariables(from expression: String) -> [VariableMatch] { | ||
let variablePattern = Regex { | ||
OneOrMore { | ||
"{{ " | ||
Capture { | ||
aboedo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
OneOrMore(.word) | ||
} | ||
" }}" | ||
} | ||
Comment on lines
+45
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So nice |
||
} | ||
|
||
return expression.matches(of: variablePattern).map { match in | ||
let (_, variable) = match.output | ||
return VariableMatch(variable: String(variable), range: match.range) | ||
Comment on lines
+54
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the neat thing here is that the range is for the full expression, the variable is the content of the |
||
} | ||
} | ||
|
||
private struct VariableMatch { | ||
|
||
let variable: String | ||
let range: Range<String.Index> | ||
|
||
} | ||
|
||
} | ||
|
||
@available(iOS 16.0, macOS 13.0, tvOS 16.0, *) | ||
extension String { | ||
|
||
func processed(with provider: VariableDataProvider) -> Self { | ||
|
@@ -67,6 +75,7 @@ extension String { | |
|
||
} | ||
|
||
@available(iOS 16.0, macOS 13.0, tvOS 16.0, *) | ||
private extension VariableDataProvider { | ||
|
||
func value(for variableName: String) -> 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.
the range comes in for free