Groovy vs. JRuby

coordinatedcapableΛογισμικό & κατασκευή λογ/κού

4 Νοε 2013 (πριν από 3 χρόνια και 9 μήνες)

253 εμφανίσεις

Groovy vs. JRuby

Rod Cope, CTO & Founder

OpenLogic, 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 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

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;

}

}

and Groovy!

OpenLogic Company Confidential

Groovy!

list = ["Rod", "Neeta", "Eric", "Missy"]

shorts = list.find_all { |name| name.size <= 4 }

puts shorts.size

shorts.each { |name| puts name }



-
> 2


-
> Rod


Eric

JRuby!

list = ["Rod", "Neeta", "Eric", "Missy"]

shorts = list.findAll { name
-
> name.size() <= 4 }

println shorts.size

shorts.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

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 //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 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
// 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)) }

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) m
2


-
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) m
2


-
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!


// 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: 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

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


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
-
unit
-


Grails

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