350 likes | 794 Views
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. Introduction. Rod Cope CTO & Founder of OpenLogic 25 years of software development experience
E N D
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
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
Agenda • Code Samples • Basic Features • Advanced Java Integration • Groovy JDK vs. JRuby/Ruby Libraries • Advanced Features • Demo • Conclusion
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;} }
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
Agenda • Code Samples • Basic Features • Advanced Java Integration • Groovy JDK vs. JRuby/Ruby Libraries • Advanced Features • Demo • Conclusion
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
Agenda • Code Samples • Basic Features • Advanced Java Integration • Groovy JDK vs. JRuby/Ruby Libraries • Advanced Features • Demo • Conclusion
Advanced Java Integration • Goal: Use the JScience library (written in Java) • Java usage: Amounta1=Amount.valueOf(3,KILO(GRAM)); Amounta2=Amount.valueOf("2kg"); Amountsum=a1.plus(a2); • Desired usage: a1 = 3.kg a2 = 2.kg sum = a1 + a2
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
JScience Usage: Groovy Solution // sample units println 2.kg // 2 kg println 3.m // 3 m println 4.5.in // (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)) }
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
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
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
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
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() }
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
Agenda • Code Samples • Basic Features • Advanced Java Integration • Groovy JDK vs. JRuby/Ruby Libraries • Advanced Features • Demo • Conclusion
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
Agenda • Code Samples • Basic Features • Advanced Java Integration • Groovy JDK vs. JRuby/Ruby Libraries • Advanced Features • Demo • Conclusion
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! // yum! • JRuby: OpenStruct 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!
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 }
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() // 2 println company.address.zip // 80021 company.employees.each { // Rod, 1 println "${it.name}, ${it.employeeId}" // Eric, 2 } println company.employees[1].address.street // 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
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 ...
Agenda • Code Samples • Basic Features • Advanced Java Integration • Groovy JDK vs. JRuby/Ruby Libraries • Advanced Features • Demo • Conclusion
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 "
Agenda • Code Samples • Basic Features • Advanced Java Integration • Groovy JDK vs. JRuby/Ruby Libraries • Advanced Features • Demo • Conclusion
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
For More Information • Groovy • http://groovy.codehaus.org • Article on JScience integration by Guillaume Laforge:http://groovy.dzone.com/news/domain-specific-language-unit- • Grailshttp://grails.codehaus.org/ • JRuby • http://jruby.codehaus.org • Railshttp://rubyonrails.org • Both • Great comparison of Java, Groovy, and JRuby syntax:http://blogs.sun.com/sundararajan/entry/java_groovy_and_j_ruby
Q & A Any questions for Rod? Image licensed from BigStockPhoto.com