I want to compare a pattern in string
sealed trait Demo { def value: String }
object Demo {
case object TypeAB extends Demo {
val value = "a:b"
}
.......other constants
}
val test = Option("a:b:c")
val s =test.map(_.startsWith(Demo.TypeAB.value))
I want to not use .value in Demo.TypeAB.value
Is there a better approach to achieve the above .I preferred to use startsWith
I tried but it didnot work
def unapply(arg: Demo): String= arg.value
sealed trait Demo {
def value: String
}
object Demo {
case object TypeAB extends Demo {
val value = "a:b"
}
implicit def demoToString(demo: Demo): String = demo.value
}
You can now write "a:b:c".startsWith(Demo.TypeAB)
Whether it's a good idea to have an implicit Demo to string method in your code, well, I'll leave it up to you :D
You could add predicates to Demo that provide the tests you need:
sealed trait Demo {
def value: String
def startsWith(body: Option[String]): Boolean = body match {
case Some(content) => content.startsWith(value)
case _ => false
}
}
This allows you to hide the implementation details at the cost of a broader interface.
Does this counts as a better way:
sealed trait Demo {
def value: String
def startsWith(s: String): Boolean = s.startsWith(value)
}
object Demo {
case object TypeAB extends Demo {
val value = "a:b"
}
}
val test = Option("a:b:c")
val s = test.map(Demo.TypeAB.startsWith(_))
println(s)
or maybe you want to use implicits magic such as
sealed trait Demo { def value: String }
implicit class DemoStringOps(val s: String) extends AnyRef {
def startsWith(d: Demo) = s.startsWith(d.value)
}
object Demo {
case object TypeAB extends Demo {
val value = "a:b"
}
}
val test = Option("a:b:c")
val s = test.map(_.startsWith(Demo.TypeAB))
println(s)
Related
I have the following enum, trait and a class.
enum FileFormat {
V2, V3
}
trait FileSet {
int fileSetId
List<DataFile> srcFiles = Collections.emptyList()
boolean header = false
boolean mixedPack = false
FileFormat format
List<String> getSrcFileNames() {
srcFiles.collect { it -> it.getSrcFileName() }
}
int getFileCount() {
srcFiles.size()
}
abstract boolean isValid()
def addFile(HeaderFileType hdrType) {
def f = DataFile()
}
}
#Builder(builderMethodName = "builder", buildMethodName = "build", prefix = "with", excludes = "srcFileNames, valid, fileCount")
class VolumeFileSet implements FileSet {
#Override
boolean isValid() {
//TODO implement based on VolumeFileSet validation rules
return true
}
}
When I try to use builder to set the format enum, I am getting the error
groovy.lang.MissingMethodException: No signature of method: static com.tccc.bia.testdrive.nsr.VolumeFileSet.witFormat() is applicable for argument types: (com.tccc.bia.testdrive.nsr.FileFormat) values: [V3]
Possible solutions: setFormat(com.tccc.bia.testdrive.nsr.FileFormat), getFormat()
Here is the test
class TestSpec extends Specification {
def setupSpec() {
def volumeFileSet = VolumeFileSet
.builder()
.withHeader(true)
.withMixedPack(true)
.witFormat(FileFormat.V3) //ERROR here
.build()
}
}
You misspelled the method name.
It should be withFormat(FileFormat.V3), not witFormat.
When corrected, the code compiles and runs just fine.
I have a module:
single{ (name: String) -> Person(name) }
When I do:
val alice: Person by inject {parametersOf("Alice")}
val bob: Person by inject {parametersOf("Bob")}
I get 2 instances of Alice. All parameters other than the first are ignored.
Is there a simple way to make Koin treat those 2 as different? Parameters are not known in advance, so I can't use named properties. factory won't do either, I need to reuse instances with same parameter sets.
There is no such thing directly in Koin, but it's easy enough to make something that works this way.
1) a class that does create-if-not-present:
class DistinctFactory<K, V>(private val newInstance: (K) -> V) {
private val _locker = Any()
private val mRepo: HashMap<K, V> = HashMap()
operator fun get(id: K): V {
return mRepo[id] ?: run {
synchronized(_locker) {
mRepo[id] ?: run {
newInstance(id).also {
mRepo[id] = it
}
}
}
}
}
}
2) Koin single of DistinctFactory:
single { DistinctFactory<String, Person> { Person(it) } }
3) Koin factory that uses the previous single:
factory { (name: String) -> get<DistinctFactory<String, Person>>()[name] }
test:
val alice: Person by inject {parametersOf("Alice")}
val bob: Person by inject {parametersOf("Bob")}
val aliceAgain: Person by inject {parametersOf("Alice")}
alice === aliceAgain
module {
val personCache = HashMap<Int, Person>()
factory { parameters ->
val hash = parameters.values.hashCode()
personCache.getOrPut(hash) {
Person(parameters.get())
}
}
}
I want to retrieve the annotation value used from MyAnnot. I am getting 3 annotations in the list even though there are only 2. Also, I have tried obtaining the used field of MyAnnot but with no success. I would like to return a map where MyAnnot's used is the key and type as the map's value.
// Then, define your class with it's annotated Fields
class MyClass {
#MyAnnot(used = "Hey", type = "There")
String fielda
#MyAnnot(used = "denn", type = "Ton")
String fieldc
}
def findAllPropertiesForClassWithAnotation(obj, annotClass) {
def op = []
def annos = []
def i = 0
obj.properties.findAll { prop ->
obj.getClass().declaredFields.find {
it.name == prop.key && annotClass in it.declaredAnnotations*.annotationType()
annos=it.declaredAnnotations
i++
if(annos)
op << annos[0] as Set
// println"Props ${annos[0]}"
}
}
op.each{ println "${it} and i is ${i}"}
}
// Then, define an instance of our class
MyClass a = new MyClass(fielda: 'tim', fieldc: 'dennisStar')
// And print the results of calling our method
println findAllPropertiesForClassWithAnotation(a, MyAnnot)
First of all you need to mark you annotation with: #Retention(RetentionPolicy.RUNTIME) to make it available for processing at runtime, so it will be:
#Retention(RetentionPolicy.RUNTIME)
#interface MyAnnot {
String used()
String type()
}
Then, used and type are not fields, nor properties but methods, so they must be invoked and get.
The script will be:
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Retention
#Retention(RetentionPolicy.RUNTIME)
#interface MyAnnot {
String used()
String type()
}
class MyClass {
#MyAnnot(used="Hey" ,type="There")
String fielda
#MyAnnot(used="denn", type="Ton")
String fieldc
}
def findAllPropertiesForClassWithAnotation( obj, annotClass ) {
def c = obj.getClass()
c.declaredFields.findAll { field ->
field.isAnnotationPresent(annotClass)
}.collect { found ->
def a = found.getAnnotation(annotClass)
[(a.used()): a.type()]
}.sum()
}
MyClass a = new MyClass(fielda: 'tim', fieldc: 'dennisStar')
println findAllPropertiesForClassWithAnotation(a, MyAnnot)
Mind that passing only a class of annotation is not sufficient, since you don't know the methods (used and type) to be invoked on the annotation. The following method will work only for MyAnnot class.
I have been going through the Programming Scala book(by Martin Odersky,Lex Spoon,Bill Venners ed1) and came across traits. A section that I find interesting is stackable modifications. The example used is
abstract class IntQueue {
def get(): Int
def put(x: Int)
}
trait Incrementing extends IntQueue {
abstract override def put(x: Int) {super.put(x+1)}
}
trait Filtering extends IntQueue{
abstract override def put(x: Int){
if(x >=0) super.put(x)
}
}
so the example provided has a concrete class "BasicIntQueue that extends IntQueue as follows
import scala.collection.mutable.ArrayBuffer
class BasicIntQueue extends IntQueue{
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x: Int) {buf +=x}
}
scala> val queue = (new BasicIntQueue with Incrementing with Filtering)
scala> queue.put(-1);queue.put(0);queue.put(1)
scala> queue.get() = 1
So the example shows that both the filtering and incrementing are "chained" and executed before the elements are "put" into the queue.
I was just wondering how this could be accomplished in Groovy. Maybe it is not needed because of Groovy's meta-programability.
Beginning from Groovy 2.3 Groovy supports traits and also stackable traits. The implementation looks therefore exactly as in Scala:
interface IntQueue {
Integer get()
void put(Integer x)
}
trait Incrementing implements IntQueue {
void put(Integer x) { super.put(x+1) }
}
trait Filtering implements IntQueue {
void put(Integer x) { if(x >= 0) super.put(x) }
}
class BasicIntQueue implements IntQueue {
private buf = new ArrayList<Integer>()
Integer get() { buf.remove(0) }
void put(Integer x) { buf << x}
String toString() { buf.toString() }
}
def queue = new BasicIntQueue().withTraits Incrementing, Filtering
queue.put(-1)
queue.put(0)
queue.put(1)
assert queue.get() == 1
Groovy doesn't have a natural way to do stackable traits. Categories provide some of the trait functionality, but they're not well suited to overriding methods and can't be stacked without much metaclass magic.
A better approach in groovy would be to apply the decorator pattern along with the #Delegate annotation. Each "trait" can override the appropriate behavior and delegate to the "super" class. Example:
interface IntQueue {
def get()
def put(x)
}
class Incrementing implements IntQueue {
#Delegate IntQueue self
def put(x) {
self.put(x+1)
}
}
class Filtering implements IntQueue {
#Delegate IntQueue self
def put(x) {
if (x >= 0) {
self.put(x)
}
}
}
class BasicIntQueue implements IntQueue {
private buf = []
def get() { buf.pop() }
def put(x) { buf << x }
}
You could then construct an object with the desired traits like so:
def q = new Filtering(self: new Incrementing(self: new BasicIntQueue()))
In the following Groovy snippet, I attempt to replace both the hashCode and toString methods
String.metaClass.toString = {-> "override" }
String.metaClass.hashCode = {-> 22 }
But when I test it out, only the replacement of hashCode works
String s = "foo"
println s.hashCode() // prints 22
println s.toString() // prints "foo"
Is toString somehow a special case (possibly for security reasons)?
See the first comment on this issue. It says about String's toString and other String related classes:
(...) seems to be intent, it is probably a
good idea to have a faster invocation
for classes that don't allow
overriding toString().
This is a know defect.
Basically Groovy does not correctly override methods that are part of an interface implementation.
This works:
class T {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
assert !t.doIt()
This doesn't:
interface I {
def doIt()
}
class T implements I {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
assert !t.doIt()
Because toString() in String comes from CharSequence the correct way to override would be:
CharSequence.metaClass.toString = {-> "silly"}
println "hello world".toString()