compare string with startWith in scala - string

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

groovy.lang.MissingMethodException: No signature of method exception when using Groovy default Builder annotation

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.

Koin - single instance per parameter value

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())
}
}
}

How do I get the annotation value 'used'

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.

Groovy equivalent to Scala trait stackable modifications?

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()))

replacing toString using Groovy metaprogramming

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()

Resources