Is it possible to create a dsl with infix operators in Groovy ?
I've researched the builder pattern, invokeMethod, propertyInvoke and the MetaClass and I can only see how to use it to create tree structures using prefix operators (polish notation). What I want to do is build tree structures with infix operators that have binding precedence rules.
eg: if this pseudo code evaluates to 8:
add(2,multiply(3, 2))
I want to express it as:
2 add 3 multiply 2
where multiply binds more tightly than add. I'm using arithmetic just as an example - my application is something quite different.
I don't want to write and support my own parser so I'm hoping groovy has a mechanism for this ???
EDIT: While searching for solutions I've found this is possible and well documented in Scala (see chapter 33: Combinator Parsers in Programming in Scala by Martin Odersky).
I see you found an answer in Scala, but anyway, in Groovy, although it needs the dot (or an AST to insert it automatically), it's not hard to do the command tree:
UPDATE: added a floatNode method, whose precedence is based in the precedence list. The nodes with higher precedence "float" upward:
class Operation {
static final precedence = ['minus', 'add', 'multiply', 'divide']
def left, right, method
Operation parent
def invokeMethod(String method, args) {
def o = new Operation(
parent: this, left: right, method: method, right: args[0])
this.floatNode(o)
}
def floatNode(Operation op) {
if (op.hasHigherPrecedenceThan(this)) {
op.parent = this.parent
this.parent = op
if (op.parent) { this.parent = op.parent.floatNode(op) }
return this
}
else {
return op
}
}
def hasHigherPrecedenceThan(Operation o) {
return precedence.indexOf(this.method) > precedence.indexOf(o.method)
}
String toString() { "Operation($left $method $right, parent=$parent)" }
}
Tests:
Integer.metaClass.invokeMethod = { String method, args ->
new Operation(parent: null, method: method, left: delegate, right: args.head())
}
a = 2.add 3 multiply 4 minus 5 divide 6 add 7
println a
The println will output:
Operation(3 minus 5,
parent=Operation(5 add 7,
parent=Operation(2 add 3,
parent=Operation(3 multiply 4,
parent=Operation(5 divide 6, parent=null)))))
Related
Please help with a metaprogramming configuration such that I can add collections methods called collectWithIndex and injectWithIndex that work in a similar manner to eachWithIndex but of course include the base functionality of collect and inject. The new methods would accept a two (three with maps) argument closure just like eachWithIndex. I would like to have the capability to utilize these methods across many different scripts.
Use case:
List one = [1, 2, 3]
List two = [10, 20, 30]
assert [10, 40, 90] == one.collectWithIndex { value, index ->
value * two [index]
}
Once the method is developed then how would it be made available to scripts? I suspect that a jar file would be created with special extension information and then added to the classpath.
Many thanks in advance
I'm still sure, it's not a proper SO question, but I'll give you an example, how you can enrich metaclass for your multiple scripts.
Idea is based on basescript, adding required method to List's metaClass in it's constructor. You have to implement collect logic yourself, through it's pretty easy. You can use wrapping
import org.codehaus.groovy.control.CompilerConfiguration
class WithIndexInjector extends Script {
WithIndexInjector() {
println("Adding collectWithIndex to List")
List.metaClass.collectWithIndex {
int i = 0
def result = []
for (o in delegate) // delegate is a ref holding initial list.
result << it(o, i++) // it is closure given to method
result
}
}
#Override Object run() {
return null
}
}
def configuration = new CompilerConfiguration()
configuration.scriptBaseClass = WithIndexInjector.name
new GroovyShell(configuration).evaluate('''
println(['a', 'b'].collectWithIndex { it, id -> "[$id]:$it" })
''')
// will print [[0]:a, [1]:b]
If you like to do it in more functional way, without repeating collect logic, you may use wrapping proxy closure. I expect it to be slower, but maybe it's not a deal. Just replace collectWithIndex with following implementation.
List.metaClass.collectWithIndex {
def wrappingProxyClosure = { Closure collectClosure, int startIndex = 0 ->
int i = startIndex
return {
collectClosure(it, i++) // here we keep hold on outer collectClosure and i, and use call former with one extra argument. "it" is list element, provided by default collect method.
}
}
delegate.collect(wrappingProxyClosure(it))
}
offtopic: In SO community your current question will only attract minuses, not answers.
I have an array and i want to build a map out of it recording the frequency of elements in the array. So for the example below the map = [15:2, 16:1] is what it will look like. How do I do this in Groovy ?
static void doSomething()
{
def a = [15,16,15]
def map = []
a.each{
k,v->
if(map.contains(it))
map.putAt k, v++
else
map.putAt k, 1;
}
println map
}
In Groovy 1.8 or higher,
assert [15, 16, 15].countBy { it } == [15: 2, 16: 1]
You could modify your code to be the following:
void doSomething() {
def a = [15,16,15]
def map = [:] //1
a.each { //2
if(map.containsKey(it)) map[it] = map[it] + 1 //3
else map[it] = 1;
}
println map
}
This fixes a few things:
map needs to be initiated with colon between braces, as notes by Bill James in comments.
can't use a 2-parameter version of each on an arraylist
postfix increment won't result in incremented value being saved; Also, explicit putAt call is fine, but it's there to provide the overloaded [key] = val syntax which is more expressive.
All that said, I'm assuming this is a coding exercise to learn groovy. doelleri's answer is more succinct and uses the tools provided, so in a real-world situation, I'd go with that.
This may be a duplicate but "as" is an INCREDABLY hard keyword to google, even S.O. ignores "as" as part of query.
So I'm wondering how to implement a class that supports "as" reflexively. For an example class:
class X {
private val
public X(def v) {
val=v
}
public asType(Class c) {
if (c == Integer.class)
return val as Integer
if(c == String.class)
return val as String
}
}
This allows something like:
new X(3) as String
to work, but doesn't help with:
3 as X
I probably have to attach/modify the "asType" on String and Integer somehow, but I feel any changes like this should be confined to the "X" class... Can the X class either implement a method like:
X fromObject(object)
or somehow modify the String/Integer class from within X. This seems tough since it won't execute any code in X until X is actually used... what if my first usage of X is "3 as X", will X get a chance to override Integer's asType before Groovy tries to call is?
As you say, it's not going to be easy to change the asType method for Integer to accept X as a new type of transformation (especially without destroying the existing functionality).
The best I can think of is to do:
Integer.metaClass.toX = { -> new X( delegate ) }
And then you can call:
3.toX()
I can't think how 3 as X could be done -- as you say, the other way; new X('3') as Integer is relatively easy.
Actually, you can do this:
// Get a handle on the old `asType` method for Integer
def oldAsType = Integer.metaClass.getMetaMethod( "asType", [Class] as Class[] )
// Then write our own
Integer.metaClass.asType = { Class c ->
if( c == X ) {
new X( delegate )
}
else {
// if it's not an X, call the original
oldAsType.invoke( delegate, c )
}
}
3 as X
This keeps the functionality out of the Integer type, and minimizes scope of the effect (which is good or bad depending on what you're looking for).
This category will apply asType from the Integer side.
class IntegerCategory {
static Object asType(Integer inty, Class c) {
if(c == X) return new X(inty)
else return inty.asType(c)
}
}
use (IntegerCategory) {
(3 as X) instanceof X
}
What is the differ between string.Join & string.Concat
similarly what is the diff between string.Equals & string.Compare
Show me with some example for each. I already searched but didn't understand.
Thanks in Advance.
Join combines several strings with a separator in between; this is most often used if you have a list and want to format it in a way that there is a separator (e.g. a comma) between each element. Concat just appends them all after another. In a way, Join with an empty separator is equivalent to Concat.
Equals determines whether two strings are considered equal, Compare is for determining a sort order between two strings.
Honestly, though, this is all explained very well in the documentation.
With .NET 4.0, String.Join() uses StringBuilder class internally so it is more efficient.
Whereas String.Concat() uses basic concatenation of String using "+" which is of course not an efficient approach as String is immutable.
I compared String.Join() in .NET 2.0 framework where its implementation was different(it wasn't using StringBuilder in .NET 2.0). But with .NET 4.0, String.Join() is using StringBuilder() internally so its like easy wrapper on top of StringBuilder() for string concatenation.
Microsoft even recommends using StringBuilder class for any string concatenation.
Program that joins strings [C#]
using System;
class Program
{
static void Main()
{
string[] arr = { "one", "two", "three" };
// "string" can be lowercase, or...
Console.WriteLine(string.Join(",", arr));
// ... "String" can be uppercase:
Console.WriteLine(String.Join(",", arr));
}
}
Output -
one,two,three
one,two,three
Concat:
using System;
class Program
{
static void Main()
{
// 1.
// New string called s1.
string s1 = "string2";
// 2.
// Add another string to the start.
string s2 = "string1" + s1;
// 3.
// Write to console.
Console.WriteLine(s2);
}
}
Output -
string1string2
these two methods are quite related. Although it hasn't been done, equals could have been implemented using compareTo:
public boolean equals(Object o)
{
if (this == anObject)
{
return true;
}
if (o instanceof String)
{
String s = (String)o;
return compareTo(s) == 0;
}
return false;
}
Also, s1.equals(s2) == true implies s1.compareTo(s2) == 0 (and vice versa), and s1.equals(s2) == false implies s1.compareTo(s2) != 0 (and vice versa).
However, and this is important, this does not have to be the case for all classes. It is for String, but no rule prohibits different natural orders for other classes.
How to truncate string in groovy?
I used:
def c = truncate("abscd adfa dasfds ghisgirs fsdfgf", 10)
but getting error.
The Groovy community has added a take() method which can be used for easy and safe string truncation.
Examples:
"abscd adfa dasfds ghisgirs fsdfgf".take(10) //"abscd adfa"
"It's groovy, man".take(4) //"It's"
"It's groovy, man".take(10000) //"It's groovy, man" (no exception thrown)
There's also a corresponding drop() method:
"It's groovy, man".drop(15) //"n"
"It's groovy, man".drop(5).take(6) //"groovy"
Both take() and drop() are relative to the start of the string, as in "take from the front" and "drop from the front".
Online Groovy console to run the examples:
https://ideone.com/zQD9Om — (note: the UI is really bad)
For additional information, see "Add a take method to Collections, Iterators, Arrays":
https://issues.apache.org/jira/browse/GROOVY-4865
In Groovy, strings can be considered as ranges of characters. As a consequence, you can simply use range indexing features of Groovy and do myString[startIndex..endIndex].
As an example,
"012345678901234567890123456789"[0..10]
outputs
"0123456789"
we can simply use range indexing features of Groovy and do someString[startIndex..endIndex].
For example:
def str = "abcdefgh"
def outputTrunc = str[2..5]
print outputTrunc
Console:
"cde"
To avoid word break you can make use of the java.text.BreakIterator. This will truncate a string to the closest word boundary after a number of characters.
Example
package com.example
import java.text.BreakIterator
class exampleClass {
private truncate( String content, int contentLength ) {
def result
//Is content > than the contentLength?
if(content.size() > contentLength) {
BreakIterator bi = BreakIterator.getWordInstance()
bi.setText(content);
def first_after = bi.following(contentLength)
//Truncate
result = content.substring(0, first_after) + "..."
} else {
result = content
}
return result
}
}
Here's my helper functions to to solve this kinda problem. In many cases you'll probably want to truncate by-word rather than by-characters so I pasted the function for that as well.
public static String truncate(String self, int limit) {
if (limit >= self.length())
return self;
return self.substring(0, limit);
}
public static String truncate(String self, int hardLimit, String nonWordPattern) {
if (hardLimit >= self.length())
return self;
int softLimit = 0;
Matcher matcher = compile(nonWordPattern, CASE_INSENSITIVE | UNICODE_CHARACTER_CLASS).matcher(self);
while (matcher.find()) {
if (matcher.start() > hardLimit)
break;
softLimit = matcher.start();
}
return truncate(self, softLimit);
}