Skip to content

Commit

Permalink
Release 0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
fo2rist authored Aug 19, 2019
2 parents 7a159ef + 6428f7b commit 4ee8517
Show file tree
Hide file tree
Showing 102 changed files with 3,381 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
/captures
*.iml
.externalNativeBuild

.kotlintest

/local.properties
.gradle
build/
bin/

.DS_Store
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Cadabra is the A/B testing library that simplifies objects creation
at the different application layers.

Cadabra either takes the external A/B test configuration, or makes the decision based on supplied end-user id.

To publish use `gw uploadArchives --no-daemon --no-parallel`

[![Build Status](https://app.bitrise.io/app/5781b73059466ba5/status.svg?token=fvX37th1yPPTTe6L2iVzuQ&branch=master)](https://app.bitrise.io/app/5781b73059466ba5)

[![Codacy Badge](https://api.codacy.com/project/badge/Grade/e1ae15358eb94f52b0fe262b256f788e)](https://www.codacy.com/app/fo2/cadabra?utm_source=github.com&utm_medium=referral&utm_content=fo2rist/cadabra&utm_campaign=Badge_Grade)

[![codecov](https://codecov.io/gh/fo2rist/cadabra/branch/master/graph/badge.svg)](https://codecov.io/gh/fo2rist/cadabra)
58 changes: 58 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.3.31'
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.android.tools.build:gradle:3.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// for google-services plugin
classpath 'com.google.gms:google-services:4.2.0'

// for jacoco aggregator plugin
classpath "com.vanniktech:gradle-android-junit-jacoco-plugin:0.15.0"
// for maven publisher plugin
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.8.0'
}
}

allprojects {
repositories {
google()
jcenter()
mavenCentral()
}

buildscript {
repositories {
mavenCentral()
}
}

configurations.all {
resolutionStrategy {
//Force appcompat 28 before migration for Firebase 18+ and AndroidX
force 'com.android.support:appcompat-v7:28.0.0'
force 'com.android.support:support-v4:28.0.0'
force 'com.android.support:support-annotations:28.0.0'
}
}
}

//adds report aggregation tasks such as jacocoTestReport & jacocoTestReport<FLAVOR><BUILD_TYPE>
apply plugin: "com.vanniktech.android.junit.jacoco"
junitJacoco {
jacocoVersion = "0.8.4"
includeNoLocationClasses = true
}

task clean(type: Delete) {
delete rootProject.buildDir
}
57 changes: 57 additions & 0 deletions cadabra-android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: "com.vanniktech.maven.publish"

android {
compileSdkVersion 28
buildToolsVersion = '28.0.3'

defaultConfig {
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "0.0.1"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

testOptions {
unitTests {
includeAndroidResources = true
all {
useJUnitPlatform()
testLogging {
events 'PASSED', 'FAILED', 'SKIPPED'
}
}
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
api project(path: ':cadabra-core')

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'

//Kotlintest
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation 'io.kotlintest:kotlintest-runner-junit5:3.3.2'

//JUnit5 (Required for kotlintest and spek)
testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.2"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.2"
//Robolectric
testImplementation 'org.robolectric:robolectric:4.3'
testImplementation 'junit:junit:4.12'
//vintage engine is required for Robolectic tests which need JUnit4
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.4.2"

//Mockito
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
}
3 changes: 3 additions & 0 deletions cadabra-android/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# region Maven publishing
POM_ARTIFACT_ID=cadabra-android
# endregion
2 changes: 2 additions & 0 deletions cadabra-android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fo2rist.cadabra.android"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.fo2rist.cadabra.android

import android.content.Context
import com.fo2rist.cadabra.Cadabra
import com.fo2rist.cadabra.CadabraConfig
import com.fo2rist.cadabra.Variant
import com.fo2rist.cadabra.android.CadabraAndroid.Companion.initialize
import com.fo2rist.cadabra.android.exceptions.NotInitializedException
import kotlin.reflect.KClass

/**
* Android-specific cadabra extension that supports resources injection.
* Usage:
* - register/start experiments with [Cadabra.config]
* - initialize context with [initialize]
* - access resources associated with experiment via [getExperimentContext], see [VariantResources] for details
* @see [Cadabra] for experiment registration details
*/
interface CadabraAndroid : Cadabra {

/**
* Get Android resources accessor for active experiment variant.
* @throws IllegalStateException if was not initialized via [initialize].
*/
fun getExperimentContext(variantClass: KClass<out Variant>): ExperimentContext

/**
* Get Android resources accessor for active experiment variant.
* @throws NotInitializedException if was not initialized via [initialize].
*/
fun getExperimentContext(variantClass: Class<out Variant>): ExperimentContext

companion object {

private val _instance = CadabraAndroidImpl()

/**
* Entry point CadabraAndroid experiment variants usage.
*/
val instance: CadabraAndroid
get() = _instance

/**
* Entry point for Cadabra configuration.
* Same as [Cadabra.config].
*/
val config: CadabraConfig
get() = _instance

/**
* Initialize Cadabra for resources access.
* Initialization is required prior resources usage but not required to register and access experiments.
* [Context.getApplicationContext] will be used by Cadabra as the context.
*/
fun initialize(context: Context) {
_instance.initialize(context)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.fo2rist.cadabra.android

import android.content.Context
import com.fo2rist.cadabra.Cadabra
import com.fo2rist.cadabra.CadabraConfig
import com.fo2rist.cadabra.Variant
import com.fo2rist.cadabra.android.exceptions.NotInitializedException
import kotlin.reflect.KClass

internal class CadabraAndroidImpl : CadabraAndroid, Cadabra by Cadabra.instance, CadabraConfig by Cadabra.config {

private lateinit var appContext: Context

fun initialize(context: Context) {
if (::appContext.isInitialized) {
return
}

appContext = context.applicationContext
}

override fun getExperimentContext(variantClass: KClass<out Variant>): ExperimentContext {
return getExperimentContext(variantClass.java)
}

override fun getExperimentContext(variantClass: Class<out Variant>): ExperimentContext {
checkInitialized()

val variant = getExperimentVariant(variantClass)
return ExperimentContext(variant, VariantResourcesImpl(appContext, variant))
}

/**
* @throws NotInitializedException if the value is null.
*/
private fun checkInitialized() {
if (!::appContext.isInitialized) {
throw NotInitializedException()
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.fo2rist.cadabra.android

import com.fo2rist.cadabra.ExperimentsConfig
import org.json.JSONObject

/**
* Create config from json.
* Format example:
* ```
* {
* "ExperimentId": "VariantName",
* ...
* }
* ```
* @throws org.json.JSONException if the parse fails.
*/
fun configFromJson(json: String): ExperimentsConfig {
if (json.isEmpty()) {
return ExperimentsConfig.create()
}

val jsonObject = JSONObject(json)

val keys = jsonObject.keys()
val configPairs = Array<Pair<String, String>>(jsonObject.length()) {
val experimentId = keys.next()
experimentId to jsonObject.getString(experimentId)
}

@Suppress("SpreadOperator")
return ExperimentsConfig.create(*configPairs)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.fo2rist.cadabra.android

import com.fo2rist.cadabra.Variant

/**
* Full context of experiment state as it's resolved for current session/user.
*/
class ExperimentContext(
/**
* Active variant to be applied by the app.
*/
val variant: Variant,
resources: VariantResources
) : VariantResources by resources
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.fo2rist.cadabra.android

/**
* Generates names for resources by base resource name and given variant.
*/
internal class ResourceNamesGenerator {

/**
* Generate resource name to use by base name current variant.
* E.g. For "string_a" and variant "A" should give "string_a", for "string_a" and variant "B" should give "string_b"
*/
fun generateResourceName(baseResourceName: String, variantName: String): String {
return baseResourceName.replaceAfterLast("_", variantName.toLowerCase())
}
}
Loading

0 comments on commit 4ee8517

Please sign in to comment.