Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Groovy vs. JRuby Rod Cope, CTO & Founder OpenLogic, Inc. Goal Learn which is best for you if you only have time to learn one scripting language: Groovy or JRuby OpenLogic Company Confidential Introduction Rod Cope CTO & Founder of OpenLogic 25 years of software development experience IBM Global Services, Anthem, Ericsson, many more OpenLogic, Inc. SLA support, security updates, and indemnification for over 400 Open Source packages (including Groovy and JRuby) Dozens of Fortune 500 customers OSS Census (osscensus.org) Global, community effort to catalog use of open source JRuby client OpenLogic Company Confidential Agenda Code Samples Basic Features Advanced Java Integration Groovy JDK vs. JRuby/Ruby Libraries Advanced Features Demo Conclusion OpenLogic Company Confidential Sample: Java and Groovy! public class Filter { public static void main( String[] args ) { List list = new ArrayList(); list.add("Rod"); list.add("Neeta"); list.add("Eric"); list.add("Missy"); Filter filter = new Filter(); List shorts = filter.filterLongerThan(list, 4); System.out.println(shorts.size()); Iterator iter = shorts.iterator(); while (iter.hasNext()) { System.out.println(iter.next()); } } } public List filterLongerThan(List list, int length) { List result = new ArrayList(); Iterator iter = list.iterator(); while (iter.hasNext()) { String item = (String) iter.next(); if (item.length() <= length) { result.add(item); } } return result; } OpenLogic Company Confidential Groovy! list = ["Rod", "Neeta", "Eric", "Missy"] shorts = list.findAll { name -> name.size() <= 4 } println shorts.size shorts.each { name -> println name } -> 2 -> Rod Eric JRuby! list = ["Rod", "Neeta", "Eric", "Missy"] shorts = list.find_all { |name| name.size <= 4 } puts shorts.size shorts.each { |name| puts name } -> 2 -> Rod Eric OpenLogic Company Confidential Agenda Code Samples Basic Features Advanced Java Integration Groovy JDK vs. JRuby/Ruby Libraries Advanced Features Demo Conclusion OpenLogic Company Confidential Basic Features: Background Groovy Started in 2003 by James Strachan and Bob McWhirter Now led by Guillaume Laforge Dynamic, object-oriented scripting language for the JVM Features of Ruby, Python, and Smalltalk License: Apache 2.0 JRuby Started in 2001 by Jan Arne Petersen Now led by Charles Nutter, Thomas Enebo, Ola Bini, and Nick Sieger Fast Ruby interpreter and JIT/AOT compiler written in Java Tight, bi-directional Java integration License: CPL, GPL, or LGPL OpenLogic Company Confidential Basic Feature Comparison Feature Groovy JRuby Optionals int a = 2 def str = "Hello" a = 2 str = "hello" Native data structure syntax def list = ["Rod",3,new Date()] def map = ["Neeta": 33, "Eric" : 35] list = ["Rod", 3, Time.new] map = { "Neeta" => 33, "Eric" => 35 } Closures/ Blocks map.each { name, age -> println "${name} is ${age}" } map.each { |name, age| puts "#{name} is #{age}" } Regex re = /na.*/ println "name" ==~ re println re ==~ "name" re = /na.*/ puts "name" =~ re puts re =~ "name" //true //false # 0 # 0 Operator Overload def list = [1,2,3] + [4,5,6] println list.join() // 123456 list = [1,2,3] + [4,5,6] puts list.join # 123456 Friendly println [1,2,3].size() println "dog".size() puts [1,2,3].size puts "dog".size // 3 // 3 OpenLogic Company Confidential # 3 # 3 Basic Feature Comparison (cont.) Feature Groovy JRuby Read a file println new File('file.txt').text puts File.new('file.txt').read Interactive Shell groovysh – good, but not very robust jirb – very strong Duck Typing Don't need to implement an interface or use types – they're optional No interfaces or types, just objects that receive messages a = 1000 // Integer a = 1000000000000 // Long a = 1000000000000000000000 // BigInteger a = 1000 // 1000 a = a * a // 1000000 a = a * a // -727379968 a = 1000 // Fixnum a = 10000000000000 // Fixnum a = 1000000000000000000000 // Bignum a = 1000 // 1000 a = a * a // 1000000 a = a * a // 1000000000000 a = a * a // 1000...000000 ... OpenLogic Company Confidential Agenda Code Samples Basic Features Advanced Java Integration Groovy JDK vs. JRuby/Ruby Libraries Advanced Features Demo Conclusion OpenLogic Company Confidential Advanced Java Integration Goal: Use the JScience library (written in Java) Java usage: Amount a1 = Amount.valueOf(3, KILO(GRAM)); Amount a2 = Amount.valueOf("2 kg"); Amount sum = a1.plus(a2); Desired usage: a1 = 3.kg a2 = 2.kg sum = a1 + a2 OpenLogic Company Confidential JScience Usage: JRuby Solution # sample units puts 2.kg # 2 kg puts 3.m # 3 m puts 4.5.in # (4.5 +/- 4.4E-16) in include Java require 'jscience.jar' Unit = javax.measure.unit.Unit Amount = org.jscience.physics.amount.Amount class Numeric def method_missing(sym) Amount.valueOf(self, Unit.valueOf(sym.to_s)) end end OpenLogic Company Confidential JScience Usage: Groovy Solution // sample units println 2.kg println 3.m println 4.5.in // 2 kg // 3 m // (4.5 +/- 4.4E-16) in import javax.measure.unit.* import org.jscience.physics.amount.* // Let ExpandoMetaClass traverse class hierarchies // so properties added to Number are available in // Integer or BigDecimal, etc. ExpandoMetaClass.enableGlobally() Number.metaClass.getProperty = { String symbol -> Amount.valueOf(delegate, Unit.valueOf(symbol)) } OpenLogic Company Confidential JScience Usage: JRuby Solution (cont.) 18.kg * 2 # 36 kg 1800000.kg / 3 # 600000 kg 1.kg * 2 + 3.kg / 4 # (2.75 +/- 2.2E-16) kg 32.cm + 170.m + 1.km # 117032 cm 121.min – 1.h – 60.s # 60 min 10.m**2 - 32.8.ft**2 # (0.05119344640006 +/- 5.0E-14) m2 -3.h # -3 h 3.h < 4.h # true OpenLogic Company Confidential JScience Usage: JRuby Solution (cont.) class Amount def *(other) if other.instance_of?(Amount) self.times(other) else self.times(Amount.valueOf(other, Unit::ONE)) end end def +(other) if other.instance_of?(Amount) self.plus(other) else self.plus(Amount.valueOf(other, Unit::ONE)) end end ... end OpenLogic Company Confidential JScience Usage: JRuby Solution (cont.) [Fixnum,Float].each do |c| c.class_eval do alias original_times * alias original_plus + ... def *(other) if other.instance_of?(Amount) other.times(Amount.valueOf(self, Unit::ONE)) else original_times(other) end end ... end end OpenLogic Company Confidential JScience Usage: Groovy Solution (cont.) 18.kg * 2 // 36 kg 1800000.kg / 3 // 600000 kg 1.kg * 2 + 3.kg / 4 // (2.75 +/- 2.2E-16) kg 32.cm + 170.m + 1.km // 117032 cm 121.min – 1.h – 60.s // 60 min 10.m**2 - 32.8.ft**2 // (0.05119344640006 +/- 5.0E-14) m2 -3.h // -3 h 3.h < 4.h // true OpenLogic Company Confidential JScience Usage: Groovy Solution (cont.) Amount.metaClass.multiply = { Number factor -> delegate.times(factor) } Number.metaClass.multiply = { Amount amount -> amount.times(delegate) } Number.metaClass.div = { Amount amount -> amount.inverse().times(delegate) } Amount.metaClass.div = { Number factor -> delegate.divide(factor) } Amount.metaClass.div = { Amount factor -> delegate.divide(factor) } Amount.metaClass.power = { Number factor -> delegate.pow(factor) } Amount.metaClass.negative = { delegate.opposite() } OpenLogic Company Confidential JScience Integration: Groovy vs. JRuby Suitability for the task: Tie Ease of setup: Groovy (slight edge) Ease of use: Tie Performance: Groovy 3x faster in my benchmark (was 5x faster last month) Partially due to extra type conversions required in JRuby Being addressed by JRuby team OpenLogic Company Confidential Agenda Code Samples Basic Features Advanced Java Integration Groovy JDK vs. JRuby/Ruby Libraries Advanced Features Demo Conclusion OpenLogic Company Confidential Groovy JDK vs. JRuby/Ruby Libraries Groovy JDK Adds lots of utility methods to String, File, Collection, etc. Heavily inspired by Ruby Robust and easy to add new ones String.metaClass.alphabetical = { (delegate.toCharArray() as List).sort().join() } "scripts".alphabetical() // ciprsst JRuby/Ruby Libraries JRuby can use both the JDK release and all of Ruby's libraries Very robust and easy to add new ones def String.alphabetical self.split("").sort.join end "scripts".alphabetical # ciprsst OpenLogic Company Confidential Agenda Code Samples Basic Features Advanced Java Integration Groovy JDK vs. JRuby/Ruby Libraries Advanced Features Demo Conclusion OpenLogic Company Confidential Advanced Features Groovy: Expando rod = new Expando(name: 'Rod', age: 37) rod.drinkWater = { num -> num.times { println "yum!" } } rod.age // 37 rod.drinkWater(2) // yum! JRuby: OpenStruct // yum! require 'ostruct' rod = OpenStruct.new(:name => 'Rod', :age => 37) def rod.drinkWater(num) num.times { println "yum!" } } end rod.age # 37 rod.drinkWater(2) # yum! # yum! OpenLogic Company Confidential Advanced Features: Groovy package com.openlogic class Company { String name Address address List employees = [] } class Address { String street int zip String state } class Employee { String name int employeeId Address address Company company } OpenLogic Company Confidential Advanced Features: Groovy def builder = new ObjectGraphBuilder( classNameResolver: "com.openlogic") def company = builder.company(name: 'OpenLogic') { address(id:'a1', street:'Elm', zip:80021, state:'CO') employee(name: 'Rod', employeeId: 1) { address(refId: 'a1') } employee(name: 'Eric', employeeId: 2) { address(refId: 'a1') } } println company.employees.size() println company.address.zip company.employees.each { println "${it.name}, ${it.employeeId}" } println company.employees[1].address.street OpenLogic Company Confidential // // // // 2 80021 Rod, 1 Eric, 2 // Elm Advanced Features: JRuby class Order < ActiveRecord::Base belongs_to :user has_many :transactions validates_presence_of :quantity, :price validates_numericality_of :quantity, :integer_only => true validates_inclusion_of :quantity, :in => 1..1_000_000, :message => "should be between 1 and 1,000,000" def cancelled? transactions.empty? && price < 0 end end OpenLogic Company Confidential Advanced Features: JRuby Low level file operations File class: chmod, setuid?, symlink?, ln_s, etc. REXML require "rexml/document"; include REXML addrbook = Document.new(File.new("address.xml")).root puts addrbook.elements["//person[2]/address"] .attributes["city"] Code can run under both JRuby/JVM machine and C-based Ruby begin require 'java' JAVA = true rescue LoadError JAVA = false end if JAVA ... OpenLogic Company Confidential Agenda Code Samples Basic Features Advanced Java Integration Groovy JDK vs. JRuby/Ruby Libraries Advanced Features Demo Conclusion OpenLogic Company Confidential Groovy and JRuby Demo OpenLogic Company Confidential Demo code Groovy Download xmlrpc module import groovy.net.xmlrpc.* server = new XMLRPCServer() server.multiply = { it * 3 } server.startServer(new java.net.ServerSocket(9047)) server.stopServer() // later JRuby require 'xmlrpc/client' server = XMLRPC::Client.new2("http://localhost:9047") server.call("multiply", 2) def server.method_missing(sym, *args) self.call(sym.to_s, *args) end server.multiply 7 server.multiply "cool " OpenLogic Company Confidential Agenda Code Samples Basic Features Advanced Java Integration Groovy JDK vs. JRuby/Ruby Libraries Advanced Features Demo Conclusion OpenLogic Company Confidential Conclusion Groovy Seamless fit with existing Java code Performance is good and improving Best suited for tight and/or heavy Java code integration Grails JRuby Java code integration is good, but needs some work Performance is good and improving all the time Best suited for general scripting and light Java code integration Rails OpenLogic Company Confidential For More Information Groovy http://groovy.codehaus.org Article on JScience integration by Guillaume Laforge: http://groovy.dzone.com/news/domain-specific-language-unitGrails http://grails.codehaus.org/ JRuby http://jruby.codehaus.org Rails http://rubyonrails.org Both Great comparison of Java, Groovy, and JRuby syntax: http://blogs.sun.com/sundararajan/entry/java_groovy_and_j_ruby OpenLogic Company Confidential Q&A Any questions for Rod? Image licensed from BigStockPhoto.com OpenLogic Company Confidential