June 2nd - 4th 2015
Copenhagen, Denmark
Grooscript in Action
Jorge Franco
@jfrancoleza
jorge.franco.leza@gmail.com
Developer
NEWS
v1.1.1
INFO
• Library (JAR)
• Groovy 2.0+ to javascript ECMA 5
• Apache 2 License
• Converted code needs grooscript.js
• Tools: gradle, grails, npm/bower
LINKS
• Website http://grooscript.org
• Documentation http://grooscript.org/doc.html
• Github https://github.com/chiquitinxx/grooscript
• Demos https://github.com/chiquitinxx/grooscript-demos
• Twitter @grooscript
• Try live! http://grooscript.org/conversions.html
CONVERT GROOVY CODE
Groovy / java code to javascript code
Groovy / java file to javascript file
Folder to folder or javascript file
List of files / folders to folder or javascript file
@Grab('org.grooscript:grooscript:1.1.1')
import org.grooscript.GrooScript
String result = GrooScript.convert '''
def sayHello = { println "Hello ${it}!" }
['Groovy','JavaScript','GrooScript'].each sayHello
'''
println result
CONVERSION OPTIONS
• classPath - List of folders or jar’s to find dependencies. Before groovy code is converted to javascript, that code have to
be successfully compiled. For example: [''src/groovy'']
• customization - to each file to be converted, will be applied a groovy customization. For example you can for example
type check all the groovy classes to be converted with { -> ast(TypeChecked)}
• initialText / finalText - you can add test at the beginning or end of your converted javascript file.You can add comments
or javascript code. For example: ''//This code has been generated with grooscript''
• recursive - if you specify a folder with the source conversion option, by default will not convert files inside folders.To
convert recursive, just set to true
• mainContextScope - you can help the converted, specifying functions and variables that will be available in the main
context of the javascript environment. For example: [''$'', ''window'',''myFunction'']
• addGsLib - you can add a grooscript js lib at the beginning of the converted file. For example you can add grooscript.js
to the result, and then you don’t have to worry about include that dependency in javascript ''grooscript''
SUPPORT
SEE DOCUMENTATION
• groovy-core
• classes, numbers, lists, maps, sets, date, ranges, closures,AST’s,
(g)strings, operators, groovy truth, Expando, categories, traits,
beans, switch, metaprogramming, enum, equals, multiple
assignment, optional params, default constructor, pointer methods,
operator overload, regular expressions, @Delegate, @Category, …
NOT SUPPORTED
SEE DOCUMENTATION
• Non groovy-core (json, builders, I/O, …)
• Java / GroovyTypes (Thread, LinkedHashMap, Stack, …)
• Super
• Methods with same name (overload), classes with same name
• Java 8 stuff not supported by groovy
• Module extensions, complex metaprogramming, groovy AST’s
after Semantic Phase
@GsNotConvert
@GsNative
import org.grooscript.asts.GsNative
class Data {
@GsNative
def saySomething(some) {/*
console.log(some);
*/}
@GsNative
def five() {/*
return 5;
*/ 1 + 1 + 3
}
}
import org.grooscript.asts.GsNotConvert
@GsNotConvert
class ClassNotConvert {
def a
}
class A {
@GsNotConvert
def methodNoConvert() {
‘No!’
}
def hello() {
println ‘Hello!’
}
}
@GrabConfig(systemClassLoader = true)
@Grab(‘org.grooscript:grooscript:1.1.1’)
import org.grooscript.asts.PhantomJsTest
//Need phantomjs installed
System.setProperty(‘PHANTOMJS_HOME’, ‘path/to/phantomjs’)
@PhantomJsTest(url = 'http://beta.groovy-lang.org/')
void testCountLinks() {
def links = $('a')
assert links.size() > 40, "Number of links: ${links.size()}"
links.toArray().collect { it.toString() }.each { link ->
println link
}
}
testCountLinks()
PhantomJsTests
JAVASCRIPT LIBS
• grooscript.js (86 kb) (8 kb minified and gziped)
• grooscript.min.js (33 kb)
• grooscript-tools.js (14 kb)
(GQuery, HtmlBuilder, Observable)
given:
def result = HtmlBuilder.build {
body {
ul(class: 'list', id: 'mainList') {
2.times { number ->
li number + 'Hello!'
}
}
}
}
expect:
result == "<body><ul class='list' id=‘mainList'>
<li>0Hello!</li><li>1Hello!</li></ul></body>"
HtmlBuilder
import org.grooscript.jquery.GQueryImpl
def result = new Result()
def gQuery = new GQueryImpl()
gQuery.onReady {
gQuery.doRemoteCall(“${JSON_ADDRESS}”, 'GET', null, { res ->
gQuery('.result').html('OK')
result = res
}, {
result = 'FAIL!'
}, Result)
}
GQuery
given:
def result = []
Observable.from([1, 5, 9, 12, 3, 8]).
filter { it < 5 }.
map { 'H' * it }.
subscribe { event ->
result << event
}
expect:
result == ['H', 'HHH']
Observable
https://github.com/chiquitinxx/grooscript-gradle-plugin
http://grooscript.org/starting_gradle.html
http://grooscript.org/gradle/tasks.html
DEMO
https://github.com/chiquitinxx/books-demo
Server Browser
GTPLGTPLGTPL
BookPresenter.groovy
Book.groovy
Springboot
Websockets
Mongo
SockJs
stomp
jQuery
grooscript
grooscript-tools
sweet-alert
chartist
time
newBook
listOfBooks
bookAdded
groovy traits
Counter.groovy
StompClient.groovy
reload
Converted
js files
http://grooscript.org/grails-plugin/index.html
https://github.com/chiquitinxx/grails-grooscript
https://github.com/chiquitinxx/grooscript-grails3-plugin
var gs = require('grooscript');
bower install grooscript
WHY GROOSCRIPT?
• You have all the java / groovy tools and IDE’s
• Meet javascript! Create your own libraries
• Don’t repeat code in two languages
• Same templates in client and server
• Single development environment
• Don’t learn another “to Javascript” tool
• Static typed if you want to
• but… mainly… because is…
Concise
Readable
Expressive
@Component

class Counter implements Colorable {



Integer number



void init() {

number = null

}



void render() {

div(class: "widget bg-${randomColor()}") {

if (number) {

p 'Number of books'

em number.toString()

a(href:"#", class:"button",
onclick: 'bookPresenter.showBooks()') {

yield 'Show'

}

} else {

p 'Counting books...'

}

}

}

}
AST’s
Getter / Setters
def start() {
def countries = loadCountries().
findAll { it.population > 100000}.
unique { it.alpha3Code }
countries.each { country ->
customSigma.addNode id: country.alpha3Code,
x: country.latlng[1], color: ‘purple’
}
countries.each { country ->
country.borders?.each { border ->
this.&hello(border)
}
}
updateNumberCountries countries.size()
customSigma.refresh()
}
Groovy Lists and Maps
server {
get('/') {
render Templates.applyTemplate('index.gtpl')
}
on('login') { data, socket ->
if (data.name && !socket.login) {
socket.login = data.name
socket.emit 'loginok', [name: data.name]
socket.broadcast.emit 'loginok', [name: data.name]
}
}
on('msg') { data, socket ->
if (data.msg && socket.login) {
socket.broadcast.emit 'msg', [msg: data.msg]
}
}
on('disconnect') { socket ->
if (socket.login) {
socket.broadcast.emit 'off', [name: socket.login]
}
}
}.start()
Dsl’s
class Hello {
def methodMissing(String name, args) {
println "Hello ${name}!"
}
}
def hello = new Hello()
hello.Groovy()
hello.Javascript()
hello.grooscript()
Metaprogramming
def plus2 = { it + 2 }
def times3 = { it * 3 }
def times3plus2 = plus2 << times3
assert times3plus2(3) == 11
def plus2times3 = times3 << plus2
assert plus2times3.curry(5)() == 21
Functional
NEXT
3 Continuous
Mode
Q & A
Thank you!

Grooscript gr8conf 2015

  • 1.
    June 2nd -4th 2015 Copenhagen, Denmark Grooscript in Action
  • 2.
  • 4.
  • 5.
    INFO • Library (JAR) •Groovy 2.0+ to javascript ECMA 5 • Apache 2 License • Converted code needs grooscript.js • Tools: gradle, grails, npm/bower
  • 6.
    LINKS • Website http://grooscript.org •Documentation http://grooscript.org/doc.html • Github https://github.com/chiquitinxx/grooscript • Demos https://github.com/chiquitinxx/grooscript-demos • Twitter @grooscript • Try live! http://grooscript.org/conversions.html
  • 7.
    CONVERT GROOVY CODE Groovy/ java code to javascript code Groovy / java file to javascript file Folder to folder or javascript file List of files / folders to folder or javascript file @Grab('org.grooscript:grooscript:1.1.1') import org.grooscript.GrooScript String result = GrooScript.convert ''' def sayHello = { println "Hello ${it}!" } ['Groovy','JavaScript','GrooScript'].each sayHello ''' println result
  • 8.
    CONVERSION OPTIONS • classPath- List of folders or jar’s to find dependencies. Before groovy code is converted to javascript, that code have to be successfully compiled. For example: [''src/groovy''] • customization - to each file to be converted, will be applied a groovy customization. For example you can for example type check all the groovy classes to be converted with { -> ast(TypeChecked)} • initialText / finalText - you can add test at the beginning or end of your converted javascript file.You can add comments or javascript code. For example: ''//This code has been generated with grooscript'' • recursive - if you specify a folder with the source conversion option, by default will not convert files inside folders.To convert recursive, just set to true • mainContextScope - you can help the converted, specifying functions and variables that will be available in the main context of the javascript environment. For example: [''$'', ''window'',''myFunction''] • addGsLib - you can add a grooscript js lib at the beginning of the converted file. For example you can add grooscript.js to the result, and then you don’t have to worry about include that dependency in javascript ''grooscript''
  • 9.
    SUPPORT SEE DOCUMENTATION • groovy-core •classes, numbers, lists, maps, sets, date, ranges, closures,AST’s, (g)strings, operators, groovy truth, Expando, categories, traits, beans, switch, metaprogramming, enum, equals, multiple assignment, optional params, default constructor, pointer methods, operator overload, regular expressions, @Delegate, @Category, …
  • 10.
    NOT SUPPORTED SEE DOCUMENTATION •Non groovy-core (json, builders, I/O, …) • Java / GroovyTypes (Thread, LinkedHashMap, Stack, …) • Super • Methods with same name (overload), classes with same name • Java 8 stuff not supported by groovy • Module extensions, complex metaprogramming, groovy AST’s after Semantic Phase
  • 11.
    @GsNotConvert @GsNative import org.grooscript.asts.GsNative class Data{ @GsNative def saySomething(some) {/* console.log(some); */} @GsNative def five() {/* return 5; */ 1 + 1 + 3 } } import org.grooscript.asts.GsNotConvert @GsNotConvert class ClassNotConvert { def a } class A { @GsNotConvert def methodNoConvert() { ‘No!’ } def hello() { println ‘Hello!’ } }
  • 12.
    @GrabConfig(systemClassLoader = true) @Grab(‘org.grooscript:grooscript:1.1.1’) importorg.grooscript.asts.PhantomJsTest //Need phantomjs installed System.setProperty(‘PHANTOMJS_HOME’, ‘path/to/phantomjs’) @PhantomJsTest(url = 'http://beta.groovy-lang.org/') void testCountLinks() { def links = $('a') assert links.size() > 40, "Number of links: ${links.size()}" links.toArray().collect { it.toString() }.each { link -> println link } } testCountLinks() PhantomJsTests
  • 13.
    JAVASCRIPT LIBS • grooscript.js(86 kb) (8 kb minified and gziped) • grooscript.min.js (33 kb) • grooscript-tools.js (14 kb) (GQuery, HtmlBuilder, Observable)
  • 14.
    given: def result =HtmlBuilder.build { body { ul(class: 'list', id: 'mainList') { 2.times { number -> li number + 'Hello!' } } } } expect: result == "<body><ul class='list' id=‘mainList'> <li>0Hello!</li><li>1Hello!</li></ul></body>" HtmlBuilder
  • 15.
    import org.grooscript.jquery.GQueryImpl def result= new Result() def gQuery = new GQueryImpl() gQuery.onReady { gQuery.doRemoteCall(“${JSON_ADDRESS}”, 'GET', null, { res -> gQuery('.result').html('OK') result = res }, { result = 'FAIL!' }, Result) } GQuery
  • 16.
    given: def result =[] Observable.from([1, 5, 9, 12, 3, 8]). filter { it < 5 }. map { 'H' * it }. subscribe { event -> result << event } expect: result == ['H', 'HHH'] Observable
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
    var gs =require('grooscript'); bower install grooscript
  • 22.
    WHY GROOSCRIPT? • Youhave all the java / groovy tools and IDE’s • Meet javascript! Create your own libraries • Don’t repeat code in two languages • Same templates in client and server • Single development environment • Don’t learn another “to Javascript” tool • Static typed if you want to • but… mainly… because is…
  • 23.
  • 24.
    @Component
 class Counter implementsColorable {
 
 Integer number
 
 void init() {
 number = null
 }
 
 void render() {
 div(class: "widget bg-${randomColor()}") {
 if (number) {
 p 'Number of books'
 em number.toString()
 a(href:"#", class:"button", onclick: 'bookPresenter.showBooks()') {
 yield 'Show'
 }
 } else {
 p 'Counting books...'
 }
 }
 }
 } AST’s Getter / Setters
  • 25.
    def start() { defcountries = loadCountries(). findAll { it.population > 100000}. unique { it.alpha3Code } countries.each { country -> customSigma.addNode id: country.alpha3Code, x: country.latlng[1], color: ‘purple’ } countries.each { country -> country.borders?.each { border -> this.&hello(border) } } updateNumberCountries countries.size() customSigma.refresh() } Groovy Lists and Maps
  • 26.
    server { get('/') { renderTemplates.applyTemplate('index.gtpl') } on('login') { data, socket -> if (data.name && !socket.login) { socket.login = data.name socket.emit 'loginok', [name: data.name] socket.broadcast.emit 'loginok', [name: data.name] } } on('msg') { data, socket -> if (data.msg && socket.login) { socket.broadcast.emit 'msg', [msg: data.msg] } } on('disconnect') { socket -> if (socket.login) { socket.broadcast.emit 'off', [name: socket.login] } } }.start() Dsl’s
  • 27.
    class Hello { defmethodMissing(String name, args) { println "Hello ${name}!" } } def hello = new Hello() hello.Groovy() hello.Javascript() hello.grooscript() Metaprogramming
  • 28.
    def plus2 ={ it + 2 } def times3 = { it * 3 } def times3plus2 = plus2 << times3 assert times3plus2(3) == 11 def plus2times3 = times3 << plus2 assert plus2times3.curry(5)() == 21 Functional
  • 29.
  • 30.
  • 31.