groovy vs. jruby rod cope, cto & founder openlogic, inc
TRANSCRIPT
Groovy vs. JRubyRod Cope, CTO & FounderOpenLogic, Inc.
OpenLogic Company Confidential
Learn which is best for you if you only have time to learn one scripting language: Groovy or JRuby
Goal
OpenLogic Company Confidential
Introduction
Rod CopeCTO & Founder of OpenLogic25 years of software development experienceIBM 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 sourceJRuby 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: Javapublic 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;}
}
and Groovy!
OpenLogic Company Confidential
Groovy!
list = ["Rod", "Neeta", "Eric", "Missy"]shorts = list.find_all { |name| name.size <= 4 }puts shorts.sizeshorts.each { |name| puts name }
-> 2 -> Rod Eric
JRuby!
list = ["Rod", "Neeta", "Eric", "Missy"]shorts = list.findAll { name -> name.size() <= 4 }println shorts.sizeshorts.each { name -> println 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
GroovyStarted in 2003 by James Strachan and Bob McWhirterNow led by Guillaume LaforgeDynamic, object-oriented scripting language for the JVMFeatures of Ruby, Python, and SmalltalkLicense: Apache 2.0
JRubyStarted in 2001 by Jan Arne PetersenNow led by Charles Nutter, Thomas Enebo, Ola Bini, and Nick SiegerFast Ruby interpreter and JIT/AOT compiler written in JavaTight, bi-directional Java integrationLicense: CPL, GPL, or LGPL
OpenLogic Company Confidential
Basic Feature ComparisonFeature 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 //true
println re ==~ "name" //false
re = /na.*/
puts "name" =~ re # 0
puts re =~ "name" # 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() // 3
println "dog".size() // 3
puts [1,2,3].size # 3
puts "dog".size # 3
OpenLogic Company Confidential
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
a = 1000 // Integer
a = 1000000000000 // Long
a = 1000000000000000000000
// BigInteger
a = 1000 // 1000
a = a * a // 1000000
a = a * a // -727379968
No interfaces or types, just objects that receive messages
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 unitsputs 2.kg # 2 kgputs 3.m # 3 mputs 4.5.in # (4.5 +/- 4.4E-16) in
include Javarequire 'jscience.jar'Unit = javax.measure.unit.UnitAmount = org.jscience.physics.amount.Amount
class Numeric def method_missing(sym) Amount.valueOf(self, Unit.valueOf(sym.to_s)) endend
OpenLogic Company Confidential
JScience Usage: Groovy Solution
// sample unitsprintln 2.kg // 2 kgprintln 3.m // 3 mprintln 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)) }
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 ... endend
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: Groovy3x faster in my benchmark (was 5x faster last month)Partially due to extra type conversions required in JRubyBeing 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 JDKAdds lots of utility methods to String, File, Collection, etc.Heavily inspired by RubyRobust and easy to add new onesString.metaClass.alphabetical = {
(delegate.toCharArray() as List).sort().join() } "scripts".alphabetical() // ciprsst
JRuby/Ruby LibrariesJRuby can use both the JDK release and all of Ruby's librariesVery robust and easy to add new onesdef 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! // 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!
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: Groovydef 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() // 2println company.address.zip // 80021company.employees.each { // Rod, 1 println "${it.name}, ${it.employeeId}" // Eric, 2}println company.employees[1].address.street // Elm
OpenLogic Company Confidential
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 endend
OpenLogic Company Confidential
Advanced Features: JRuby
Low level file operationsFile class: chmod, setuid?, symlink?, ln_s, etc.
REXMLrequire "rexml/document"; include REXMLaddrbook = Document.new(File.new("address.xml")).rootputs addrbook.elements["//person[2]/address"] .attributes["city"]
Code can run under both JRuby/JVM machine and C-based Rubybegin require 'java' JAVA = truerescue LoadError JAVA = falseendif 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
GroovyDownload xmlrpc moduleimport groovy.net.xmlrpc.*server = new XMLRPCServer()server.multiply = { it * 3 }server.startServer(new java.net.ServerSocket(9047))server.stopServer() // later
JRubyrequire '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)endserver.multiply 7server.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
GroovySeamless fit with existing Java codePerformance is good and improvingBest suited for tight and/or heavy Java code integrationGrails
JRubyJava code integration is good, but needs some workPerformance is good and improving all the timeBest suited for general scripting and light Java code integrationRails
OpenLogic Company Confidential
For More Information
Groovyhttp://groovy.codehaus.orgArticle on JScience integration by Guillaume Laforge:http://groovy.dzone.com/news/domain-specific-language-unit- Grailshttp://grails.codehaus.org/
JRubyhttp://jruby.codehaus.orgRailshttp://rubyonrails.org
BothGreat 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