350 likes | 459 Vues
Learn the differences between Groovy and JRuby to determine which is best for you in terms of features, Java integration, and advanced capabilities. Explore code samples and practical demonstrations.
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