Skip to content

Instantly share code, notes, and snippets.

@jbruchanov
Last active January 12, 2020 20:38
Show Gist options
  • Save jbruchanov/0c31298ca85ea156eb7c0b7beaad3cfd to your computer and use it in GitHub Desktop.
Save jbruchanov/0c31298ca85ea156eb7c0b7beaad3cfd to your computer and use it in GitHub Desktop.
Analytics uFramework
package com.kotlin
interface IEventName {
val eventName: String
}
interface IAnalyticsArgsEvent<T> : IEventName
interface IAnalyticsMapArgsEvent : IAnalyticsArgsEvent<Map<String, Any>>
class AnalyticsArgsEvent<T>(override val eventName: String) : IAnalyticsArgsEvent<T>
class AnalyticsMapArgsEvent(override val eventName: String) : IAnalyticsMapArgsEvent
interface IAnalyticsAPI {
fun track(event: String)
}
@Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
class EventContext<T>(val event: IAnalyticsArgsEvent<T>, val args: T) {
val eventName = event.eventName
}
interface IAnalyticsRegistry {
fun <T> add(event: IAnalyticsArgsEvent<T>, block: (EventContext<T>) -> Unit) {
event.invoke(block)
}
@JvmSynthetic
operator fun <T> IAnalyticsArgsEvent<T>.invoke(block: (EventContext<T>) -> Unit)
fun track(event: IAnalyticsMapArgsEvent, args: Map<String, Any> = emptyMap()) =
//explicit casting to call other track
track(event as IAnalyticsArgsEvent<Map<String, Any>>, args)
fun <T> track(event: IAnalyticsArgsEvent<T>, args: T)
}
interface AppDynamicsRegistry : IAnalyticsRegistry {
val api: IAnalyticsAPI
}
sealed class Feature1Events : IEventName {
override val eventName: String = this::class.java.name
object Event1 : Feature1Events(), IAnalyticsArgsEvent<Int>
object Event1A : Feature1Events(), IAnalyticsArgsEvent<Int?>
object Event2 : Feature1Events(), IAnalyticsMapArgsEvent
}
enum class Feature2Events : IAnalyticsMapArgsEvent {
E1, E2;
override val eventName: String = name
}
object Feature3Events {
val Event1 = AnalyticsArgsEvent<String>("Event1")
val Event2 = AnalyticsMapArgsEvent("Event2")
val Event3 = AnalyticsArgsEvent<List<String>>("Event3")
}
interface IAnalyticsImplRegistry : IAnalyticsRegistry {
val api: IAnalyticsAPI
}
fun main() {
fun register(registry: IAnalyticsImplRegistry) {
registry.apply {
val defHandler: ((EventContext<*>) -> Unit) =
{ context: EventContext<*> -> println("DH:${context.eventName} args:${context.args}") }
Feature2Events.E1 {
api.track(it.eventName)
}
Feature1Events.Event1(defHandler)
Feature1Events.Event1A {
api.track("${it.eventName} args:${it.args}")
}
Feature1Events.Event2(defHandler)
Feature1Events.Event2 {
api.track("${it.eventName} args:${it.args}")
}
Feature3Events.Event1 {
api.track("${it.eventName} args:${it.args}")
}
Feature3Events.Event1(defHandler)
}
val tracker = registry
tracker.track(Feature2Events.E1)
tracker.track(Feature1Events.Event1, 1)
tracker.track(Feature1Events.Event1A, null)
tracker.track(Feature1Events.Event2)
tracker.track(Feature3Events.Event2)
}
analytics {
register(this)
}
}
fun analytics(function: IAnalyticsImplRegistry.() -> Unit): IAnalyticsImplRegistry {
val api = object : IAnalyticsAPI {
override fun track(event: String) {
println(event)
}
}
return AnalyticsRegistry(api).apply(function)
}
private typealias EventAction = ((EventContext<*>) -> Unit)
class AnalyticsRegistry(override val api: IAnalyticsAPI) : IAnalyticsImplRegistry {
private val map = mutableMapOf<IAnalyticsArgsEvent<*>, MutableList<EventAction>>()
override fun <T> IAnalyticsArgsEvent<T>.invoke(block: (EventContext<T>) -> Unit) {
@Suppress("UNCHECKED_CAST")
map.getOrPut(this) { mutableListOf() }.add(block as EventAction)
}
override fun <T> track(event: IAnalyticsArgsEvent<T>, args: T) {
map[event]?.forEach {
it.invoke(EventContext(event, args))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment