Skip to content
Open
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
77 changes: 48 additions & 29 deletions Cloudinary/Classes/Core/Features/Helpers/CLDExpression.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ import Foundation
case initial_height
case initialHeight

case initial_aspect_ratio
case aspect_ratio
case aspectRatio
case initial_aspect_ratio
case initialAspectRatio

case page_count
Expand Down Expand Up @@ -73,9 +73,9 @@ import Foundation
case .initial_height: return "ih"
case .initialHeight : return "ih"

case .initial_aspect_ratio: return "iar"
case .aspect_ratio : return "ar"
case .aspectRatio : return "ar"
case .initial_aspect_ratio: return "iar"
case .initialAspectRatio : return "iar"

case .page_count: return "pc"
Expand Down Expand Up @@ -104,9 +104,11 @@ import Foundation

internal var currentValue : String
internal var currentKey : String

private let consecutiveDashesRegex: String = "[ _]+"


private var allSpaceAndOrDash : Bool = false
private let consecutiveDashesRegex : String = "[ _]+"
private let userVariableRegex : String = "\\$_*[^_]+"

// MARK: - Init
public override init() {
self.currentKey = String()
Expand All @@ -118,6 +120,9 @@ import Foundation
var components = value.components(separatedBy: .whitespacesAndNewlines)
self.currentKey = components.removeFirst()
self.currentValue = components.joined(separator: CLDVariable.elementsSeparator)
let range = NSRange(location: 0, length: value.utf16.count)
let regex = try? NSRegularExpression(pattern: "^" + consecutiveDashesRegex)
self.allSpaceAndOrDash = !(regex?.firstMatch(in: value, options: [], range: range) == nil)
super.init()
}

Expand Down Expand Up @@ -286,14 +291,19 @@ import Foundation
// MARK: - provide content
public func asString() -> String {

guard !currentKey.isEmpty && !currentValue.isEmpty else {

guard !currentKey.isEmpty else {
if allSpaceAndOrDash {
Copy link
Contributor

Choose a reason for hiding this comment

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

A specific use case of regex expression should not impact the asString() function
This should be handled in the Regex expression and not outside of it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I understood that this is the new requirements (according to Patriks tests)
Meaning if the value contains "allSpaceAndOrDash" then asString() should return "_" otherwise the tests fail.

return "_"
}
return String()
}

let key = replaceAllExpressionKeys(in: currentKey)
let value = removeExtraDashes(from: replaceAllUnencodeChars(in: currentValue))


let key = removeExtraDashes(from: replaceAllExpressionKeys(in: currentKey))

if currentValue.isEmpty {
return "\(key)"
}
let value = removeExtraDashes(from: replaceAllUnencodedChars(in: currentValue))
return "\(key)_\(value)"
}

Expand All @@ -305,7 +315,7 @@ import Foundation
}

let key = replaceAllExpressionKeys(in: currentKey)
let value = removeExtraDashes(from: replaceAllUnencodeChars(in: currentValue))
let value = removeExtraDashes(from: replaceAllUnencodedChars(in: currentValue))

return [key:value]
}
Expand All @@ -320,7 +330,7 @@ import Foundation
}

// MARK: - Private methods
private func replaceAllUnencodeChars(in string: String) -> String {
private func replaceAllUnencodedChars(in string: String) -> String {

var wipString = string
wipString = replaceAllOperators(in: string)
Expand Down Expand Up @@ -353,26 +363,34 @@ import Foundation

return wipString
}

private func replace(expressionKey: ExpressionKeys, in string: String) -> String {

var result : String


var result : String!
let string = removeExtraDashes(from: string)

if string.contains(CLDVariable.variableNamePrefix) {

result = string.components(separatedBy: CLDVariable.elementsSeparator).map({

let temp : String
switch $0.hasPrefix(CLDVariable.variableNamePrefix) {
case true : temp = $0
case false: temp = $0.replacingOccurrences(of: expressionKey.rawValue, with: expressionKey.asString)
let range = NSRange(location: 0, length: string.utf16.count)
let regex = try? NSRegularExpression(pattern: userVariableRegex)
let allRanges = regex?.matches(in: string, options: [], range: range).map({ $0.range }) ?? []

// Replace substring in between user variables. e.x $initial_aspect_ratio_$width, only '_aspect_ratio_' will be addressed.
for (index, range) in allRanges.enumerated() {
let location = range.length + range.location
var length = range.length

if index + 1 == allRanges.count {
length = string.count
} else {
let nextRange = allRanges[index + 1]
length = nextRange.location
}
return temp

}).joined(separator: CLDVariable.elementsSeparator)


if let stringRange = Range(NSRange(location: location, length: length - location), in: string) {
result = string.replacingOccurrences(of: expressionKey.rawValue, with: expressionKey.asString, options: .regularExpression, range: stringRange)
}
}
} else {

result = string.replacingOccurrences(of: expressionKey.rawValue, with: expressionKey.asString)
}
return result
Expand Down Expand Up @@ -404,3 +422,4 @@ import Foundation
return string.replacingOccurrences(of: consecutiveDashesRegex, with: CLDVariable.elementsSeparator, options: .regularExpression, range: nil)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import Foundation
internal var fontWeight: String?
internal var textDecoration: String?
internal var textAlign: String?
internal var textStyle: String?
internal var stroke: String?
internal var letterSpacing: String?
internal var lineSpacing: String?
Expand Down Expand Up @@ -66,6 +67,32 @@ import Foundation
return self
}

/**
Sets a text style identifier.
Note: If this is used, all other style attributes are ignored in favor of this identifier

- parameter text: A variable string or an explicit style (e.g. "Arial_17_bold_antialias_best").

- returns: The same instance of CLDTextLayer.
*/
open func setTextStyle(textStyle: String) -> CLDTextLayer {
self.textStyle = textStyle
return self
}

/**
Sets a text style identifier using an expression.
Note: If this is used, all other style attributes are ignored in favor of this identifier

- parameter text: An expression instance referencing the style.

- returns: The same instance of CLDTextLayer.
*/
open func setTextStyle(expression: CLDExpression) -> CLDTextLayer {
self.textStyle = expression.asString()
return self
}

/**
Set the name of a font family. e.g. `arial`.

Expand Down Expand Up @@ -333,7 +360,10 @@ import Foundation

let optionalTextParams = getOptionalTextPropertiesArray()
let mandatoryTextParams = getMandatoryTextPropertiesArray()
if optionalTextParams.isEmpty {
if let textStyle = textStyle {
components.append([textStyle].joined(separator: "_"))
}
else if optionalTextParams.isEmpty {
if !mandatoryTextParams.isEmpty {
components.append(mandatoryTextParams.joined(separator: "_"))
}
Expand Down
23 changes: 23 additions & 0 deletions Example/Tests/GenerateUrlTests/UrlTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,29 @@ class UrlTests: BaseTestCase {
XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDFetchLayer(url: "https://res.cloudinary.com/demo/image/upload/sample"))).generate("test"),
"\(prefix)/image/upload/l_fetch:aHR0cHM6Ly9yZXMuY2xvdWRpbmFyeS5jb20vZGVtby9pbWFnZS91cGxvYWQvc2FtcGxl/test")
}

func testTextStyle() {
XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVariable("$style", string: "!Arial_12!").chain().setOverlayWithLayer(CLDTextLayer().setText(text: "hello-world").setTextStyle(textStyle: "$style"))).generate("test"), "\(prefix)/image/upload/$style_!Arial_12!/l_text:$style:hello-world/test")

XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVariable("$style", string: "!Arial_12!").chain().setOverlayWithLayer(CLDTextLayer().setText(text: "hello-world").setTextStyle(expression: CLDExpression(value: "$style")))).generate("test"), "\(prefix)/image/upload/$style_!Arial_12!/l_text:$style:hello-world/test")
}

func testTextStyleOverpowerOtherTextAttributes() {
let layer = CLDTextLayer()
.setText(text: "hello_world")
.setFontFamily(fontFamily: "Arial")
.setFontSize(18)
.setFontStyle(.italic)
.setFontWeight(.bold)
.setLetterSpacing(4)
.setTextStyle(textStyle: "$style")

let transformation = CLDTransformation().setVariable("$style", string: "!Arial_12!").chain().setOverlayWithLayer(layer)
let url = sut?.createUrl().setTransformation(transformation).generate("test")

XCTAssertNotNil(url)
XCTAssertFalse(url!.contains("Arial_18_bold_italic_letter_spacing_4"), "$style should overpower other text attributes.")
}

func testOverlayErrors() {
XCTAssertNil(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDTextLayer().setText(text: "text").setFontStyle(.italic))).generate("test"))
Expand Down
Loading