Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Grooscript

 Grooscript

Groovy to javascript transpiler presented at Gr8Conf in Copenhagen 2014

Jorge Franco

June 03, 2014
Tweet

More Decks by Jorge Franco

Other Decks in Programming

Transcript

  1. About me Developer, I love it Lazy in english at

    school Living in Madrid Working at Osoco Grooscript developer @jfrancoleza [email protected]
  2. Do something! No excuses You can do a library, resolve

    issues, create a plugin, give feedback, help other projects, … ! You will learn a lot
  3. Groovy to Javascript converter Groovy 2 to Javascript ECMAScript 5

    Open source project, Apache 2 license Library with Groovy and GPars dependencies No special Javascript objects or functions Converted code requires grooscript.js to run Different conversion options Grails plugin, npm package, gradle plugin What is grooscript?
  4. Groovy code def sayHello = { -> println "Hello ${it}!"

    } [‘Groovy', ‘JavaScript', 'GrooScript'].each sayHello ! assert [1, 2, 3].size() == 3 class Amazing {} ! amazing = new Amazing() amazing.metaClass.who = [] amazing.metaClass.add = { who << it} ! amazing.add 'Rafa Nadal' assert amazing.who.size() == 1
  5. Javascript result function Amazing() { var gSobject = gs.inherit(gs.baseClass,'Amazing'); gSobject.clazz

    = { name: 'Amazing', simpleName: 'Amazing'}; gSobject.clazz.superclass = { name: 'java.lang.Object', simpleName: 'Object'}; if (arguments.length == 1) {gs.passMapToObject(arguments[0],gSobject);}; return gSobject; }; var sayHello = function(it) { return gs.println("Hello " + (it) + "!"); }; gs.mc(gs.list(["Groovy" , "JavaScript" , "GrooScript"]),"each",[sayHello]); gs.assert(gs.equals(gs.mc(gs.list([1 , 2 , 3]),"size",[]), 3), null); amazing = Amazing(); gs.sp((amazing = gs.metaClass(amazing)),"who",gs.list([])); gs.sp((amazing = gs.metaClass(amazing)),"add",function(it) { return gs.mc(gs.fs('who', this),'leftShift', gs.list([it])); }); gs.mc(amazing,"add",["Rafa Nadal"]); gs.assert(gs.equals(gs.mc(gs.gp(amazing,"who"),"size",[]), 1), null); Class Default constructor Function New
  6. Javascript Groovy Java More Javascript friendly Types, inheritance, java 8,

    … metaClass Lists Closures Operators Dsl’s Expando Maps beans methodMissing Mixins Categories Traits delegate propertyMissing
  7. Using converted code in javascript Create classes NameClass(); Default constructor

    with js object NameClass({property: value, data: 1}); Call methods, basic parameters myObject.method(params); Access properties myObject.property = 4; Use functions as closures list.each(function () { … }); Traits Metaprogramming Mixins, Categories Groovy types gs.map({}); gs.set(); gs.range(1, 5); gs.date(); gs.regExp(); gs.stringBuffer(); … Groovy list functions added to js lists Added some functions to numbers and strings (1).times(function () {}); “Groovy”.startsWith(); “Hello”.replaceAll(); Added curry to functions Convert objects ‘to groovy’ or ‘to javascript’ gs.toGroovy(javaScriptList, NameClass); gs.toJavascript(myGroovyObject); Operators Groovy truth equals getters and setters Conversions gs.toGroovy(obj, Type); gs.toJavascript();
  8. Limitations Groovy / Java not fully supported Working in groovy-core

    No good support for inheritance (super) No methods with same name Basic support in metaClass No packages, no classes with same name No metainfo, expandoMetaClass, … Only AST transformations applied in semantic phase No complex Java / Groovy types (Thread, Stack,…) … see documentation for more info on grooscript.org
  9. Directly convert code @Grab(‘org.grooscript:grooscript:0.5.1’) ! import org.grooscript.GrooScript ! //Convert a

    fragment code String jsResult = GrooScript.convert(“println ‘Hello!’”) ! //Convert some file or folder, generate .js files with same name GrooScript.convert(‘path/to/file.groovy’, ‘destination/folder’) GrooScript.convert(‘path/to/folder’, ‘destination/folder’) GrooScript.convert(listOfFilesAndOrFolders, ‘destination/folder’)
  10. Conversion options convertDependencies - boolean - default true classPath -

    List<String> or String - default null - Ex: ‘src/groovy’ customization - Closure - default null mainContextScope - List<String> - default null initialText / finalText - String - default null recursive - boolean - default false includeJsLib - String - default null - Ex: ‘grooscript-all’ //Set a conversion property GrooScript.setConversionProperty(‘convertDependencies’, false) GrooScript.setConversionProperty(‘customization’, { ast(TypeChecked) })
  11. Main context scope Customization • Requires Groovy 2.1, the closure

    is passed to withConfig(conf) • More info in http://docs.codehaus.org/display/GROOVY/Advanced+compiler+configuration • Sometimes you don’t know where to find a variable • When conversion is done, some variables come from other contexts • grooscript.js sometimes tries to find missed variables with eval • Node.js eval not working same way that browsers do • You can define variables or function names with this option • Ex. [‘$’, ‘myAwesomeFunction’, ‘myMissedVariable’]
  12. >phantomjs myTest.js Inject grooscript.js and jquery Use Groovy script abilities

    I want to be Groovy @AST http://phantomjs.org/ Please code in Groovy!
  13. @PhantomJsTest(url = ‘index.html’, capture = ‘capture.png’) void testExpectedElements(element, expectedSize) {

    assert $(element).size() == expectedSize, ‘Unexpected size’ } Mandatory Screen capture Accepts basic parameters Works fine in GroovyTestCase Not so well in Spock Have to define Phantom.js path Feature: PhantomJsTest
  14. Example @GrabConfig(systemClassLoader = true) @Grab(‘org.grooscript:grooscript:0.5.1’) ! import org.grooscript.asts.PhantomJsTest ! //Need

    phantoms installed System.setProperty(‘PHANTOMJS_HOME’, ‘path/to/phantomjs’) ! @PhantomJsTest(url = ‘http://www.grails.org’) void grailsSiteChecks() { assert $(‘a’).size() > 50, “Not enough links ${$(‘a’).size()}” def title = $(“title”) assert title[0].text == ‘Grails - The search is over.’ $(‘a’).each { println it } } ! //Run phantomjs test grailsSiteChecks()
  15. package org.grooscript.builder ! class HtmlBuilder { ! String html !

    static String build(@DelegatesTo(HtmlBuilder) Closure closure) { def mc = new ExpandoMetaClass(HtmlBuilder, false, true) mc.initialize() def builder = new HtmlBuilder() builder.metaClass = mc closure.delegate = builder closure() ! builder.html } ! def yield(String text) { html += text } ! def methodMissing(String name, args) { … } } Feature: html builder def result = HtmlBuilder.build { body { ul(class: 'list', id: 'mainList') { 2.times { number -> li number + 'Hello!' } } } } ! assert result == ‘<body><ul class='list' id='mainList'><li>0Hello!</li><li>1Hello!</ li></ul></body>’ grooscript-builder.js
  16. Feature: jquery tools package org.grooscript.jquery ! interface GQuery { def

    bind(String selector, target, String nameProperty) def bind(String selector, target, String nameProperty, Closure closure) boolean existsId(String id) boolean existsName(String name) boolean existsGroup(String name) void bindEvent(String id, String name, Closure func) void doRemoteCall(String url, String type, params, Closure onSuccess, Closure onFailure) void doRemoteCall(String url, String type, params, Closure onSuccess, Closure onFailure, objectResult) void onReady(Closure func) void html(String selector, String text) } import org.grooscript.jquery ! GQuery gQuery = new GQueryImpl() gQueryImpl.js
  17. Feature: binder grooscript-binder.js package org.grooscript.jquery ! class Binder { !

    GQuery gQuery = new GQueryImpl() ! def bindAllProperties(target, closure = null) { target.properties.each { name, value -> if (gQuery.existsId(name)) { gQuery.bind("#$name", target, name, closure) } if (gQuery.existsName(name)) { gQuery.bind("[name='$name']", target, name, closure) } if (gQuery.existsGroup(name)) { gQuery.bind("input:radio[name=${name}]", target, name, closure) } } } ! def bindAllMethods(target) { target.metaClass.methods.each { method -> if (method.name.endsWith('Click')) { def shortName = method.name.substring(0, method.name.length() - 5) if (gQuery.existsId(shortName)) { gQuery.bindEvent(shortName, 'click', target.&"${method.name}") } } } } ! def call(target, closure = null) { bindAllProperties(target, closure) bindAllMethods(target) } } Bind an instance properties to input elements, by Id or name Bind on click events to an instance methods new Binder()(myInstance)
  18. Grooscript Vert.x Plugin Convert Groovy code to Javascript Run conversion

    daemon Websockets Eventbus bridge New port open Events in the client Auto reload pages Both are optional http://grooscript.org/pluginManual/ v 1.3.1 Requires Java 1.7
  19. Differences? Renders on server Renders on the client Conversions are

    cached with cache plugin Grooscript tags auto - import js files needed
  20. Grails port 8080 Vert.x port 8085 Browser gsp eventBus http

    websockets Config.groovy BootStrap.groovy Chat sample main.gsp
  21. More events Html Builder Where Listen events Render on load

    Send event message = println Execute on event message Don’t use ${} in grooscript tags Strong dependency Resources plugin Can put code in a .groovy file
  22. Domain classes in the client* *Experimental, it requires Groovy 2.1

    (grails 2.3) • validate, clientValidations ** • hasErrors • count • list * without params • get • save * without params • delete
  23. Domain classes connected with the server* *Experimental, it requires Groovy

    2.1 (grails 2.3) • list • get • save • delete
  24. PhantomJs Tests* *Not working in Grails 2.3, need improvements New

    test phase phantomjs Tests in test/phantomjs More features
  25. features, features… next release - new plugin - remove vert.x

    From resources plugin to Require.js or Asset pipeline plugin Improve domain options PhantomJs tests improvements Move to websockets/sockJs/stomp with Spring 4 in grails 2.4 … Remote domain class to grails REST support
  26. Gradle plugin Add in your build.gradle http://grooscript.wordpress.com/2014/02/22/starting-with-grooscript/ buildscript { repositories

    { mavenCentral() } dependencies { classpath 'org.grooscript:grooscript-gradle-plugin:0.3' } } ! apply plugin: 'grooscript' ! //If you need to change any conversion option, can do this way, optional grooscript { source = [‘src/main/groovy/presenters'] }
  27. Demo springboot http://projects.spring.io/spring-boot/ REST - Require.js - Grooscript Gradle Plugin

    - Websockets - Mongo https://github.com/chiquitinxx/springboot-rest-demo http://frameworks-groovygs.rhcloud.com/
  28. Examples using groovy in Node.js Node.js is very fast! http://grooscript.wordpress.com/2014/01/10/impressive-node-js-v8-speed/

    http://grooscript.wordpress.com/2014/05/20/grooving-node-js-modules/ https://github.com/chiquitinxx/colors
  29. //Dsl using express with Node.js server { get('/') { render

    'Hello World!' } get('/spain') { render 'World champion football 2010 :)’ } get('/salute/:name') { render "Hello ${req.params.name}!" } }.start(3000)
  30. Why would I use grooscript? • You can continue developing

    in Groovy • Can use dsl’s, typeCheck, AST’s,… in the browser • You have all the java tools and IDE’s • You can work with new Javascript tools from Groovy • Don’t repeat code in two languages • Single development environment • Create your own architecture in Groovy • Don’t learn another “to Javascript” tool
  31. Community will decide Future Version 0.5.1, you can improve I

    will continue improving grooscript Never will support full Groovy / Java I’m learning a lot, very fun New grails plugin in summer Focus next version: more and better java and groovy support
  32. Thank you! All people reading this 680 motivation clicks Jetbrains

    for IntelliJ IDEA v13 open source license Special thanks to René, @glaforge @marioggar @CedricChampeau @burtbeckwith