Following Tutorial at http://groovy.codehaus.org/Beginners+Tutorial Groovy has no do/until construct. Use 'while'. Logical exprs. Still need (...) after 'if' and such, but numerical expressions can be evaluated for T/F just like in C. More convenient than Java, like scripting languages, (null), (''), (0) are all valid tests and evaluate to false. This works perfectly for literals and vars, and with !thing. Need to set env. var GROOVY_HOME Executables in $GROOVY_HOME/bin GroovyConsole for obvious purpose groovy is CLI like "perl" and requires an inline script or file name. http://groovy.codehaus.org/Groovy+CLI _ is like Perl $_ with -n switch. groovysh. If give expression on command line, will not be interactive (just like "groovy -e 'expr...'"). I like "-q" switch. Lacks useful -e, -n, -a switches of "groovy". Has wacky variable scope rules. typed nor def'd variables at root level visible at root lvl. ???: GroovyC startGroovy Global configs in $GROOVY_HOME/conf/groovy-starter.conf. Comments in tha file point you to JavaDoc page with syntax details. Grape: grab() method which hooks into Ivy to obtain dependency libs. http://groovy.codehaus.org/Grape (a section of User Guide) Usage: @Grab(group='org.springframework', module='spring', version='2.5.6') import org.springframework.jdbc.core.JdbcTemplate Setup. Uses an ivysettings.xml found in this precedence: - defaultGrapeConfig.xml in the jar - the one in, say, GROOVY_HOME/conf - Java system property grape.config - ~/.groovy/grapeConfig.xml Loosely typed. Don't need to define variables or set their type. Don't need to use parens around parameter lists. I don't know about 0-param methods though. Code lists exactly like array constants. Empty list: [] Code maps just like JSON maps EXCEPT ENCLOSED BY [] NOT {}; [name:'val', otherKey: 'otherval] Assign map['key'] = 5. mput.pub('key', 5) map.key = 5 Reference values: either map.key map['key']. Empty map: [:] Global (LIKE?) functions: print "msg" OR print("msg") Script invocation parameters available as String[] args. [s1, s2] as String[] == [s1, s2].toArray(new String[0]) File Inclusion run(new File('u.groovy'), args) // 2nd param must be a real String[] run(new File('u.groovy'), ['one', 'new File('two.text').absolutePath] as String[] If you need a class, then simply name the script file as the class in it (just like you would in java) and use the class. Therefore, your x.groovy class name must have a valid Java class name before the suffix. (But in this case Groovy somehow allows class names starting with lower-case... but there are other problems with lower-case-beginning class names). A much better way is to just code classes with static methods with explicit "class" declarations. Only problem is msysgit isn't doing the CLASSPATH lookups right, apparently. "def" == "Object"/"void". See note about variable scopes in 'groovysh' section. 2 types of variables: Defined with either a type name or "def". These are regularly scoped. Binding (undefined). Global. Grails = Groovy on Rails (emulating Ruby on Rails) All basic java.* package classes and a couple groovy.*'s are imported by default. import statements must be at root level (can not be inside a class). BUILDERS Most standard builder is the XML builder: groovy.xml.MarkupBuilder. Constructor takes outputStream or Writer, defaulting to stdout. (... or an Indentprinter). Consequently by default they write to stdout as soon as they execute. You add nodes onto the Builder (this being the root node) or onto other nodes by invoking nodeCreationMethods. builder.nodeCreationMethod PARAMS OR ancestorStuff... {... nodeCreationMethod PARAMS nodeCreationMethod syntax. Parens optional (required for precedence or line continuation purposes). One of: newNodeName object // object.toString becomes node text content newNodeName map // newNN a:'str', b:2 OR newNN mName OR newNN [...] newNodeName {closure} // closure may be empty OR ANY COMBINATION of the above, with closure always last if present. Can only have 0 or 1 of each of the 3 params. 3 ways to make a name-only node: newNodeName() OR newNodeName [:] OR newNodeName {} Closures inside Builder-node-creation-block: Can use variables like any Groovy closure/body. If just reference a new variable, it's created as a global bind var. For each statement within each closure: If first token resolves to a known Groovy command/object/method, then it executes as normal. Otherwise statement is a newNodeName statement as explained above. CLASSES Use defs for local vars inside methods, I guess. To have automatic getter created for a field, create it final with no visibility. To have automattic getter and setter created, create field w/ no visib. (buuuuut I notice that private fields are writable from outside the class! == means equals(). Function/method/closure calls Only need parentheses if otherwise ambiguous. Can call with named-params semis optional unless multiple statements on a single line; or to set off instance initializers. LINE BREAKS: If you want an expression to span a line, then you must force it somehow, like by using parens around the entire expression. return tatements are optional. Methods by default will return the value of the last statement executed in the body. aList[2] === aList.get(2) Throw/Catch exactly same as Java. Default visibility is default! Seems that native arrays are barely supported. No .length operator. CONVERT YOUR NATIVES TO COLLECTIONS EARLY!: Arrays.asList(nativeArray) etc. nativeArray as ArrayList MAY? accomplish the same thing? There is no convenience .length for Strings. Must use .length() just like with Java. Can sometime trigger this automatically by just assigning to a collection, like List depEls = aString.split(/[\s,]+/) Benefit is that you can use the much simpler native syntax to work with Collections. You can use the 'as X' suffix to convert collections to/from Groovy-enhanced types. One time I couldn't use enhanced Groovy collection operators unless I declared the collection variable with def (a.o.t. the Java collection type). COLLECTION GOTCHA This is a specific case of general Groovy limitation that .method invocations only work for get* methods: Must explicitly use .size() for collections. Getting Started Guide is excellent. http://groovy.codehaus.org/Getting+Started+Guide Requires back-slashes in GROOVY_HOME value in Windows!!! groovysh has \special commands just like SqlTool! list << element // append? Closure is a variable with value of code block (hence maps do not use curlies). Declare before point of usage Execute them directly with parens just like a method or function. Some provided methods take these closures as parameters. By default just 1 param supported, value passed to "it". Explicit params: { p0, p1 -> body } Scoped (local at least) vars are inherited into the body at runtime. Closures differ from functions in that higher vars are iherited and params not declared in signature and must be declared before usage. May skip parens surrounding single {closure} param, or may move a final closure to after the parens, as long as the { does not start on a new line. Closures have 3 contexts tracked. this: Normal code-location instance that contains the code. owner: this or super-closure delegate: defaults to this but may be assigned (like to use a calling context instance) SCRIPTS (a.o.t. Gojos) Functions: def fnName(param1, param2) {... }. Nearly intuitive. Contrary to docs, you do not have to type it with 'def' (equivalent to Object). An instance method is indeed generated from this. Script body consists of: class definitions + method definitions + other statements Method definitions become methods in the script AutoClass, defaulting, of course, to instance methods. 'other statements' all end up in AutoClass.main(String[]) or perhaps run() (after setting binding var map). As a consequence of these rules, it is IMPOSSIBLE TO USE instance OR static VARIABLES! Any attempted field definitions become local variables in the generated main() or run() method body. DUAL-USE Script auto-classes are just unsuitable for general OO or static usage, since auto-classes don't support instance or static variables. For a real OO or static class, you will have to code an explicit Gojo class, and since you obviously can't use same class name as the auto-class name, you might as well put it into an independent file named according to the intuitive Java convention instead of hiding it inside a script file. Occurrences of ${expr} inside of "" string literals do execute and output string contains the final output of the expression execution. E.g. can do "Pre ${otherFi = new File('x.k'); 'insertion'} Post" expression execution. Typical scripting diff between ' and ". ' substitition: NONE GString " substitution: GOTCHA: [] do not work (without ${...} subexpressions) ${...} do not just 'delimit' like in other languages. Obviously need to escape when you want output string to actually contain a $, like: \$ The $ things do not have to be Strings. .toString() will apply as desired. $var and $var.field As long as the end of this can be distinguished (i.e. "$varother" and "$var.fieldother" would not work. A dot without a letter after it does work as post-variable-name char: "$var. " expands to "value. ". All other forms, incl., $var['x'] and $var.meth() require {}: ${var[x]} """ or ''' for multi-line Strings, just like Python. Otherwise termd like Java. Nicety about quotes at very beginning or end of """ or ''' strings. You string just can not end with the used quote character. It can begin with it. /slashed-strings/ The document gives the impression that these are very general low-level objects like string constants, but they are not. They work fine enough as regular expressions which do not contain /, but don't try to use them for non-regular-expressions. GREAT IDIOM: Instead of the hack-with-side-effects of using "Deb's hair" to allow for unquoted single-quote in the string, use the safer '''Deb's hair'''. Map literals: Keys different from all other languages. If a non-String, a typed literal. If a non-quoted String, then auto-quoted. (Can quote if wish) if (astring) then the dereferenced variable value. MAPS. Seems impossible to access Map class fields like aMap.class, since that would look for a map element with key "class". .class For some reason o.class.name works, but not in Gstring: "$o.class.name". COLLECTION GOTCHA This is a specific case of general Groovy limitation that .method invocations only work for get* methods: Must explicitly use .size() for collections. PROVIDED METHODS See https://github.com/unsaved/gradle-javaPropFile-plugin/raw/master/README.txt map.each(kvClosure) // Where the closure takes params it.key and it.value map.each(kvClosure) // By default 'it' is entry, so you can it.key/it.value // If you specify 2 params then they get key and values. list.each(eClosure) // Where the closure takes param Element (can "it") nice .eachWithIndex facilitates parallel iteration. (For "file" methods shown here, I haven't looked into whether they are available only for 'def x = file's, or for all File instances.) List file.readLines() String X.getText() == X.text (of course) String file.text() String file.getText("charset") String inputStream.text() String inputStream.getText("charset") String addr.toURL().openStream().text String addr.toURL().openStream().getText("charset") // ditto // write()s REPLACE the file void file.write(string), file.write(string, "encoding") DO THEY CLOSE? void file.append(string), file.append(string, "encoding") DO THEY CLOSE? byte[] file.bytes file.eachLine(lClosure) // same as file.readLines().each(lClosure) File.deleteDir() // recursive object.is(otherObject) tests for real object identity CONVERION METHODS LIKE x.toType() ARE USELESS. x.parseType() and similar serve the same purposes. FILE COPYING: (Can append with append instead) TEXT FILES: destFile.write(srcFile.getText('ISO-8859-1'), 'ISO-8859-1') BINARY FILES: destFile.setBytes(srcFile.bytes) groovy.sql.Sql; con = Sql.newInstance(jdbcUrl, u, p[, driverClassName]) con.eachRow(query, {closure with it == row}) row = con.firstRow(query) // For a single row Insert/Delete/Update with or without Prepare: execute[Update] boolean execute(...) or int execute(...) con.execute("insert statement values (?, ?)", [val...]) con.execute("Insert statement values (${expr})") Can somehow instantiate your own classes like Cl(GroovyRowResult). (I don't know how fields or properties are matched. Field reflection?) There is a Class for dynamic objects very similar to JavaScript objects. GOTCHA!!! Seems that your class names must start with a capital letter. The file names too, even on Windows. Events/Listening done entirely different from Java, w/ Closures. IMPLICIT CONSTRUCTORS: x = [cons.params] // after x has been typed as ClassName OR def x = [cons.params] as ClassName REGEXs It is not regex-specific, but you must add an extra \ before $ in any Gstring. (also obviously in the replacement literals like "\$1" but '$1'). /.../ construct just reverses escaping needs between \ and /, since regexs often include \ characters. Therefore, wherever I say patStr below, you may use a regular string or /one of these/ N.b. /this/ does not instantiate a Pattern or anything other than a String. RE matching: doesMatch = strExpr ==~ patStr // i.e. .matcher().matches() op. === (strExpr =~ patStr).matches() As per Matcher.matches(), obviously must match the entire expression. RE capturing: Matcher matcher = strEx =~ patStr OR: Matcher matcher = strEx =~ regexPattern ??? may not re-use! (May cast it to String and then create another Pattern) If you want to have a reusable Pattern, I guess you need to make one the old-fashioned way. But it MAY make no diff. if you use it with =~ (see abv). referencing matcher[i] Attempts to do as many find() as possible. populating matcher[i] with the 0-shifted .group() array for find # i. Since the great majority of the time I want .matches() capturing, not find() capturing, DO NOT USE matcher[i]. RECAP: If want to re-use a Pattern for efficiency, FUCK Groovy regex until they do it efficiently. For a one-time pattern use, DO THIS: java.util.regex.Matcher m = candidateStr =~ patStr if (m.matches()) { // use m.group(), m.groupCount(), m.group(int) Groovlets (name files x.groovy) http://www.javabeat.net/articles/58-web-development-in-groovy-using-groovlets-2.html Just groovy.servlet.GroovyServlet typically serves *.groovy url-pattern. You get implicit variables like a JSP would and methods. See: http://groovy.codehaus.org/gapi/groovy/servlet/ServletBinding.html printing goes to client. Can optionally use 'html' which is bound to new MarkupBuilder(out) done just like Groovy XML. html.html { head { title 'Groovy Test' } body { h1 'Groovy page called table(border:'2') { tr() { td("... } } // Can put quotes around the method param strings. Requires: groovy.jar + antlr.jar + asm.jar. Exec'ing external programs: def p = "cp file1 file2".execute() println p.text p.waitFor() // Returns same value as additional .exitValue()s will. For non-trivial control, you need to use Java 1.5's ProcessBuilder. I don't understand closure delegates. System properties via System.properties["prop.name"] var.x Runs var.getX() or var.isX() or var.x var.x = y Runs var.setX(y) TYPING No reason to use generics or otherwise type collections. Just use def. Use typed variables to constrain assignments (with exception noted below), but method and field access is purely runtime and not constrained by syntax at all. Members are coerced to runtime class but allow for both super- and sub-classes, PLUS conversion happens automatically sometimes, like from Integer to Double. Consequently Object vars can assign and be assigned to anything. Unlike Javascript, you can't add a new member by doing existingVar.newMember = 4 The assignment type checking also applies to method definitions, so use typed parameter placeholders. Groovy has no "foreach". Use either 'for (x in...)' or 'for (x :...)'. Types of iteration variables have absolutely no effect. Don't waste effort doing more than for (d in... for (def d : ... The weirdness is not that the elements are read as Objects, since that is what Groovy always does with Collections, but that the type may be specified but is ?. operator: Just like . but null-safe: foo?.something?.myMethod() You insert the '?' AFTER the thing which may be null. So, remember that whenever you code x = ...?..., you must handle case of x being assigned null. TIP: Gradle, at least, uses a lot of Sets. To get the first item of a set, use the idiom: set.toArray()[0] Collection.find({closure}) returns first item where (closure) true. Collection.findAll({closure}) returns another collection where (closure) true. Appending to collections: coll << 3 << 4 BUT NO: coll << [3, 4] // This adds a collection instance to col Instead do: coll = coll + [3, 4] OR coll.addAll([3, 4]) (depending whether can change the instance reference) Can -, +, +=, -=, etc. with non-map collectins. Works intuitively. Fetching via URL: addr.toURL().text or addr.toURL().getText("encoding") If need to do more, use with*() or: http download http://groovy.codehaus.org/Simple+file+download+from+URL No way for recursive fetches. [Groovy has no "file(...)" method. That is Gradle's thing.] See "gradle.txt" about variable scope. Much of that is Groovy-specific not Gradle-specific. Parsing HTML http://www.frothandjava.com/2007/06/html-screen-scraping-with-groovy.html with*([String, ] closer) methods Get Streams/Readers/Writers and to operate with inside, and makes sure they get closed. withReader(closer) and with printing empty line: Must use parens in this one case: println() If print or logger.* parameter spans lines, then must use parens. logger and prints may certainly take multiple args without parens, as long as dont' span multiple lines: logger.error aMap.size() + " a Gstr ($aMap)" GPathResult's Slurper parse methods return GPathResults. For some reason not in default path, so if want strict type enforcement: import groovy.util.slurpersupport.GPathResult GPathResult topNode = new XmlSlurper().parseText(xmlString) COOL! Get tag name like gPathR.name() // NOT A GETTER so must use (). Get elements like parent.child (List) Get attrs like el.@attr or el['@attr'] Get el body like n.text() .parent(), .children(), .name() Searches: DIRECT CHILDREN ONLY!!! newGPathR = gPathR.find { it.@id == 'x' } newGPathRs = gPathR.findAll { it.@id == 'x' } RECURSIVE newGPathR = gPathR.'**'.find { it.@id == 'x' } newGPathRs = gPathR.'**'.findAll { it.@id == 'x' } (The "'**'" is a shortcut for node.depthFirst().find* {... ) I don't understand the use for "Attributes" plural, since .list().size() is always 0 if attribute not present or 1 if it's present. Instead of dealing with .list() or .iterator(), just read with .text() Somehow can assign Strings to Attributes. That is the way to assign! GOTCHA: N.b. can not use a reference for x.@attr, must assign directly! or some reason, it is not an error to reference gPathr.nosuchthing Funny thing is that gPathr.nosuchthing is really fantastical. It prints as an empty string, but thing.class.name also prints as an empty string. But you can always run gPathr.anything.isEmpth(). To declare fields (instance or static), you must explicitly define a class with "class". Otherwise root-level variable declarations make it into the local binding instead of into the class. SCRIPTS A Script 'class' is only generated if the .groovy file contains code outside of class definitions. The name will the the file name base. A GroovyObject 'class' is generated from every instance of explicit 'class{...}'. Therefore, you can not have a script (i.e. .groovy with code outside of explicit class defs) that also has an explicit class def of the script name. EOLS println variants all write the platform-specific EOL. \n's in any strings at all do not. Line breaks in ''' and """ multi-line GStrings output only \n. includes must be at root level (but not at beginning of file) Gojo = Groovy (traditional) class TemplateEngines SimpleTemplateEngine. Basically GString template. Of course do not double-quote the tpl string. Variable map specified instead of using all program variables in scope. The variable map is from String to any other type. In the case of template $varname usage, the values will be toString()d. The variables in the map are not just for direct display purposes, but may be used in ${...}, <%...%>, or <%=...%> scriptlets. import groovy.text.SimpleTemplateEngine <% scriptlet code without outputting %> print target are so as to end up in output string. <%=....%> is exactly same as ${...} new SimpleTemplateEngine().createTemplate(gstring).make(varMap).toString() OR ... stream or file Backslashes and double quotes need extra escaping. Scriptlets don't have access to the program variables (even global statics). GStringTemplateEngine Same, but append to 'out' object in scriptlets instead of prints. new GStringTemplateEngine().createTemplate(file).make(varMap).toString() XmlTemplateEngine Template and output are valid XML. GSP = Groovy Server Pages = TemplateServlet input files. Requires: groovy.jar + antlr.jar + asm.jar. Like Groovy scripts, in that non-method, non-class statements get into a servlet service method (where stdout gets routed to user over http). I guess, like scripts, that method definitions become instance definitions, and due to Servlet spec, are not thread safe. ?? I guess, like scripts, there is no ability to create or use static or instance variables. Very much like JSP Map *.gsp files to this servlet in web.xml. For var map, you get the standard Groovlet implicit vars... that's it! Set content type like <% response.contentType = 'text/plain' %> MVC In ... do request.setAttribute(key, aval)... then forward("desg.gsp", request, response) Unfortunately, the GSP can only get the values manually through the request implicit in the var map. FROM EXAMPLE BUT THIS LOOKS WRONG: <%= "${request.getAttribute("qinsert")}" %> DEBUGGING Compile to .class with: groovyc file.groovy Then run "javap -pringave pkg.ClassName" To execute the class, need your class, groovy-*.jar, and asm-*.jar in -cp. Definitely can overload methods according to normal Java rules Definitely can overload methods according to normal Java rules