Skip to content

Commit

Permalink
v3.1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
alexey-troshkov committed Sep 5, 2024
1 parent 344b334 commit 820aa8d
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 1 deletion.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ If you are new to Cocoapods, please refer to [CocoaPods documentation](https://g
"page_chapter3": "chapter 3"
]))
```
or
```swift
pa.sendEvent(Event(PA.EventName.Page.Display, properties: Set([
try! Property("page", "name"),
try! Property("enabled", true),
try! Property("count", "1", forceType: .int)
])))
```
_For more examples, please refer to the [Documentation](https://developers.atinternet-solutions.com/piano-analytics/)_
Expand Down
25 changes: 25 additions & 0 deletions Sources/PianoAnalytics/Core/Error.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
//
// Error.swift
//
// This SDK is licensed under the MIT license (MIT)
// Copyright (c) 2015- Applied Technologies Internet SAS (registration number B 403 261 258 - Trade and Companies Register of Bordeaux – France)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

import Foundation

public extension PA {
Expand Down
25 changes: 25 additions & 0 deletions Sources/PianoAnalytics/Core/ExtendedConfiguration.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
//
// ExtendedConfiguration.swift
//
// This SDK is licensed under the MIT license (MIT)
// Copyright (c) 2015- Applied Technologies Internet SAS (registration number B 403 261 258 - Trade and Companies Register of Bordeaux – France)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

import Foundation

extension PA {
Expand Down
11 changes: 10 additions & 1 deletion Sources/PianoAnalytics/Event.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,19 @@ public final class Event {
public final let name: String
public final let data: [String: Any]

public init(_ name: String, data: [String: Any] = [:]) {
public init(_ name: String, data: [String: Any]) {
self.name = name
self.data = PianoAnalyticsUtils.toFlatten(src: data)
}

public init(_ name: String) {
self.name = name
self.data = [:]
}

public convenience init(_ name: String, properties: Set<Property>) {
self.init(name, data: properties.toMap())
}

final func toMap(context: [String: ContextProperty] = [:]) -> [String: Any] {

Expand Down
114 changes: 114 additions & 0 deletions Sources/PianoAnalytics/Property.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//
// Property.swift
//
// This SDK is licensed under the MIT license (MIT)
// Copyright (c) 2015- Applied Technologies Internet SAS (registration number B 403 261 258 - Trade and Companies Register of Bordeaux – France)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

import Foundation

public final class Property {

private static let nameExpression = try! NSRegularExpression(pattern: "^[a-z]\\w*$")

private static func check(name: String) -> Bool {
Property.nameExpression.matches(in: name, range: NSRange(name.startIndex..., in: name)).count > 0
}

fileprivate let name: String
fileprivate let lowerCasedName: String

internal let value: Any

private init(name: String, value: Any, forceType: PA.PropertyType? = nil) throws {
self.lowerCasedName = name.lowercased()
guard name.count <= 40
&& !lowerCasedName.hasPrefix("m_")
&& !lowerCasedName.hasPrefix("visit_")
&& (name == "*" || Property.check(name: lowerCasedName)) else {
throw PA.Err(
message:
"Property name can contain only `a-z`, `0-9`, `_`, " +
"must begin with `a-z`, " +
"must not begin with m_ or visit_. " +
"Max allowed length: 40"
)
}
self.name = forceType?.rawValue.appending(":\(name)") ?? name
self.value = value
}

public convenience init(_ name: String, _ value: Bool, forceType: PA.PropertyType? = nil) throws {
try self.init(name: name, value: value, forceType: forceType)
}

convenience init(_ name: String, _ value: Int, forceType: PA.PropertyType? = nil) throws {
try self.init(name: name, value: value, forceType: forceType)
}

convenience init(_ name: String, _ value: Int64, forceType: PA.PropertyType? = nil) throws {
try self.init(name: name, value: value, forceType: forceType)
}

convenience init(_ name: String, _ value: Double, forceType: PA.PropertyType? = nil) throws {
try self.init(name: name, value: value, forceType: forceType)
}

convenience init(_ name: String, _ value: String, forceType: PA.PropertyType? = nil) throws {
try self.init(name: name, value: value, forceType: forceType)
}

convenience init(_ name: String, _ value: Date) throws {
try self.init(name: name, value: Int64(value.timeIntervalSince1970), forceType: .date)
}

convenience init(_ name: String, _ value: [Int], forceType: PA.PropertyType? = nil) throws {
try self.init(name: name, value: value, forceType: forceType)
}

convenience init(_ name: String, _ value: [Double], forceType: PA.PropertyType? = nil) throws {
try self.init(name: name, value: value, forceType: forceType)
}

convenience init(_ name: String, _ value: [String], forceType: PA.PropertyType? = nil) throws {
try self.init(name: name, value: value, forceType: forceType)
}
}

extension Property: Hashable {

public static func == (lhs: Property, rhs: Property) -> Bool {
lhs.lowerCasedName == rhs.lowerCasedName
}

public func hash(into hasher: inout Hasher) {
hasher.combine(lowerCasedName)
}
}

internal extension Set where Element == Property {

func toMap() -> [String:Any] {
Dictionary(
uniqueKeysWithValues: self.map { ($0.name, $0.value) }
)
}
}
103 changes: 103 additions & 0 deletions Tests/PianoAnalyticsTests/PropertyTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// PropertyTests.swift
// PianoAnalyticsTests
//
// This SDK is licensed under the MIT license (MIT)
// Copyright (c) 2015- Applied Technologies Internet SAS (registration number B 403 261 258 - Trade and Companies Register of Bordeaux – France)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

import XCTest
@testable import PianoAnalytics

class PropertyTests: XCTestCase {

func testName() throws {
XCTAssertNoThrow(try Property("valid_name", true))
XCTAssertNoThrow(try Property("Valid_Name", true))
XCTAssertNoThrow(try Property("ValidName", true))
XCTAssertThrowsError(try Property("invalid-name", true))
}

func testValues() throws {
let now = Date()

let properties = Set([
try Property("bool", true),
try Property("bool_force", "true", forceType: .bool),
try Property("int", 1),
try Property("int_force", "1", forceType: .int),
try Property("int64", Int64.max),
try Property("int64_force", "\(Int64.max)", forceType: .int),
try Property("double", 1.1),
try Property("double_force", "1.1", forceType: .float),
try Property("string", "value"),
try Property("string_force", 1, forceType: .string),
try Property("date", now),
try Property("int_array", [1]),
try Property("int_array_force", "1", forceType: .intArray),
try Property("double_array", [1.1]),
try Property("double_array_force", "1", forceType: .floatArray),
try Property("string_array", ["value"]),
try Property("string_array_force", 1, forceType: .stringArray),
]).toMap()

XCTAssertEqual(properties["bool"] as? Bool, true)
XCTAssertEqual(properties["b:bool_force"] as? String, "true")
XCTAssertEqual(properties["int"] as? Int, 1)
XCTAssertEqual(properties["n:int_force"] as? String, "1")
XCTAssertEqual(properties["int64"] as? Int64, Int64.max)
XCTAssertEqual(properties["n:int64_force"] as? String, "\(Int64.max)")
XCTAssertEqual(properties["double"] as? Double, 1.1)
XCTAssertEqual(properties["f:double_force"] as? String, "1.1")
XCTAssertEqual(properties["string"] as? String, "value")
XCTAssertEqual(properties["s:string_force"] as? Int, 1)
XCTAssertEqual(properties["d:date"] as? Int64, Int64(now.timeIntervalSince1970))
XCTAssertEqual(properties["int_array"] as? [Int], [1])
XCTAssertEqual(properties["a:n:int_array_force"] as? String, "1")
XCTAssertEqual(properties["double_array"] as? [Double], [1.1])
XCTAssertEqual(properties["a:f:double_array_force"] as? String, "1")
XCTAssertEqual(properties["string_array"] as? [String], ["value"])
XCTAssertEqual(properties["a:s:string_array_force"] as? Int, 1)
}

func testDuplicate() throws {
var set = Set([
try Property("value", 1),
try Property("value", 2)
])

set.insert(try Property("value", 3))

XCTAssertEqual(set.count, 1)
XCTAssertEqual(set.first?.value as? Int, 1)
}
}

func nnn() {

pa.sendEvent(
Event(PA.EventName.Page.Display, properties: Set([
try! Property("page", "name"),
try! Property("enabled", true),
try! Property("count", "1", forceType: .int)
]))
)
}

0 comments on commit 820aa8d

Please sign in to comment.