From a8fdec5d0de1699d285d566412526661a0ec06d9 Mon Sep 17 00:00:00 2001 From: galarragas Date: Thu, 16 Jan 2014 14:46:32 +0000 Subject: [PATCH 1/8] Added support for config file properties injection --- .../subcut/inject/BindingModule.scala | 68 ++++++- .../subcut/inject/Injectable.scala | 31 +++- .../config/BasicPropertyConversions.scala | 27 +++ .../subcut/inject/config/ConfigProperty.scala | 12 ++ .../inject/config/ConfigPropertySource.scala | 10 ++ .../PropertiesConfigPropertySource.scala | 31 ++++ src/test/resources/test.properties | 4 + .../inject/ConfigPropertyBindingTest.scala | 169 ++++++++++++++++++ .../PropertiesConfigPropertySourceTest.scala | 57 ++++++ 9 files changed, 407 insertions(+), 2 deletions(-) create mode 100644 src/main/scala/com/escalatesoft/subcut/inject/config/BasicPropertyConversions.scala create mode 100644 src/main/scala/com/escalatesoft/subcut/inject/config/ConfigProperty.scala create mode 100644 src/main/scala/com/escalatesoft/subcut/inject/config/ConfigPropertySource.scala create mode 100644 src/main/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySource.scala create mode 100644 src/test/resources/test.properties create mode 100644 src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala create mode 100644 src/test/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySourceTest.scala diff --git a/src/main/scala/com/escalatesoft/subcut/inject/BindingModule.scala b/src/main/scala/com/escalatesoft/subcut/inject/BindingModule.scala index 75face0..e07665f 100644 --- a/src/main/scala/com/escalatesoft/subcut/inject/BindingModule.scala +++ b/src/main/scala/com/escalatesoft/subcut/inject/BindingModule.scala @@ -7,12 +7,19 @@ package com.escalatesoft.subcut.inject * Time: 11:39 AM */ import scala.collection._ +import com.escalatesoft.subcut.inject.config._ +import com.escalatesoft.subcut.inject.config.Undefined +import scala.Some +import com.escalatesoft.subcut.inject.BindingKey +import com.escalatesoft.subcut.inject.config.Defined /** * The binding key, used to uniquely identify the desired injection using the class and an optional name. */ private[inject] case class BindingKey[A](m: Manifest[A], name: Option[String]) + + /** * The main BindingModule trait. * Not intended to be used directly, instead extend NewBindingModule with a function to create the bindings @@ -23,7 +30,11 @@ trait BindingModule { outer => /** Abstract binding map definition */ def bindings: immutable.Map[BindingKey[_], Any] - + + def configPropertySource: ConfigPropertySource = new ConfigPropertySource { + def getOptional(propertyName: String): ConfigProperty = throw new IllegalStateException("No ConfigPropertySource provided") + } + /** * Merge this module with another. The resulting module will include all bindings from both modules, with this * module winning if there are common bindings (binding override). If you prefer symbolic operators, @@ -135,6 +146,30 @@ trait BindingModule { outer => for ((k, v) <- bindings) yield { k.toString + " -> " + v.toString } } + /** + * Retrieves a mandatory binding for class T for the giving property in the ConfigPropertySource owned by this module. + * If there is no ConfigPropertySource the binding will fail (use NewBindingModule.newBindingModuleWithConfig to create + * a config with ConfigPropertySource). + * + * @param propertyName The key to use to retrieve the property from the ConfigPropertySource + * @return The property value converted to the required type by the implicit property converter + */ + def injectPropertyMandatory[T <: Any](propertyName: String)(implicit m: scala.reflect.Manifest[T], propertyConverter: ConfigProperty => T): T = + propertyConverter( configPropertySource.get(propertyName) ) + + /** + * Retrieves an optional binding for class T for the giving property in the ConfigPropertySource owned by this module. + * If there is no ConfigPropertySource the binding will fail (use NewBindingModule.newBindingModuleWithConfig to create + * a config with ConfigPropertySource). + * + * @param propertyName The key to use to retrieve the property from the ConfigPropertySource + * @return An optional property value converted to the required type by the implicit property converter + */ + def injectPropertyOptional[T <: Any](propertyName: String)(implicit m: scala.reflect.Manifest[T], propertyConverter: ConfigProperty => T): Option[T] = + configPropertySource.getOptional(propertyName) match { + case property@Defined(_, _) => Some(propertyConverter(property)) + case Undefined(_) => None + } } /** @@ -167,6 +202,10 @@ class NewBindingModule(fn: MutableBindingModule => Unit) extends BindingModule { } } +class NewBindingModuleWithConfig(fn: MutableBindingModule => Unit)(implicit configProvider: ConfigPropertySource) extends NewBindingModule(fn) { + override val configPropertySource = configProvider +} + /** * A companion object holding a convenience method to create new binding modules on the fly when passed * a function from MutableBindingModule to unit. @@ -182,9 +221,19 @@ class NewBindingModule(fn: MutableBindingModule => Unit) extends BindingModule { * bind [QueryService] toSingle { new SlowInitQueryService } * } * + * + * Use the newBindingModuleWithConfig method if you need to inject from a ConfigPropertySource. That needs a + * ConfigPropertySource instance to be implicitly available. A version without any binding is available if you + * are just injecting properties using the injectProperty method */ object NewBindingModule { def newBindingModule(fn: MutableBindingModule => Unit): BindingModule = new NewBindingModule(fn) + + def newBindingModuleWithConfig(fn: MutableBindingModule => Unit)(implicit configProvider: ConfigPropertySource): BindingModule = + new NewBindingModuleWithConfig(fn)(configProvider) + + def newBindingModuleWithConfig(implicit configProvider: ConfigPropertySource): BindingModule = + new NewBindingModuleWithConfig( { mutableBindingModule: MutableBindingModule => } )(configProvider) } /** @@ -576,6 +625,22 @@ trait MutableBindingModule extends BindingModule { outer => name = None } + /** + * Bind to a new instance of the provided class for each injection. The value for this instance is read from + * the ConfigPropertySource available in the BindingModule and converted using an implicitly available converter from + * ConfigPropertySource (essentially a wrapper for String) to the target type. + * Converters for the basic types are already available, you need to provide a new one for special types. + * + * @param name + * @param source + * @param converter + * @tparam I + * @return + */ + def toProperty[I <: T](name: String)(implicit source: ConfigPropertySource, converter: ConfigProperty => I) { + toSingle( converter(source.get(name)) ) + } + /** * Part of the fluent interface in the DSL, identified by provides a name to attach to the binding key so that, * in combination with the trait type being bound, a unique key is formed. This form takes a string name, but @@ -622,3 +687,4 @@ trait MutableBindingModule extends BindingModule { outer => // and a parameterized bind method to kick it all off def bind[T <: Any](implicit m: scala.reflect.Manifest[T]) = new Bind[T]() } + diff --git a/src/main/scala/com/escalatesoft/subcut/inject/Injectable.scala b/src/main/scala/com/escalatesoft/subcut/inject/Injectable.scala index 6322670..d86aff5 100644 --- a/src/main/scala/com/escalatesoft/subcut/inject/Injectable.scala +++ b/src/main/scala/com/escalatesoft/subcut/inject/Injectable.scala @@ -1,5 +1,7 @@ package com.escalatesoft.subcut.inject +import com.escalatesoft.subcut.inject.config.{ConfigProperty, BasicPropertyConversions} + /** * The trait that provides dependency injection features for a class or object. To use this trait, * Mix it in to the class or object definition, and then define the abstract bindingModule which holds @@ -8,7 +10,7 @@ package com.escalatesoft.subcut.inject * or, perhaps most flexibly, an implicit constructor parameter in a curried parameter list. This last option * can provide flexible and mostly invisible bindings all the way down an object instance creation chain. */ -trait Injectable { +trait Injectable extends BasicPropertyConversions{ implicit def bindingModule: BindingModule /** @@ -167,6 +169,33 @@ trait Injectable { def injectOptional[T <: Any](name: String)(implicit m: scala.reflect.Manifest[T]): Option[T] = bindingModule.injectOptional[T](Some(name)) + /** + * Inject a required instance for the given trait as read from the ConfigPropertySource provided by the BindingModule + * and converted using an implicit converter from ConfigProperty (a wrapper of String properties) to the required target + * trait. + * + * If the module contains no configuration the injection will fail. The same will happen if the property cannot be + * found. + * + * Instances of ConfigPropertySource trait can be developed to allow the injection to retrieve from different sources. + * At the moment the only implementation available allows the use of the Java Properties class. + * + * @param propertyName The key in the ConfigPropertySource to load the property to be Inject + * @return An instance converted to the relevant type + */ + def injectProperty[T <: Any](propertyName: String)(implicit m: scala.reflect.Manifest[T], propertyConverter: ConfigProperty => T): T = + bindingModule.injectPropertyMandatory[T](propertyName) + + /** + * Inject an optional for the given trait as read from the ConfigPropertySource provided by the BindingModule + * and converted using an implicit converter from ConfigProperty (a wrapper of String properties) to the required target + * trait.. If there is no matching binding, this method will return None. + * + * @param propertyName The name of the property to be read + * @return An option with instance converted to the relevant type if found or None if not found + */ + def injectOptionalProperty[T <: Any](propertyName: String)(implicit m: scala.reflect.Manifest[T], propertyConverter: ConfigProperty => T): Option[T] = + bindingModule.injectPropertyOptional[T](propertyName) } /** diff --git a/src/main/scala/com/escalatesoft/subcut/inject/config/BasicPropertyConversions.scala b/src/main/scala/com/escalatesoft/subcut/inject/config/BasicPropertyConversions.scala new file mode 100644 index 0000000..b505c61 --- /dev/null +++ b/src/main/scala/com/escalatesoft/subcut/inject/config/BasicPropertyConversions.scala @@ -0,0 +1,27 @@ +package com.escalatesoft.subcut.inject.config + +object BasicPropertyConversions { + + implicit def _toString(input: ConfigProperty) : String = input.value + implicit def _toInt(input: ConfigProperty) : Int = augmentString(input.value).toInt + implicit def _toLong(input: ConfigProperty) : Long = augmentString(input.value).toLong + implicit def _toDouble(input: ConfigProperty) : Double = augmentString(input.value).toDouble + implicit def _toFloat(input: ConfigProperty) : Float = augmentString(input.value).toFloat + implicit def _toByte(input: ConfigProperty) : Byte = augmentString(input.value).toByte + implicit def _toShort(input: ConfigProperty) : Short = augmentString(input.value).toShort +} + +import BasicPropertyConversions._ +trait BasicPropertyConversions { + + implicit def toString(input: ConfigProperty) : String = _toString(input) + implicit def toInt(input: ConfigProperty) : Int = _toInt(input) + implicit def toLong(input: ConfigProperty) : Long = _toLong(input) + implicit def toDouble(input: ConfigProperty) : Double = _toDouble(input) + implicit def toFloat(input: ConfigProperty) : Float = _toFloat(input) + implicit def toByte(input: ConfigProperty) : Byte = _toByte(input) + implicit def toShort(input: ConfigProperty) : Short = _toShort(input) + +} + + diff --git a/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigProperty.scala b/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigProperty.scala new file mode 100644 index 0000000..007a087 --- /dev/null +++ b/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigProperty.scala @@ -0,0 +1,12 @@ +package com.escalatesoft.subcut.inject.config + +sealed trait ConfigProperty { + def name: String + def value: String +} + +case class Defined(name: String, value: String) extends ConfigProperty + +case class Undefined(name: String) extends ConfigProperty { + def value = throw new IllegalArgumentException(s"Undefined value for property $name") +} diff --git a/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigPropertySource.scala b/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigPropertySource.scala new file mode 100644 index 0000000..3bc3cc2 --- /dev/null +++ b/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigPropertySource.scala @@ -0,0 +1,10 @@ +package com.escalatesoft.subcut.inject.config + +trait ConfigPropertySource { + def get(propertyName: String) : ConfigProperty = getOptional(propertyName) match { + case property@Defined(_, value) => property + case Undefined(_) => throw new IllegalArgumentException(s"Missing property $propertyName in config") + } + + def getOptional(propertyName: String) : ConfigProperty +} diff --git a/src/main/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySource.scala b/src/main/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySource.scala new file mode 100644 index 0000000..2a9a6f3 --- /dev/null +++ b/src/main/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySource.scala @@ -0,0 +1,31 @@ +package com.escalatesoft.subcut.inject.config + +import java.util.Properties +import java.io.{FileInputStream, File} + +class PropertiesConfigPropertySource(properties: Properties) extends ConfigPropertySource { + def getOptional(propertyName: String) : ConfigProperty = { + val prop = properties.getProperty(propertyName) + + if(prop != null) + Defined(propertyName, prop) + else + Undefined(propertyName) + } +} + +object PropertiesConfigPropertySource { + def apply(properties: Properties) = new PropertiesConfigPropertySource(properties) + + def fromPath(path: String) = { + val properties = new Properties() + properties.load(new FileInputStream(new File(path))) + new PropertiesConfigPropertySource(properties) + } + + def fromClasspathResource(path: String) = { + val properties = new Properties() + properties.load(getClass.getClassLoader.getResourceAsStream(path)) + new PropertiesConfigPropertySource(properties) + } +} diff --git a/src/test/resources/test.properties b/src/test/resources/test.properties new file mode 100644 index 0000000..17d42fd --- /dev/null +++ b/src/test/resources/test.properties @@ -0,0 +1,4 @@ +property1=value1 +property2=2 +property3=3 +property4=4 \ No newline at end of file diff --git a/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala new file mode 100644 index 0000000..d2c4650 --- /dev/null +++ b/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala @@ -0,0 +1,169 @@ +package com.escalatesoft.subcut.inject + +import org.scalatest.FunSuite +import org.scalatest.matchers.ShouldMatchers + +import NewBindingModule._ +import com.escalatesoft.subcut.inject.config._ +import com.escalatesoft.subcut.inject.config.Defined +import scala.Some +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import java.util.Date +import java.text.SimpleDateFormat +import scala.concurrent.duration.Duration +import scala.concurrent.duration._ + +@RunWith(classOf[JUnitRunner]) +class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { + + def configProvider(properties: Map[String, String]) = new ConfigPropertySource { + def getOptional(propertyName: String) : ConfigProperty = properties.get(propertyName) match { + case Some(value) => Defined(propertyName, value) + case None => Undefined(propertyName) + } + } + + test("Should inject from config") { + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val property1 = injectProperty[String]("property1") + val property2 = injectProperty[String]("property2") + + def properties: List[Any] = List(property1, property2) + } + + implicit val propertyProvider = configProvider { + Map( "property1" -> "value1", "property2" -> "value2") + } + implicit val bindingModule = newBindingModuleWithConfig + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List("value1", "value2")) + } + + test("Should convert basic types") { + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val property1 = injectProperty[String]("property1") + val property2 = injectProperty[Int]("property2") + val property3 = injectProperty[Long]("property3") + val property4 = injectProperty[Float]("property4") + + def properties: List[Any] = List(property1, property2, property3, property4) + } + + implicit val propertyProvider = configProvider { + Map( "property1" -> "value1", "property2" -> "2", "property3" -> "3", "property4" -> "4.0") + } + implicit val bindingModule = newBindingModuleWithConfig { bindingModule => } + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List("value1", 2, 3l, 4.0)) + } + + test("Should bind properties from config source") { + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val property1 = inject[String]("property1") + val property2 = inject[Int]("property2") + val property3 = inject[Long]("property3") + val property4 = inject[Float]("property4") + + def properties: List[Any] = List(property1, property2, property3, property4) + } + + implicit val propertyProvider = configProvider { + Map( "property1" -> "value1", "property2" -> "2", "property3" -> "3", "property4" -> "4.0") + } + + implicit val bindingModule = newBindingModuleWithConfig { bindingModule => + import bindingModule._ + import BasicPropertyConversions._ + + bind [String] idBy 'property1 toProperty "property1" + bind [Int] idBy 'property2 toProperty "property2" + bind [Long] idBy 'property3 toProperty "property3" + bind [Float] idBy 'property4 toProperty "property4" + } + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List("value1", 2, 3l, 4.0)) + } + + test("Should optinally bind properties from config source") { + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val property1 = injectOptionalProperty[Int]("property1") getOrElse(-1) + val property2 = injectOptionalProperty[Int]("property2") getOrElse(-1) + + def properties: List[Any] = List(property1, property2) + } + + implicit val propertyProvider = configProvider { + Map( "property1" -> "100") + } + + implicit val bindingModule = newBindingModuleWithConfig + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List(100, -1)) + } + + test("Should bind custom type if a converter is provided") { + implicit def toDate(prop: ConfigProperty): Date = new SimpleDateFormat("yyyy-mm-DD").parse(prop.value) + + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val property1 = inject[Date]("property1") + val property2 = injectProperty[Date]("property2") + } + + implicit val propertyProvider = configProvider { + Map( "property1" -> "2014-01-15", "property2" -> "2014-01-15") + } + + implicit val bindingModule = newBindingModuleWithConfig { bindingModule => + import bindingModule._ + + bind [Date] idBy 'property1 toProperty "property1" + } + + val configReaderInstance = new ToInject + + configReaderInstance.property1 should equal (new SimpleDateFormat("yyyy-mm-DD").parse("2014-01-15")) + configReaderInstance.property2 should equal (new SimpleDateFormat("yyyy-mm-DD").parse("2014-01-15")) + } + + test("You can write more esoteric conversion using property name") { + implicit def toDuration(prop: ConfigProperty): Duration = { + val amount: Long = prop.value.toLong + val timeQualifier: String = prop.name.split('.').last + + timeQualifier match { + case "seconds" | "secs" => amount.seconds + case "hours" => amount.hours + case _ => amount.milliseconds + } + } + + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val timeout1 = injectProperty[Duration]("timeout.millis") + val timeout2 = inject[Duration]("timeout2") + } + + implicit val propertyProvider = configProvider { + Map( "timeout.millis" -> "100", "timeout.seconds" -> "20") + } + + implicit val bindingModule = newBindingModuleWithConfig { bindingModule => + import bindingModule._ + + bind [Duration] idBy "timeout2" toProperty "timeout.seconds" + } + + val configReaderInstance = new ToInject + + configReaderInstance.timeout1 should equal (100.milliseconds) + configReaderInstance.timeout2 should equal (20.seconds) + } +} diff --git a/src/test/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySourceTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySourceTest.scala new file mode 100644 index 0000000..6446904 --- /dev/null +++ b/src/test/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySourceTest.scala @@ -0,0 +1,57 @@ +package com.escalatesoft.subcut.inject.config + +import org.scalatest.matchers.ShouldMatchers +import org.scalatest.FunSuite +import com.escalatesoft.subcut.inject.{Injectable, BindingModule} +import com.escalatesoft.subcut.inject.NewBindingModule._ +import java.util.Properties +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class PropertiesConfigPropertySourceTest extends FunSuite with ShouldMatchers { + + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val property1 = injectProperty[String]("property1") + val property2 = injectProperty[Int]("property2") + val property3 = injectProperty[Long]("property3") + val property4 = injectProperty[Float]("property4") + + def properties: List[Any] = List(property1, property2, property3, property4) + } + + test("should load from properties") { + val properties = new Properties() + properties.put("property1", "value1") + properties.put("property2", "2") + properties.put("property3", "3") + properties.put("property4", "4") + implicit val propertySource = PropertiesConfigPropertySource(properties) + + implicit val bindingModule = newBindingModuleWithConfig + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List("value1", 2, 3l, 4.0)) + } + + test("should load from classpath") { + implicit val propertySource = PropertiesConfigPropertySource.fromClasspathResource("test.properties") + + implicit val bindingModule = newBindingModuleWithConfig + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List("value1", 2, 3l, 4.0)) + } + + test("should load from path") { + implicit val propertySource = PropertiesConfigPropertySource.fromPath("src/test/resources/test.properties") + + implicit val bindingModule = newBindingModuleWithConfig + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List("value1", 2, 3l, 4.0)) + } +} From 2f43811be312e7c74a72ddd1fc11af64e1c1eb06 Mon Sep 17 00:00:00 2001 From: galarragas Date: Thu, 6 Feb 2014 10:58:20 +0000 Subject: [PATCH 2/8] Forked the project from the main one wating for the pull request to be approved. Fixed problems of lack of config support when mofidying the module with modifyBindings --- README.md | 29 +++++++++ pom.xml | 4 +- src/main/resources/pom.xml | 55 ++++++++++++++++ .../subcut/inject/BindingModule.scala | 37 ++++++++--- .../PropertiesConfigPropertySource.scala | 8 +++ .../inject/ConfigPropertyBindingTest.scala | 63 ++++++++++++++----- .../subcut/inject/FrozenModuleTest.scala | 2 +- .../ModuleCompositionAndMergingTest.scala | 2 +- .../PlainScalaInjectInBindingTest.scala | 2 +- .../subcut/inject/PushBindingsTest.scala | 6 +- .../subcut/inject/TrialBindingModule.scala | 2 +- .../PropertiesConfigPropertySourceTest.scala | 11 +++- 12 files changed, 185 insertions(+), 36 deletions(-) create mode 100644 src/main/resources/pom.xml diff --git a/README.md b/README.md index 03d5d48..f8ad971 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,32 @@ +SubCut Extended README +============= + +This project is an extension of SubCut (https://github.com/dickwall/subcut) I'm keeping active while waiting for the extension +code to be merged in the original project. + +I added some feature to implement injection similarly to the @value annotation in spring. For example: + +```(scala) +class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val stringProperty = injectProperty[String]("property1") + val intProperty = injectProperty[Int]("property2") + val longProperty = injectProperty[Long]("property3") + val floatProperty = injectProperty[Float]("property4") +} +``` + +Allowing to inject in this way: + +```(scala) +{ + implicit val bindingModule = newBindingModuleWithConfig(PropertiesConfigPropertySource.fromPath("src/test/resources/test.properties")) + + val configReaderInstance = new ToInject +} +``` + +It supports injection of basic types and allows generic types injection if a custom conversion function is provided. + SubCut README ============= diff --git a/pom.xml b/pom.xml index fc971b1..fb880b2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,8 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.escalatesoft.subcut - subcut + com.pragmasoft + subcut_ext 2.0 diff --git a/src/main/resources/pom.xml b/src/main/resources/pom.xml new file mode 100644 index 0000000..99c7e62 --- /dev/null +++ b/src/main/resources/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + com.pragmasoft + subcut_ext + 2.0 + + + 2.10.1 + + + + com.pragmasoft + + https://github.com/galarragas/ScaldingUnit + + + Apache 2 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + A business-friendly OSS license + + + + + stefanog + Stefano Galarraga + + + + + + clojars + http://clojars.org/repo/ + + + + + + org.scala-lang + scala-library + ${scala.version} + + + org.scala-lang + scala-compiler + ${scala.version} + compile + + + + diff --git a/src/main/scala/com/escalatesoft/subcut/inject/BindingModule.scala b/src/main/scala/com/escalatesoft/subcut/inject/BindingModule.scala index e07665f..707f6d7 100644 --- a/src/main/scala/com/escalatesoft/subcut/inject/BindingModule.scala +++ b/src/main/scala/com/escalatesoft/subcut/inject/BindingModule.scala @@ -10,7 +10,6 @@ import scala.collection._ import com.escalatesoft.subcut.inject.config._ import com.escalatesoft.subcut.inject.config.Undefined import scala.Some -import com.escalatesoft.subcut.inject.BindingKey import com.escalatesoft.subcut.inject.config.Defined /** @@ -19,6 +18,16 @@ import com.escalatesoft.subcut.inject.config.Defined private[inject] case class BindingKey[A](m: Manifest[A], name: Option[String]) +trait ConfigPropertySourceProvider { + def configPropertySource: ConfigPropertySource +} + +trait WithoutConfigPropertySource extends ConfigPropertySourceProvider { + def configPropertySource: ConfigPropertySource = new ConfigPropertySource { + def getOptional(propertyName: String): ConfigProperty = throw new IllegalStateException("No ConfigPropertySource provided") + } +} + /** * The main BindingModule trait. @@ -26,15 +35,11 @@ private[inject] case class BindingKey[A](m: Manifest[A], name: Option[String]) * (recommended - the result will be immutable) or a MutableBindingModule (not recommended unless you know what * you are doing and take on the thread safety responsibility yourself). */ -trait BindingModule { outer => +trait BindingModule extends ConfigPropertySourceProvider { outer : ConfigPropertySourceProvider => /** Abstract binding map definition */ def bindings: immutable.Map[BindingKey[_], Any] - def configPropertySource: ConfigPropertySource = new ConfigPropertySource { - def getOptional(propertyName: String): ConfigProperty = throw new IllegalStateException("No ConfigPropertySource provided") - } - /** * Merge this module with another. The resulting module will include all bindings from both modules, with this * module winning if there are common bindings (binding override). If you prefer symbolic operators, @@ -55,6 +60,8 @@ trait BindingModule { outer => case notLmip => key -> notLmip }}).toMap + + def configPropertySource: ConfigPropertySource = outer.configPropertySource } } @@ -77,6 +84,8 @@ trait BindingModule { outer => def modifyBindings[A](fn: MutableBindingModule => A): A = { val mutableBindings = new MutableBindingModule { bindings = outer.bindings + + def configPropertySource: ConfigPropertySource = outer.configPropertySource } fn(mutableBindings) } @@ -172,6 +181,7 @@ trait BindingModule { outer => } } + /** * A class to create a new, immutable, binding module. In order to work, the constructor of this class * takes a function to evaluate, and passes this on to a bindings method which can be used to resolve @@ -194,16 +204,24 @@ trait BindingModule { outer => * you want. The module will be frozen after creation of the bindings, but is mutable for the * time you are defining it with the DSL. */ -class NewBindingModule(fn: MutableBindingModule => Unit) extends BindingModule { +class NewBindingModule(fn: MutableBindingModule => Unit) extends BindingModule with WithoutConfigPropertySource { lazy val bindings = { - val module = new Object with MutableBindingModule + val module = new Object with MutableBindingModule with WithoutConfigPropertySource fn(module) module.freeze().fixed.bindings } } -class NewBindingModuleWithConfig(fn: MutableBindingModule => Unit)(implicit configProvider: ConfigPropertySource) extends NewBindingModule(fn) { +class NewBindingModuleWithConfig(fn: MutableBindingModule => Unit)(implicit configProvider: ConfigPropertySource) extends BindingModule { override val configPropertySource = configProvider + + lazy val bindings = { + val module = new Object with MutableBindingModule { + def configPropertySource: ConfigPropertySource = configProvider + } + fn(module) + module.freeze().fixed.bindings + } } /** @@ -288,6 +306,7 @@ trait MutableBindingModule extends BindingModule { outer => def fixed: BindingModule = { new BindingModule { override val bindings = outer._bindings + def configPropertySource: ConfigPropertySource = outer.configPropertySource } } diff --git a/src/main/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySource.scala b/src/main/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySource.scala index 2a9a6f3..20c2478 100644 --- a/src/main/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySource.scala +++ b/src/main/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySource.scala @@ -14,8 +14,16 @@ class PropertiesConfigPropertySource(properties: Properties) extends ConfigPrope } } +class PropertiesConfigMapSource(properties: Map[String, String]) extends ConfigPropertySource { + def getOptional(propertyName: String) : ConfigProperty = properties.get(propertyName) match { + case Some(prop) => Defined(propertyName, prop) + case None => Undefined(propertyName) + } +} + object PropertiesConfigPropertySource { def apply(properties: Properties) = new PropertiesConfigPropertySource(properties) + def apply(properties: Map[String, String]) = new PropertiesConfigMapSource(properties) def fromPath(path: String) = { val properties = new Properties() diff --git a/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala index d2c4650..6e659ee 100644 --- a/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala +++ b/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala @@ -17,12 +17,6 @@ import scala.concurrent.duration._ @RunWith(classOf[JUnitRunner]) class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { - def configProvider(properties: Map[String, String]) = new ConfigPropertySource { - def getOptional(propertyName: String) : ConfigProperty = properties.get(propertyName) match { - case Some(value) => Defined(propertyName, value) - case None => Undefined(propertyName) - } - } test("Should inject from config") { class ToInject(implicit val bindingModule: BindingModule) extends Injectable { @@ -32,7 +26,7 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { def properties: List[Any] = List(property1, property2) } - implicit val propertyProvider = configProvider { + implicit val propertyProvider = PropertiesConfigPropertySource { Map( "property1" -> "value1", "property2" -> "value2") } implicit val bindingModule = newBindingModuleWithConfig @@ -52,7 +46,7 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { def properties: List[Any] = List(property1, property2, property3, property4) } - implicit val propertyProvider = configProvider { + implicit val propertyProvider = PropertiesConfigPropertySource { Map( "property1" -> "value1", "property2" -> "2", "property3" -> "3", "property4" -> "4.0") } implicit val bindingModule = newBindingModuleWithConfig { bindingModule => } @@ -72,7 +66,7 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { def properties: List[Any] = List(property1, property2, property3, property4) } - implicit val propertyProvider = configProvider { + implicit val propertyProvider = PropertiesConfigPropertySource { Map( "property1" -> "value1", "property2" -> "2", "property3" -> "3", "property4" -> "4.0") } @@ -99,7 +93,7 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { def properties: List[Any] = List(property1, property2) } - implicit val propertyProvider = configProvider { + implicit val propertyProvider = PropertiesConfigPropertySource { Map( "property1" -> "100") } @@ -118,7 +112,7 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { val property2 = injectProperty[Date]("property2") } - implicit val propertyProvider = configProvider { + implicit val propertyProvider = PropertiesConfigPropertySource { Map( "property1" -> "2014-01-15", "property2" -> "2014-01-15") } @@ -134,7 +128,47 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { configReaderInstance.property2 should equal (new SimpleDateFormat("yyyy-mm-DD").parse("2014-01-15")) } + test("Operators on binding modules are bringing around the config properties provider - modifyBindings") { + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val property1 = inject[String]("property1") + val property2 = inject[Int]("property2") + val property3 = inject[Long]("property3") + val property4 = inject[Float]("property4") + + def properties: List[Any] = List(property1, property2, property3, property4) + } + + implicit val propertyProvider = PropertiesConfigPropertySource { + Map( "property1" -> "value1", "property2" -> "2", "property3" -> "3", "property4" -> "4.0") + } + + implicit val bindingModule = newBindingModuleWithConfig { bindingModule => + import bindingModule._ + import BasicPropertyConversions._ + + bind [String] idBy 'property1 toProperty "property1" + bind [Int] idBy 'property2 toProperty "property2" + bind [Long] idBy 'property3 toProperty "property3" + bind [Float] idBy 'property4 toProperty "property4" + } + + bindingModule modifyBindings { implicit bindingModule => + import bindingModule._ + + bind [String] idBy 'property1 toSingle "value1-MODIFIED" + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List("value1-MODIFIED", 2, 3l, 4.0)) + } + } + test("You can write more esoteric conversion using property name") { + class ToInject(implicit val bindingModule: BindingModule) extends Injectable { + val timeout1 = injectProperty[Duration]("timeout.millis") + val timeout2 = inject[Duration]("timeout2") + } + implicit def toDuration(prop: ConfigProperty): Duration = { val amount: Long = prop.value.toLong val timeQualifier: String = prop.name.split('.').last @@ -146,12 +180,7 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { } } - class ToInject(implicit val bindingModule: BindingModule) extends Injectable { - val timeout1 = injectProperty[Duration]("timeout.millis") - val timeout2 = inject[Duration]("timeout2") - } - - implicit val propertyProvider = configProvider { + implicit val propertyProvider = PropertiesConfigPropertySource { Map( "timeout.millis" -> "100", "timeout.seconds" -> "20") } diff --git a/src/test/scala/com/escalatesoft/subcut/inject/FrozenModuleTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/FrozenModuleTest.scala index 7aaabe0..5ab10c6 100644 --- a/src/test/scala/com/escalatesoft/subcut/inject/FrozenModuleTest.scala +++ b/src/test/scala/com/escalatesoft/subcut/inject/FrozenModuleTest.scala @@ -82,7 +82,7 @@ class MultFunc extends MathFunc { override def doIt(x: Int, y: Int): Int = x * y } -object MathModule extends MutableBindingModule +object MathModule extends MutableBindingModule with WithoutConfigPropertySource trait MathInjector extends BoundToModule { override val bindingModule = MathModule diff --git a/src/test/scala/com/escalatesoft/subcut/inject/ModuleCompositionAndMergingTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/ModuleCompositionAndMergingTest.scala index 11f8cb6..a0a7e3e 100644 --- a/src/test/scala/com/escalatesoft/subcut/inject/ModuleCompositionAndMergingTest.scala +++ b/src/test/scala/com/escalatesoft/subcut/inject/ModuleCompositionAndMergingTest.scala @@ -60,7 +60,7 @@ object StandardConfiguration extends NewBindingModule({ module => bind [String] idBy 'version toSingle "1.3" }) -class FromProperties extends BindingModule { +class FromProperties extends BindingModule with WithoutConfigPropertySource { val bindings = { val newMod = new NewBindingModule({ module => import module._ diff --git a/src/test/scala/com/escalatesoft/subcut/inject/PlainScalaInjectInBindingTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/PlainScalaInjectInBindingTest.scala index e8bb99a..d43eb64 100644 --- a/src/test/scala/com/escalatesoft/subcut/inject/PlainScalaInjectInBindingTest.scala +++ b/src/test/scala/com/escalatesoft/subcut/inject/PlainScalaInjectInBindingTest.scala @@ -60,7 +60,7 @@ class PlainScalaInjectInBindingTest extends FunSuite with ShouldMatchers { } //all implementations unaware of framework, inject called during module definition - object EchoModule extends MutableBindingModule with Injectable { + object EchoModule extends MutableBindingModule with WithoutConfigPropertySource with Injectable { val bindingModule = this diff --git a/src/test/scala/com/escalatesoft/subcut/inject/PushBindingsTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/PushBindingsTest.scala index 6f2b236..a3186d8 100644 --- a/src/test/scala/com/escalatesoft/subcut/inject/PushBindingsTest.scala +++ b/src/test/scala/com/escalatesoft/subcut/inject/PushBindingsTest.scala @@ -87,15 +87,15 @@ class PushBindingsTest extends FunSuite with ShouldMatchers with SeveredStackTra } -object PushBindingsTestModule1 extends MutableBindingModule { +object PushBindingsTestModule1 extends MutableBindingModule with WithoutConfigPropertySource { bind [BoundTrait1] toSingle new T1Impl1 } -object PushBindingsTestModule2 extends MutableBindingModule { +object PushBindingsTestModule2 extends MutableBindingModule with WithoutConfigPropertySource { bind [BoundTrait2] toSingle new T2Impl1 } -object PushBindingsTestModule extends MutableBindingModule { +object PushBindingsTestModule extends MutableBindingModule with WithoutConfigPropertySource { withBindingModules(PushBindingsTestModule1, PushBindingsTestModule2) } diff --git a/src/test/scala/com/escalatesoft/subcut/inject/TrialBindingModule.scala b/src/test/scala/com/escalatesoft/subcut/inject/TrialBindingModule.scala index c9dcbdc..c99ea22 100644 --- a/src/test/scala/com/escalatesoft/subcut/inject/TrialBindingModule.scala +++ b/src/test/scala/com/escalatesoft/subcut/inject/TrialBindingModule.scala @@ -68,7 +68,7 @@ class InjectionTest extends FunSuite with ShouldMatchers with SeveredStackTraces } } -object TrialBindingModule extends MutableBindingModule { +object TrialBindingModule extends MutableBindingModule with WithoutConfigPropertySource { bind [TestTrait] toProvider { new TestImpl } bind [TestTrait] identifiedBy 'testConfig toProvider (new AlternativeImpl) bind [TestTrait] identifiedBy "something else" toProvider { new AlternativeImpl } diff --git a/src/test/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySourceTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySourceTest.scala index 6446904..9684dea 100644 --- a/src/test/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySourceTest.scala +++ b/src/test/scala/com/escalatesoft/subcut/inject/config/PropertiesConfigPropertySourceTest.scala @@ -38,7 +38,7 @@ class PropertiesConfigPropertySourceTest extends FunSuite with ShouldMatchers { test("should load from classpath") { implicit val propertySource = PropertiesConfigPropertySource.fromClasspathResource("test.properties") - implicit val bindingModule = newBindingModuleWithConfig + implicit val bindingModule = newBindingModuleWithConfig val configReaderInstance = new ToInject @@ -54,4 +54,13 @@ class PropertiesConfigPropertySourceTest extends FunSuite with ShouldMatchers { configReaderInstance.properties should equal (List("value1", 2, 3l, 4.0)) } + + test("should work without implicit too") { + + implicit val bindingModule = newBindingModuleWithConfig(PropertiesConfigPropertySource.fromPath("src/test/resources/test.properties")) + + val configReaderInstance = new ToInject + + configReaderInstance.properties should equal (List("value1", 2, 3l, 4.0)) + } } From 19c29f0f4bc90874111db861f97151ea2039ee39 Mon Sep 17 00:00:00 2001 From: galarragas Date: Tue, 11 Mar 2014 10:29:44 +0000 Subject: [PATCH 3/8] Added conversion methods to ConfigProperty trait for direct usage of configuration if necessary --- .../subcut/inject/config/ConfigProperty.scala | 8 +++++++- .../inject/ConfigPropertyBindingTest.scala | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigProperty.scala b/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigProperty.scala index 007a087..15be26b 100644 --- a/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigProperty.scala +++ b/src/main/scala/com/escalatesoft/subcut/inject/config/ConfigProperty.scala @@ -3,10 +3,16 @@ package com.escalatesoft.subcut.inject.config sealed trait ConfigProperty { def name: String def value: String + + def valueAs[T](implicit converter: ConfigProperty => T) : Option[T] } -case class Defined(name: String, value: String) extends ConfigProperty +case class Defined(name: String, value: String) extends ConfigProperty { + def valueAs[T](implicit converter: ConfigProperty => T) : Option[T] = Some( converter(this) ) +} case class Undefined(name: String) extends ConfigProperty { def value = throw new IllegalArgumentException(s"Undefined value for property $name") + + def valueAs[T](implicit converter: ConfigProperty => T) : Option[T] = None } diff --git a/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala b/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala index 6e659ee..0ddb53d 100644 --- a/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala +++ b/src/test/scala/com/escalatesoft/subcut/inject/ConfigPropertyBindingTest.scala @@ -5,13 +5,10 @@ import org.scalatest.matchers.ShouldMatchers import NewBindingModule._ import com.escalatesoft.subcut.inject.config._ -import com.escalatesoft.subcut.inject.config.Defined -import scala.Some import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner import java.util.Date import java.text.SimpleDateFormat -import scala.concurrent.duration.Duration import scala.concurrent.duration._ @RunWith(classOf[JUnitRunner]) @@ -85,7 +82,7 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { configReaderInstance.properties should equal (List("value1", 2, 3l, 4.0)) } - test("Should optinally bind properties from config source") { + test("Should optionally bind properties from config source") { class ToInject(implicit val bindingModule: BindingModule) extends Injectable { val property1 = injectOptionalProperty[Int]("property1") getOrElse(-1) val property2 = injectOptionalProperty[Int]("property2") getOrElse(-1) @@ -195,4 +192,16 @@ class ConfigPropertyBindingTest extends FunSuite with ShouldMatchers { configReaderInstance.timeout1 should equal (100.milliseconds) configReaderInstance.timeout2 should equal (20.seconds) } + + test("you can use config source to directly access properties too") { + import BasicPropertyConversions._ + + val config = PropertiesConfigPropertySource { + Map( "intProp" -> "3", "doubleProp" -> "4.0") + } + + config.getOptional("intProp").valueAs[Int] should equal (Some(3)) + config.getOptional("doubleProp").valueAs[Double] should equal (Some(4.0)) + config.getOptional("otherProp").valueAs[Double] should equal (None) + } } From 0f639d116d0f283800d9a6f0ea86e720a55f5b96 Mon Sep 17 00:00:00 2001 From: Luca Milanesio Date: Thu, 11 Sep 2014 10:14:32 +0100 Subject: [PATCH 4/8] Fix SBT Plugins dependencies SBT Plugins dependencies and repositories were obsolete and needed to be updated to get the project building again. --- project/plugins.sbt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index cda13ac..3bf6a38 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,7 +1,7 @@ -resolvers += "sbt-idea-repo" at "http://mpeltonen.github.com/maven/" +resolvers += "Sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/" -addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0") +addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0") resolvers += Classpaths.typesafeResolver -addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0") +addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.5.0") From 48c32c81bc3560f52b0deefa0cf04fd9de231728 Mon Sep 17 00:00:00 2001 From: Stefano Galarraga Date: Thu, 11 Sep 2014 10:21:17 +0100 Subject: [PATCH 5/8] Added note about sub cut evolution --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f8ad971..0a1fdb9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ SubCut Extended README ============= +THE MOST RECENT VERSION OF SUBCUT ADDED SUPPORT FOR PROPERTY INJECTION SO I'M GOING TO STOP ANY SUPPORT FOR THIS PROJECT. + This project is an extension of SubCut (https://github.com/dickwall/subcut) I'm keeping active while waiting for the extension code to be merged in the original project. From 07963582a4854cc91472616da71156cfe0f517a4 Mon Sep 17 00:00:00 2001 From: Luca Milanesio Date: Thu, 11 Sep 2014 11:55:59 +0100 Subject: [PATCH 6/8] Bump to 2.0.1 and to Scala 2.10.4 Scala 2.9.x is largely obsolete and subcut wasn't compiling on it anyway. --- build.sbt | 6 ++---- pom.xml | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 75dfd3b..40ea61f 100644 --- a/build.sbt +++ b/build.sbt @@ -2,11 +2,9 @@ name := "subcut" organization := "com.escalatesoft.subcut" -version := "2.0" +version := "2.0.1" -crossScalaVersions := Seq("2.10.0", "2.9.2", "2.9.1", "2.9.0-1", "2.9.0") - -scalaVersion := "2.10.1" +scalaVersion := "2.10.4" scalacOptions += "-deprecation" diff --git a/pom.xml b/pom.xml index fb880b2..18d1885 100644 --- a/pom.xml +++ b/pom.xml @@ -6,10 +6,10 @@ com.pragmasoft subcut_ext - 2.0 + 2.0.1 - 2.10.1 + 2.10.4 From 58e9119b7fb844804543cc254909332211f4b109 Mon Sep 17 00:00:00 2001 From: Stefano Galarraga Date: Sat, 13 Dec 2014 09:30:19 +0000 Subject: [PATCH 7/8] Improving disclaimer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a1fdb9..9ccec07 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ SubCut Extended README ============= -THE MOST RECENT VERSION OF SUBCUT ADDED SUPPORT FOR PROPERTY INJECTION SO I'M GOING TO STOP ANY SUPPORT FOR THIS PROJECT. +SUBCUT 2.5 WILL ADD SUPPORT FOR PROPERTY INJECTION SO I'M GOING TO STOP ANY SUPPORT FOR THIS PROJECT WHEN IT WILL BE RELEASED This project is an extension of SubCut (https://github.com/dickwall/subcut) I'm keeping active while waiting for the extension code to be merged in the original project. From 8102d1f8659af0e079003fbe6f3489fd81d0377d Mon Sep 17 00:00:00 2001 From: galarragas Date: Sat, 13 Dec 2014 09:56:23 +0000 Subject: [PATCH 8/8] Improving distribution management to avoid to write pom twice --- build.sbt | 22 ++++++++++----- pom.xml | 2 +- src/main/resources/pom.xml | 55 -------------------------------------- 3 files changed, 17 insertions(+), 62 deletions(-) delete mode 100644 src/main/resources/pom.xml diff --git a/build.sbt b/build.sbt index 75dfd3b..5b0147d 100644 --- a/build.sbt +++ b/build.sbt @@ -1,10 +1,10 @@ -name := "subcut" +name := "subcut_ext" -organization := "com.escalatesoft.subcut" +organization := "com.pragmasoft" -version := "2.0" +version := "2.1" -crossScalaVersions := Seq("2.10.0", "2.9.2", "2.9.1", "2.9.0-1", "2.9.0") +crossScalaVersions := Seq("2.10.0", "2.11.1") scalaVersion := "2.10.1" @@ -12,7 +12,7 @@ scalacOptions += "-deprecation" libraryDependencies += "junit" % "junit" % "4.5" % "test" -libraryDependencies += "org.scalatest" %% "scalatest" % "1.9.1" % "test" +libraryDependencies += "org.scalatest" %% "scalatest" % "2.1.3" % "test" libraryDependencies <<= (scalaVersion, libraryDependencies) { (ver, deps) => deps :+ "org.scala-lang" % "scala-compiler" % ver @@ -53,4 +53,14 @@ pomExtra := ( Dick Wall http://about.me/dickwall - ) + + galarragas + Stefano Galarraga + + + + + conjars.org + http://conjars.org/repo/ + + ) diff --git a/pom.xml b/pom.xml index fb880b2..165e8ef 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.pragmasoft subcut_ext - 2.0 + 2.1 2.10.1 diff --git a/src/main/resources/pom.xml b/src/main/resources/pom.xml deleted file mode 100644 index 99c7e62..0000000 --- a/src/main/resources/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - 4.0.0 - - com.pragmasoft - subcut_ext - 2.0 - - - 2.10.1 - - - - com.pragmasoft - - https://github.com/galarragas/ScaldingUnit - - - Apache 2 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - A business-friendly OSS license - - - - - stefanog - Stefano Galarraga - - - - - - clojars - http://clojars.org/repo/ - - - - - - org.scala-lang - scala-library - ${scala.version} - - - org.scala-lang - scala-compiler - ${scala.version} - compile - - - -