Skip to content

Commit

Permalink
Merge pull request #11 from klutter/develop
Browse files Browse the repository at this point in the history
Merge develop 0.5.0 release to Master
  • Loading branch information
apatrida committed Sep 16, 2015
2 parents 9571816 + d32f13a commit 6796368
Show file tree
Hide file tree
Showing 30 changed files with 327 additions and 74 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
=========================================================
2015-09-14 v0.5.0 release
=========================================================

Kotlin M13 support, updated to Kovenant 2.5.0, Jackson 2.6.2, Injekt 1.5.0, ElasticSearch 1.7.2

=========================================================
2015-09-14 v0.4.0 release
=========================================================

Added ElasticSearch helpers, integration with Kovenant promises in klutter/elasticsearch module, see module docs for more information

=========================================================
2015-08-31 v0.3.0 release
=========================================================
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Kotlin M12](https://img.shields.io/badge/Kotlin-M12%20%40%200.12.1230-blue.svg)](http://kotlinlang.org) [![Maven Version](https://img.shields.io/maven-central/v/uy.klutter/klutter-all-jdk8.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22uy.klutter%22) [![CircleCI branch](https://img.shields.io/circleci/project/klutter/klutter/master.svg)](https://circleci.com/gh/klutter/klutter/tree/master) [![Issues](https://img.shields.io/github/issues/klutter/klutter.svg)](https://github.com/klutter/klutter/issues?q=is%3Aopen) [![DUB](https://img.shields.io/dub/l/vibe-d.svg)](https://github.com/klutter/klutter/blob/master/LICENSE)
[![Kotlin M13](https://img.shields.io/badge/Kotlin-M12%20%40%200.13.1513-blue.svg)](http://kotlinlang.org) [![Maven Version](https://img.shields.io/maven-central/v/uy.klutter/klutter-all-jdk8.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22uy.klutter%22) [![CircleCI branch](https://img.shields.io/circleci/project/klutter/klutter/master.svg)](https://circleci.com/gh/klutter/klutter/tree/master) [![Issues](https://img.shields.io/github/issues/klutter/klutter.svg)](https://github.com/klutter/klutter/issues?q=is%3Aopen) [![DUB](https://img.shields.io/dub/l/vibe-d.svg)](https://github.com/klutter/klutter/blob/master/LICENSE)

# klutter
Random small libraries, usually extensions making other libraries happier.
Expand All @@ -10,24 +10,24 @@ rights for the code to be used in Klutter.

Each module has its own set of dependencies. There is a main dependency which is always the most current JDK
version of the module, and also a version suffixed by the JDK version for which it is compatible (that version or newer).
Include the dependency in your Gradle / Maven projects, ones that already have Kotlin configured for Kotlin M12 versions
`0.12.1218` or `0.12.1230`
Include the dependency in your Gradle / Maven projects, ones that already have Kotlin configured for Kotlin M13 versions
`0.13.1513`

For example, for the whole package (one of `klutter-all` (lastest JDK), `klutter-all-jdk6`, `klutter-all-jdk7`, or `klutter-all-jdk8`) and using an
open-ended dependency number while Klutter is in early active development:

**Gradle:**

```
compile "uy.klutter:klutter-all:0.4.+"
compile "uy.klutter:klutter-all:0.5.+"
```

**Maven:**
```
<dependency>
<groupId>uy.klutter</groupId>
<artifactId>klutter-all</artifactId>
<version>[0.4.0,0.5.0)</version>
<version>[0.5.0,0.6.0)</version>
</dependency>
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import com.amazonaws.services.s3.model.ObjectMetadata
import org.apache.http.HttpStatus
import uy.klutter.aws.defaultSafeCredentialsProviderChain

fun AmazonS3Client.exists(bucket: String, key: String): Boolean {
public fun AmazonS3Client.exists(bucket: String, key: String): Boolean {
return ifExistsReturnMetadata(bucket, key) != null
}

fun AmazonS3Client.ifExistsReturnMetadata(bucket: String, key: String): ObjectMetadata? {
public fun AmazonS3Client.ifExistsReturnMetadata(bucket: String, key: String): ObjectMetadata? {
try {
val metadata = getObjectMetadata(bucket, key)
return metadata
Expand All @@ -23,7 +23,7 @@ fun AmazonS3Client.ifExistsReturnMetadata(bucket: String, key: String): ObjectMe
}


fun AmazonS3Client.ifExistsReturnUserMetadata(bucket: String, key: String): Map<String, String>? {
public fun AmazonS3Client.ifExistsReturnUserMetadata(bucket: String, key: String): Map<String, String>? {
return ifExistsReturnMetadata(bucket, key)?.getUserMetadata()
}

3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ subprojects {

repositories {
mavenCentral()
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots'
}
}

dependencies {
Expand Down
3 changes: 3 additions & 0 deletions config-typesafe-jdk6/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
dependencies {
compile "com.typesafe:config:$version_typesafe_config"
compile "uy.kohesive.injekt:injekt-core:$version_kohesive_injekt"

compile relativeProject(":klutter-json-jackson-jdk6")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package uy.klutter.config.typesafe

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.type.TypeFactory
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.typesafe.config.Config
import com.typesafe.config.ConfigRenderOptions
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.*
import kotlin.properties.Delegates

/**
* A class that startups up an system using Injekt + TypesafeConfig, using the default global scope, and default object binder
*/
public abstract class KonfigAndInjektMain() : KonfigAndInjektScopedMain(Injekt)

/**
* A startup module that registers and uses singletons/object factories from a specific scope,
* and an ObjectMapper to bind configuration properties into class instances.
*/
public abstract class KonfigAndInjektScopedMain(public val scope: InjektScope, public val mapper: ObjectMapper = jacksonObjectMapper()) : InjektModule, KonfigModule {
private val ADDON_ID = "Konfigure"

protected var resolvedConfig: Config by Delegates.notNull()

abstract fun configFactory(): Config

private inner class ScopedKonfigRegistrar(val path: List<String>, val scope: InjektScope) : KonfigRegistrar, InjektRegistrar by scope {
override fun importModule(atPath: String, module: KonfigModule) {
module.registerWith(ScopedKonfigRegistrar(path + atPath.split('.'), scope))
}

override fun <T : Any> bindClassAtConfigRoot(klass: TypeReference<T>) {
val fullpath = path.filter { it.isNotBlank() }.map { it.removePrefix(".").removeSuffix(".") }.joinToString(".")
loadAndInject(resolvedConfig, fullpath, klass)
}

override fun <T : Any> bindClassAtConfigPath(configPath: String, klass: TypeReference<T>) {
val fullpath = (path + configPath.split('.')).filter { it.isNotBlank() }.map { it.removePrefix(".").removeSuffix(".") }.joinToString(".")
loadAndInject(resolvedConfig, fullpath, klass)
}

@Suppress("UNCHECKED_CAST")
fun <T : Any> loadAndInject(config: Config, fullPath: String, klass: TypeReference<T>) {
val configAtPath = config.getConfig(fullPath)
val asJson = configAtPath.root().render(ConfigRenderOptions.concise().setJson(true))
val instance: T = mapper.readValue(asJson, TypeFactory.defaultInstance().constructType(klass.type))!!
scope.registrar.addSingleton(klass, instance)
}
}

init {
resolvedConfig = configFactory()
val registrar = ScopedKonfigRegistrar(emptyList(), scope)
registrar.registerConfigurables()
scope.registrar.registerInjectables()
}
}

public interface KonfigRegistrar : InjektRegistrar {
/**
* import a module loading it and any submodules immediately
*/
fun importModule(atPath: String, module: KonfigModule)

/**
* bind a class bindings its values from a configuration path immediately
*/
final inline fun <reified T : Any> bindClassAtConfigPath(configPath: String) {
bindClassAtConfigPath(configPath, fullType<T>())
}

/**
* bind a class bindings its values from a configuration path immediately
*/
fun <T : Any> bindClassAtConfigPath(configPath: String, klass: TypeReference<T>)

/**
* bind a class bindings its values from a configuration path immediately
*/
final inline fun <reified T : Any> bindClassAtConfigPath(configPath: String, klass: Class<T>) {
bindClassAtConfigPath(configPath, fullType<T>())
}

/**
* bind a class bindings its values from the root of the current configuration path immediately
*/
final inline fun <reified T : Any> bindClassAtConfigRoot() {
bindClassAtConfigRoot(fullType<T>())
}

/**
* bind a class bindings its values from the root of the current configuration path immediately
*/
fun <T : Any> bindClassAtConfigRoot(klass: TypeReference<T>)

/**
* bind a class bindings its values from the root of the current configuration path immediately
*/
final inline fun <reified T : Any> bindClassAtConfigRoot(klass: Class<T>) {
bindClassAtConfigRoot(fullType<T>())
}
}

/**
* A package of configuration bound items that can be included into a scope of someone else
*/
public interface KonfigModule {
final internal fun registerWith(intoModule: KonfigRegistrar) {
intoModule.registerConfigurables()
}

fun KonfigRegistrar.registerConfigurables()
}

Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package uy.klutter.config.typesafe
package uy.klutter.config.typesafe.tests

import com.typesafe.config.ConfigFactory
import org.junit.AfterClass
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import kotlin.platform.platformStatic
import uy.klutter.config.typesafe.*
import kotlin.test.assertEquals

public class TestConfigLoading {
companion object {
@BeforeClass @platformStatic public fun setupSystemProps() {
@BeforeClass @JvmStatic public fun setupSystemProps() {
System.setProperty("systemKey", "value System")
System.setProperty("base.value4", "four-sys")
}

@AfterClass @platformStatic public fun removeSystemProps() {
@AfterClass @JvmStatic public fun removeSystemProps() {
System.clearProperty("base.value4")
System.clearProperty("systemKey")
ConfigFactory.invalidateCaches()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package uy.klutter.config.typesafe.tests

import com.typesafe.config.Config
import org.junit.Test
import uy.klutter.config.typesafe.*
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.InjektModule
import uy.kohesive.injekt.api.InjektRegistrar
import kotlin.test.assertEquals

class TestInjektConfig {
companion object : KonfigAndInjektMain() {
override fun configFactory(): Config {
return loadConfig(MapAsConfig(kotlin.mapOf(
"http" to kotlin.mapOf("httpPort" to 8080, "workerThreads" to 16),
"data" to kotlin.mapOf("bucket" to "com.test.bucket", "region" to "us-east"),
"other" to kotlin.mapOf("name" to "frisbee"))))
}

override fun KonfigRegistrar.registerConfigurables() {
bindClassAtConfigPath<HttpConfig>("http")
bindClassAtConfigPath<DataConfig>("data")
importModule("other", OtherModule)
}

override fun InjektRegistrar.registerInjectables() {
addFactory { ConfiguredThing() }
importModule(OtherModule)
}

}

@Test public fun testConfigSingletonsExist() {
val matchHttp = HttpConfig(8080,16)
val matchData = DataConfig("com.test.bucket", "us-east")

assertEquals(matchHttp, Injekt.get<HttpConfig>())
assertEquals(matchData, Injekt.get<DataConfig>())
}

@Test public fun testFactoryUsingConfigWorks() {
val matchHttp = HttpConfig(8080,16)
val matchData = DataConfig("com.test.bucket", "us-east")

val thing = Injekt.get<ConfiguredThing>()
assertEquals(matchHttp, thing.httpCfg)
assertEquals(matchData, thing.dataCfg)
}

@Test public fun testWithModules() {
val thing = Injekt.get<OtherThingWantingConfig>()
assertEquals("frisbee", thing.cfg.name)
}


data class HttpConfig(val httpPort: Int, val workerThreads: Int)
data class DataConfig(val bucket: String, val region: String)
data class ConfiguredThing(val httpCfg: HttpConfig = Injekt.get(), val dataCfg: DataConfig = Injekt.get())
}


data class OtherConfig(val name: String)
data class OtherThingWantingConfig(val cfg: OtherConfig = Injekt.get())

public object OtherModule : KonfigModule, InjektModule {
override fun KonfigRegistrar.registerConfigurables() {
bindClassAtConfigRoot<OtherConfig>()
}

override fun InjektRegistrar.registerInjectables() {
addFactory { OtherThingWantingConfig() }
}
}




2 changes: 2 additions & 0 deletions config-typesafe-jdk7/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
dependencies {
compile relativeProject(":klutter-config-typesafe-jdk6")
compile "com.typesafe:config:$version_typesafe_config"

compile relativeProject(":klutter-json-jackson-jdk6")
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import uy.klutter.config.typesafe.ConfiguredValue
import java.nio.file.Path
import java.nio.file.Paths

fun ConfiguredValue.asPath(): Path = Paths.get(cfg.getString(key).trim()).toAbsolutePath()
fun ConfiguredValue.asPathOrNull(): Path? = if (exists()) asPath() else null
public fun ConfiguredValue.asPath(): Path = Paths.get(cfg.getString(key).trim()).toAbsolutePath()
public fun ConfiguredValue.asPathOrNull(): Path? = if (exists()) asPath() else null

fun ConfiguredValue.asPathRelative(relativeTo: Path): Path = relativeTo.resolve(cfg.getString(key).trim()).toAbsolutePath()
fun ConfiguredValue.asPathRelativeOrNull(relativeTo: Path): Path? = if (exists()) asPathRelative(relativeTo) else null
public fun ConfiguredValue.asPathRelative(relativeTo: Path): Path = relativeTo.resolve(cfg.getString(key).trim()).toAbsolutePath()
public fun ConfiguredValue.asPathRelativeOrNull(relativeTo: Path): Path? = if (exists()) asPathRelative(relativeTo) else null

fun ConfiguredValue.asPathSibling(relativeTo: Path): Path = relativeTo.resolveSibling(cfg.getString(key).trim()).toAbsolutePath()
fun ConfiguredValue.asPathSiblingOrNull(relativeTo: Path): Path? = if (exists()) asPathSibling(relativeTo) else null
public fun ConfiguredValue.asPathSibling(relativeTo: Path): Path = relativeTo.resolveSibling(cfg.getString(key).trim()).toAbsolutePath()
public fun ConfiguredValue.asPathSiblingOrNull(relativeTo: Path): Path? = if (exists()) asPathSibling(relativeTo) else null

fun ConfiguredValue.asPathList(): List<Path> = cfg.getStringList(key).map { Paths.get(it).toAbsolutePath() }
fun ConfiguredValue.asPathList(defaultValue: List<Path>): List<Path> = if (exists()) asPathList() else defaultValue
fun ConfiguredValue.asPathListOrNull(): List<Path>? = if (exists()) asPathList() else null
fun ConfiguredValue.asPathListOrEmpty(): List<Path> = asPathList(emptyList())
public fun ConfiguredValue.asPathList(): List<Path> = cfg.getStringList(key).map { Paths.get(it).toAbsolutePath() }
public fun ConfiguredValue.asPathList(defaultValue: List<Path>): List<Path> = if (exists()) asPathList() else defaultValue
public fun ConfiguredValue.asPathListOrNull(): List<Path>? = if (exists()) asPathList() else null
public fun ConfiguredValue.asPathListOrEmpty(): List<Path> = asPathList(emptyList())
2 changes: 2 additions & 0 deletions config-typesafe-jdk8/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
dependencies {
compile relativeProject(':klutter-config-typesafe-jdk6')
compile relativeProject(':klutter-config-typesafe-jdk7')
compile relativeProject(":klutter-json-jackson-jdk8")

compile "com.typesafe:config:$version_typesafe_config_jdk8"
}
4 changes: 2 additions & 2 deletions core-jdk6/src/main/kotlin/uy/klutter/core/jdk/Strings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public fun String.mustEndWith(postfix: Char): String {
}
}

inline public fun String.whenStartsWith(prefix: String, thenWithRest: (String)->Unit): Boolean {
public inline fun String.whenStartsWith(prefix: String, thenWithRest: (String)->Unit): Boolean {
if (this.startsWith(prefix)) {
thenWithRest(this.exceptStarting(prefix.length()))
return true
Expand All @@ -86,7 +86,7 @@ inline public fun String.whenStartsWith(prefix: String, thenWithRest: (String)->
}


inline public fun String.whenStartsWith(prefixes: List<String>, thenWithRest: (String)->Unit): Boolean {
public inline fun String.whenStartsWith(prefixes: List<String>, thenWithRest: (String)->Unit): Boolean {
prefixes.forEach { prefix ->
if (this.startsWith(prefix)) {
thenWithRest(this.exceptStarting(prefix.length()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public interface ImmutableUri {
fun fragmentAsDecodedQueryDeduped(): Map<String, String>? = if (encodedFragment == null) null else UrlEncoding.decodeQueryToMap(encodedFragment!!)
}

class UriBuilder(scheme: String? = null, encodedUserInfo: String? = null, host: String? = null, port: Int? = null, encodedPath: String? = null, encodedQuery: String? = null, encodedFragment: String? = null): ImmutableUri {
public class UriBuilder(scheme: String? = null, encodedUserInfo: String? = null, host: String? = null, port: Int? = null, encodedPath: String? = null, encodedQuery: String? = null, encodedFragment: String? = null): ImmutableUri {
override var scheme: String? = scheme
override var host: String? = host
override var port: Int? = port
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ public object UrlEncoding {
var state: ParseState = ParseState.sText
var i = 0
var code = 0
val c: Char
var c: Char
var pos = 0
var ofs = 0
var buf: ByteArray? = null
Expand Down
Loading

0 comments on commit 6796368

Please sign in to comment.