jruby: enhancing java developers' lives

110
JRuby: Enhancing Java Developers' Lives Hiro Asari @hiro_asari JRuby Support Engineer Engine Yard @engineyard Wednesday, November 16, 11

Upload: hiro-asari

Post on 15-May-2015

1.875 views

Category:

Technology


2 download

DESCRIPTION

This is a talk from Devoxx 2011.Java developers wear a lot of hats these days: they manage builds, develop applications, write command-line scripts, and must master all tiers. If only there were a way to make these tasks simple and fun.Enter JRuby.Build engineers can write or enhance builds with Ruby, never losing a thing they depend on from Ant or Maven. Ruby offers several elegant testing options that work great with JRuby. Web developers can create Rails applications in minutes, effortlessly incorporating the latest Web technologies while taking advantage of the existing Java libraries. JRuby supports binding native libraries with FFI (foreign function interface). Command-line scripts? They're easy with JRuby's system-level features.Come to this session to learn how JRuby makes you a happy developer.

TRANSCRIPT

Page 1: JRuby: Enhancing Java Developers' Lives

JRuby:Enhancing Java Developers' Lives

Hiro Asari@hiro_asariJRuby Support EngineerEngine Yard@engineyard

Wednesday, November 16, 11

Page 2: JRuby: Enhancing Java Developers' Lives

JRuby: a Brief History

Where it came from, and where it is now

Wednesday, November 16, 11

Page 3: JRuby: Enhancing Java Developers' Lives

History• September 10, 2001Source:(Wikipedia

Wednesday, November 16, 11

Page 4: JRuby: Enhancing Java Developers' Lives

History

Wednesday, November 16, 11

Page 5: JRuby: Enhancing Java Developers' Lives

History• 10+ years old• Led by Charles Nutter and

Tom Enebo• 14.800+ commits

Wednesday, November 16, 11

Page 6: JRuby: Enhancing Java Developers' Lives

Project Status• Current Stable Release:

1.6.5• Compatible with Ruby

1.8.7 and 1.9.2• Supports Rails 3.1

Wednesday, November 16, 11

Page 7: JRuby: Enhancing Java Developers' Lives

Getting JRuby

h0p://jruby.org/download

Wednesday, November 16, 11

Page 8: JRuby: Enhancing Java Developers' Lives

Trying JRubyh0p://jruby.org/tryjruby

Wednesday, November 16, 11

Page 9: JRuby: Enhancing Java Developers' Lives

Book

Wednesday, November 16, 11

Page 10: JRuby: Enhancing Java Developers' Lives

Quick Tour of Ruby

A brief overview of the language

Wednesday, November 16, 11

Page 11: JRuby: Enhancing Java Developers' Lives

Classes

public class Circle extends Shape { private final int radius;

public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } public double getArea() { return Math.PI * Math.pow(radius,2); } public static void main(String[] a) { double area=new Circle(2).getArea(); System.out.println(area); }}

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius

def area Math::PI*(@radius ** 2) endend

puts Circle.new(2).area

Wednesday, November 16, 11

Page 12: JRuby: Enhancing Java Developers' Lives

Single Inheritance

public class Circle extends Shape { private final int radius;

public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } public double getArea() { return Math.PI * Math.pow(radius,2); } public static void main(String[] a) { double area=new Circle(2).getArea(); System.out.println(area); }}

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius

def area Math::PI*(@radius ** 2) endend

puts Circle.new(2).area

Same Thing

Wednesday, November 16, 11

Page 13: JRuby: Enhancing Java Developers' Lives

Constructor

public class Circle extends Shape { private final int radius;

public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } public double getArea() { return Math.PI * Math.pow(radius,2); } public static void main(String[] a) { double area=new Circle(2).getArea(); System.out.println(area); }}

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius

def area Math::PI*(@radius ** 2) endend

puts Circle.new(2).area

Wednesday, November 16, 11

Page 14: JRuby: Enhancing Java Developers' Lives

No Type Declarations

public class Circle extends Shape { private final int radius;

public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } public double getArea() { return Math.PI * Math.pow(radius,2); } public static void main(String[] a) { double area=new Circle(2).getArea(); System.out.println(area); }}

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius

def area Math::PI*(@radius ** 2) endend

puts Circle.new(2).area

Wednesday, November 16, 11

Page 15: JRuby: Enhancing Java Developers' Lives

Instance Variables

public class Circle extends Shape { private final int radius;

public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } public double getArea() { return Math.PI * Math.pow(radius,2); } public static void main(String[] a) { double area=new Circle(2).getArea(); System.out.println(area); }}

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius

def area Math::PI*(@radius ** 2) endend

puts Circle.new(2).area

‘@’ == ‘this.’ and is mandatory

Wednesday, November 16, 11

Page 16: JRuby: Enhancing Java Developers' Lives

Working with Instance Variables

public class Circle extends Shape { private final int radius;

public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } public double getArea() { return Math.PI * Math.pow(radius,2); } public static void main(String[] a) { double area=new Circle(2).getArea(); System.out.println(area); }}

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius

def area Math::PI*(@radius ** 2) endend

puts Circle.new(2).area

Common tasks are easy

Wednesday, November 16, 11

Page 17: JRuby: Enhancing Java Developers' Lives

Symbols:identifier

• Prefixed with a colon• Uniquely defined in a runtime

Wednesday, November 16, 11

Page 18: JRuby: Enhancing Java Developers' Lives

Point of No Return

public class Circle extends Shape { private final int radius;

public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } public double getArea() { return Math.PI * Math.pow(radius,2); } public static void main(String[] a) { double area=new Circle(2).getArea(); System.out.println(area); }}

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius

def area Math::PI*(@radius ** 2) endend

puts Circle.new(2).area

Last Expression is always return value

Wednesday, November 16, 11

Page 19: JRuby: Enhancing Java Developers' Lives

.new is just a class method

public class Circle extends Shape { private final int radius;

public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } public double getArea() { return Math.PI * Math.pow(radius,2); } public static void main(String[] a) { double area=new Circle(2).getArea(); System.out.println(area); }}

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius

def area Math::PI*(@radius ** 2) endend

puts Circle.new(2).area

Wednesday, November 16, 11

Page 20: JRuby: Enhancing Java Developers' Lives

Blocks/Closures• Pass an anonymous function to a method call

# Look mom...no boilerplate!my_open(file) do |io| first_line = io.gets # ...end

def my_open(file, mode='r') io = File.open(file) yield ioensure io.closeend

letters.group_by {|b| b.zip_code }

button.action_performed do exitend

Wednesday, November 16, 11

Page 21: JRuby: Enhancing Java Developers' Lives

dude = people.find { |person| person.id == 123 }

floats = [1,2].collect { |int| int.to_f } # => [1.0, 2.0]

Modules

module Enumerable def find(if_none = nil) each { |o| return o if yield(o) } if_none end

# Many other methods not shown

def collect ary = [] each { |o| ary << yield(o) } ary endend

class MyTree include Enumerable

# tree impl not shown :)

def each # yield each element # in tree endend

Wednesday, November 16, 11

Page 22: JRuby: Enhancing Java Developers' Lives

Everything is an Expression

class Color COLORS = {:red => 0xff0000, :green => 0x00ff00, :blue => 0x0000ff}

COLORS.each do |name, value| define_method(name) do value end endend

Wednesday, November 16, 11

Page 23: JRuby: Enhancing Java Developers' Lives

Classes/Modules are open

class MyTree def each #... endend

#... later in source#... maybe even different file

class MyTree def debug #... endend

Wednesday, November 16, 11

Page 24: JRuby: Enhancing Java Developers' Lives

Pure OO Language• Everything is an objectMyTree.foo #=> method call12 + 8 #=> here, '+' is a method on Fixnum, 12.12.to_s(8) #=> "14"puts 11.odd? #=> true

Wednesday, November 16, 11

Page 25: JRuby: Enhancing Java Developers' Lives

JRuby on RailsRuby's Killer app

Wednesday, November 16, 11

Page 26: JRuby: Enhancing Java Developers' Lives

Java Web Frameworks

Devoxx 2010

Wednesday, November 16, 11

Page 27: JRuby: Enhancing Java Developers' Lives

Java Web Frameworks

h0p://j.mp/raible<jvm<frameworks

© 2010, Raible DesignsImages by Stuck in Customs - http://www.flickr.com/photos/stuckincustoms

© 2010 Raible Designs

COMPARING JVM WEB FRAMEWORKS

Matt Raiblehttp://raibledesigns.com

Wednesday, November 16, 11

Page 28: JRuby: Enhancing Java Developers' Lives

Install Rails$ jruby -S gem install railsFetching: multi_json-1.0.3.gem (100%)⋮Fetching: bundler-1.0.21.gem (100%)Fetching: rails-3.1.1.gem (100%)Successfully installed multi_json-1.0.3Successfully installed activesupport-3.1.1⋮Successfully installed thor-0.14.6Successfully installed rack-ssl-1.3.2Successfully installed json-1.6.1-javaSuccessfully installed rdoc-3.11Successfully installed railties-3.1.1Successfully installed bundler-1.0.21Successfully installed rails-3.1.131 gems installed

Wednesday, November 16, 11

Page 29: JRuby: Enhancing Java Developers' Lives

Generate Rails app$ jruby -S rails new awesomeapp create ⋮ create vendor/plugins create vendor/plugins/.gitkeep run bundle installFetching source index for http://rubygems.org/Using rake (0.9.2.2) ⋮Using json (1.6.1) Using rdoc (3.11) Using thor (0.14.6) Using railties (3.1.1) Installing coffee-rails (3.1.1) Installing jquery-rails (1.0.16) Installing jruby-openssl (0.7.4) Using rails (3.1.1) Installing sass (3.1.10) Installing sass-rails (3.1.4) Installing uglifier (1.0.4) Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

Wednesday, November 16, 11

Page 30: JRuby: Enhancing Java Developers' Lives

Rails Scaffolding$ jruby -S rails generate scaffold person name:string email:string invoke active_record create db/migrate/20111107052142_create_people.rb create app/models/person.rb⋮ create app/views/people/show.html.erb create app/views/people/new.html.erb create app/views/people/_form.html.erb invoke test_unit create test/functional/people_controller_test.rb invoke helper create app/helpers/people_helper.rb invoke test_unit create test/unit/helpers/people_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/people.js.coffee invoke scss create app/assets/stylesheets/people.css.scss invoke scss create app/assets/stylesheets/scaffolds.css.scss

Wednesday, November 16, 11

Page 31: JRuby: Enhancing Java Developers' Lives

$ jruby -S rake db:migrate== CreatePeople: migrating ====================================-- create_table(:people) -> 0.0040s -> 0 rows== CreatePeople: migrated (0.0040s) ===========================

Migrate Database

Wednesday, November 16, 11

Page 32: JRuby: Enhancing Java Developers' Lives

$ jruby -S rails server=> Booting WEBrick=> Rails 3.1.1 application starting in development on http://0.0.0.0:3000=> Call with -d to detach=> Ctrl-C to shutdown server[2011-11-07 00:26:30] INFO WEBrick 1.3.1[2011-11-07 00:26:30] INFO ruby 1.8.7 (2011-11-05) [java][2011-11-07 00:26:30] INFO WEBrick::HTTPServer#start: pid=40454 port=3000

Start Server

Wednesday, November 16, 11

Page 33: JRuby: Enhancing Java Developers' Lives

First Page

Wednesday, November 16, 11

Page 34: JRuby: Enhancing Java Developers' Lives

app/controllers/people_controller.rbclass PeopleController < ApplicationController # GET /people # GET /people.json def index @people = Person.all

respond_to do |format| format.html # index.html.erb format.json { render :json => @people } end end⋮end

Wednesday, November 16, 11

Page 35: JRuby: Enhancing Java Developers' Lives

JSON out of the box

Wednesday, November 16, 11

Page 36: JRuby: Enhancing Java Developers' Lives

class Person < ActiveRecord::Baseend

app/models/person.rb

Wednesday, November 16, 11

Page 37: JRuby: Enhancing Java Developers' Lives

Rails Deployment

Wednesday, November 16, 11

Page 38: JRuby: Enhancing Java Developers' Lives

netbeans.org

Rails IDE and text editors

jetbrains.com/ruby/

redcareditor.com

•emacs•vi(m)•TextMate

Wednesday, November 16, 11

Page 39: JRuby: Enhancing Java Developers' Lives

App

Requests

/vets/ Java/Spring

JRuby

/rack/

JRuby in Java web app

Wednesday, November 16, 11

Page 40: JRuby: Enhancing Java Developers' Lives

JRuby in Java web appdiff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xmlindex 8d02684..60ed6cb 100644--- a/src/main/webapp/WEB-INF/web.xml+++ b/src/main/webapp/WEB-INF/web.xml@@ -87,6 +87,21 @@ <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>++ <listener>+ <listener-class>org.jruby.rack.RackServletContextListener</listener-class>+ </listener>++ <servlet>+ <servlet-name>rack</servlet-name>+ <servlet-class>org.jruby.rack.RackServlet</servlet-class>+ </servlet>++ <servlet-mapping>+ <servlet-name>rack</servlet-name>+ <url-pattern>/rack/*</url-pattern>+ </servlet-mapping>+ <!-- Defines the 'default' servlet (usually for service static resources).

Wednesday, November 16, 11

Page 41: JRuby: Enhancing Java Developers' Lives

App

/vets /owners/ /owners/1/pets

Requests

Java/Spring

/vets/ JRuby

Rails in Java web app

Wednesday, November 16, 11

Page 42: JRuby: Enhancing Java Developers' Lives

Rails in Java web appdiff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xmlindex 60ed6cb..f64b34d 100644--- a/src/main/webapp/WEB-INF/web.xml+++ b/src/main/webapp/WEB-INF/web.xml@@ -92,16 +92,6 @@ <listener-class>org.jruby.rack.RackServletContextListener</listener-class> </listener> - <servlet>- <servlet-name>rack</servlet-name>- <servlet-class>org.jruby.rack.RackServlet</servlet-class>- </servlet>-- <servlet-mapping>- <servlet-name>rack</servlet-name>- <url-pattern>/rack/*</url-pattern>- </servlet-mapping>- <!-- Defines the 'default' servlet (usually for service static resources).@@ -162,6 +152,16 @@ <url-pattern>/</url-pattern> </servlet-mapping> + <filter>+ <filter-name>RackFilter</filter-name>+ <filter-class>org.jruby.rack.RubyFirstRackFilter</filter-class>+ </filter>++ <filter-mapping>+ <filter-name>RackFilter</filter-name>+ <url-pattern>/*</url-pattern>+ </filter-mapping>+ <filter> <filter-name>httpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>

Wednesday, November 16, 11

Page 43: JRuby: Enhancing Java Developers' Lives

More…

h0p://bit.ly/refactoring<to<railsh0p://vimeo.com/25410705

Wednesday, November 16, 11

Page 44: JRuby: Enhancing Java Developers' Lives

Testing LibrariesTest-Driven Development

Wednesday, November 16, 11

Page 45: JRuby: Enhancing Java Developers' Lives

Testing

25

50

75

100

Easy HardNum

ber o

f Tes

ts W

ritte

n (1

000'

s)

Ease of Writing Tests

Wednesday, November 16, 11

Page 46: JRuby: Enhancing Java Developers' Lives

$ jruby -S rails g scaffold person name:string email:string invoke active_record create db/migrate/20111107052142_create_people.rb create app/models/person.rb⋮ create app/views/people/show.html.erb create app/views/people/new.html.erb create app/views/people/_form.html.erb invoke test_unit create test/functional/people_controller_test.rb invoke helper create app/helpers/people_helper.rb invoke test_unit create test/unit/helpers/people_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/people.js.coffee invoke scss create app/assets/stylesheets/people.css.scss invoke scss create app/assets/stylesheets/scaffolds.css.scss

Test files$ jruby -S rails g scaffold person name:string email:string invoke active_record create db/migrate/20111107052142_create_people.rb create app/models/person.rb⋮ create app/views/people/show.html.erb create app/views/people/new.html.erb create app/views/people/_form.html.erb invoke test_unit create test/functional/people_controller_test.rb invoke helper create app/helpers/people_helper.rb invoke test_unit create test/unit/helpers/people_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/people.js.coffee invoke scss create app/assets/stylesheets/people.css.scss invoke scss create app/assets/stylesheets/scaffolds.css.scss

Wednesday, November 16, 11

Page 47: JRuby: Enhancing Java Developers' Lives

DeepThought.javaclass DeepThought { public static int answerToEverything(Object obj) { return 42; }

public static String getName() { return "DeepThought"; }}

Wednesday, November 16, 11

Page 48: JRuby: Enhancing Java Developers' Lives

RSpecrequire 'rspec'require 'java'

java_import 'DeepThought'

describe 'DeepThought' do describe '.answerToEverything' do it "should return 42, given any input" do DeepThought.answerToEverything(nil).should == 42 DeepThought.answerToEverything(true).should == 42 end end

describe '.getName' do it "should return 'DeepThought'" do DeepThought.name.should == "DeepThought" end endend

Wednesday, November 16, 11

Page 49: JRuby: Enhancing Java Developers' Lives

$ javac DeepThrought.java

$ jruby -rubygems deep_thought_spec.rb ..

Finished in 0.013 seconds2 examples, 0 failures

RSpec

Wednesday, November 16, 11

Page 50: JRuby: Enhancing Java Developers' Lives

Feature: AnswerToEverything Ask DeepThought the answer to everything

Scenario: Ask a question Given nil as input Then the result should be 42

Cucumber

Feature: getName Ask DeepThought what its name is

Scenario: get name When asked the name Then it answers the name as "DeepThought"

Wednesday, November 16, 11

Page 51: JRuby: Enhancing Java Developers' Lives

Cucumber$ jruby -S cucumberFeature: AnswerToEverything Ask DeepThought the answer to everything

Scenario: Ask a question # features/answer.feature:4 Given nil as input # features/step_definitions… Then the result should be 42 # features/step_definitions…

Feature: getName Ask DeepThought what its name is

Scenario: get name # features/… When asked the name # features/… Then it answers the name as "DeepThought" # features/…

2 scenarios (2 passed)4 steps (4 passed)0m0.065s

Wednesday, November 16, 11

Page 52: JRuby: Enhancing Java Developers' Lives

JTestr• Bridge for Java to make use of Ruby testing• Integrates with both Ant and Maven• Allows mocking of non-final Java class/method• Written by Ola Bini

Wednesday, November 16, 11

Page 53: JRuby: Enhancing Java Developers' Lives

JTestr Example

my_project/ build.xml! test/ test_hashmap.rb hashmap_spec.rb lib/ jtestr.jar src/ <your source ;) >

Wednesday, November 16, 11

Page 54: JRuby: Enhancing Java Developers' Lives

JTestr in Ant

<?xml version="1.0" encoding="UTF-8"?>

<project basedir="." default="jar" name="JRuby"> <target name="test" description="Runs all tests"> <taskdef name="jtestr" classname="org.jtestr.ant.JtestRAntRunner" classpath="lib/jtestr.jar"/> <jtestr/> </target></project>

Wednesday, November 16, 11

Page 55: JRuby: Enhancing Java Developers' Lives

Ruby’s test/unit

class HashMapTests < Test::Unit::TestCase def setup @map = java.util.HashMap.new end

def test_that_an_entry_can_be_added @map.put "foo", "bar" assert_equal "bar", @map.get("foo") end

def test_empty_key_set_iterator_throws_exception assert_raises(java.util.NoSuchElementException) do @map.key_set.iterator.next end endend

test/test_hashmap.rb

Wednesday, November 16, 11

Page 56: JRuby: Enhancing Java Developers' Lives

RSpec revisitedtest/hashmap_spec.rb

require 'java'java_import java.util.HashMap

describe "An empty", HashMap do before :each do @hash_map = java.util.HashMap.new end

it "should be able to add an entry to it" do @hash_map.put "foo", "bar" @hash_map.get("foo").should == "bar" end

it "should not be empty after an entry has been added to it" do @hash_map.put "foo", "bar" @hash_map.should_not be_empty end

it "should be empty" do @hash_map.should be_empty endend

Wednesday, November 16, 11

Page 57: JRuby: Enhancing Java Developers' Lives

Results

$ ant testBuildfile: /Users/asari/Development/projects/jtestr-example/build.xml

test: [jtestr] Other TestUnit: 2 tests, 0 failures, 0 errors [jtestr] [jtestr] Other Spec: 3 examples, 0 failures, 0 errors [jtestr] [jtestr] Total: 5 tests, 0 failures, 0 errors, 0 pending [jtestr]

BUILD SUCCESSFULTotal time: 7 seconds

Wednesday, November 16, 11

Page 58: JRuby: Enhancing Java Developers' Lives

Ant-Rake Integration

Wednesday, November 16, 11

Page 59: JRuby: Enhancing Java Developers' Lives

Problem…

dev.null

NUL

Windows

/dev/null

Un*x

dev_null

everything else

Wednesday, November 16, 11

Page 60: JRuby: Enhancing Java Developers' Lives

Ant…<condition property="dev.null" value="/dev/null"> <os family="unix"/></condition><condition property="dev.null" value="NUL"> <os family="windows"/></condition><condition property="dev.null" value="dev_null"> <not> <or> <os family="unix"/> <os family="windows"/> </or> </not></condition>

Wednesday, November 16, 11

Page 61: JRuby: Enhancing Java Developers' Lives

if os.family == 'unix' :dev_null = '/dev/null'elsif os.family == 'windows' :dev_null = 'NUL'else :dev_null = 'dev_null'end

Ruby

Wednesday, November 16, 11

Page 62: JRuby: Enhancing Java Developers' Lives

Ant…<macrodef name="run-junit-1.8-short"> <attribute name="compile.mode" default="OFF"/> <attribute name="jit.threshold" default="20"/> <attribute name="jit.maxsize" default="1000000000"/> <attribute name="reflection" default="false"/> <attribute name="thread.pooling" default="false"/> <attribute name="jvm.flags" default=""/>⋮</macrodef>⋮<target name="run-junit-compiled-short"> <run-junit-1.8-short compile.mode="JIT" jit.threshold="0"/></target>

Wednesday, November 16, 11

Page 63: JRuby: Enhancing Java Developers' Lives

Rubydef run_junit_18_short(opts={}) compile_mode = opts[:compile_mode] || 'OFF' jit_threshold = opts[:jit_threshold] || 20 jit_maxsize = opts[:jit_maxsize] || 1000000000 reflection = opts[:reflection] || false thread_pooling = opts[:thread_pooling] || false jvm_flags = opts[:jvm_flags] || "" ⋮end

def run_junit_compiled_short run_junit_18_short :compile_mode => 'JIT', :jit_threshold => 0end

Wednesday, November 16, 11

Page 64: JRuby: Enhancing Java Developers' Lives

Ant tasks from Rake<path id="build.classpath"> <fileset dir="${build.lib.dir}" includes="*.jar"/></path>

<path id="jruby.execute.classpath"> <path refid="build.classpath"/> <pathelement path="${jruby.classes.dir}"/></path>

task :initialize_paths do ant.path(:id => "build.classpath") do fileset :dir => BUILD_LIB_DIR, :includes => "*.jar" end

ant.path(:id => "jruby.execute.classpath") do path :refid => "build.classpath" pathelement :path => JRUBY_CLASSES_DIR endend

Wednesday, November 16, 11

Page 65: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targets

build.xml

RakefileWednesday, November 16, 11

Page 66: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targets

build.xml

Wednesday, November 16, 11

Page 67: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targets

RakefileWednesday, November 16, 11

Page 68: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

Rake tasks as Ant targets

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Wednesday, November 16, 11

Page 69: JRuby: Enhancing Java Developers' Lives

Rake tasks as Ant targets<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Wednesday, November 16, 11

Page 70: JRuby: Enhancing Java Developers' Lives

Rake tasks as Ant targets<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Wednesday, November 16, 11

Page 71: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targets

Wednesday, November 16, 11

Page 72: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targetsBuildfile: build.xml[rakeimport] (in /tmp/example2)

setup:

Wednesday, November 16, 11

Page 73: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targetsBuildfile: build.xml[rakeimport] (in /tmp/example2)

setup:setup in Rake

Wednesday, November 16, 11

Page 74: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targetsBuildfile: build.xml[rakeimport] (in /tmp/example2)

setup:setup in Rake

its_in_ant:

Wednesday, November 16, 11

Page 75: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targetsBuildfile: build.xml[rakeimport] (in /tmp/example2)

setup:setup in Rake

its_in_ant: [echo] ant: its_in_ant

Wednesday, November 16, 11

Page 76: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targetsBuildfile: build.xml[rakeimport] (in /tmp/example2)

setup:setup in Rake

its_in_ant: [echo] ant: its_in_ant

its_in_rake:

Wednesday, November 16, 11

Page 77: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targetsBuildfile: build.xml[rakeimport] (in /tmp/example2)

setup:setup in Rake

its_in_ant: [echo] ant: its_in_ant

its_in_rake:it's in Rake

Wednesday, November 16, 11

Page 78: JRuby: Enhancing Java Developers' Lives

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs foobar.</description>

<taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/> <rakeimport/>

<target name="top-level" depends="its_in_rake" />

<target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target></project>

task :its_in_rake => [:setup, :its_in_ant] do puts "it's in Rake"end

task :setup do puts "setup in Rake"end

Rake tasks as Ant targetsBuildfile: build.xml[rakeimport] (in /tmp/example2)

setup:setup in Rake

its_in_ant: [echo] ant: its_in_ant

its_in_rake:it's in Rake

top-level:

BUILD SUCCESSFULTotal time: 7 seconds

Wednesday, November 16, 11

Page 79: JRuby: Enhancing Java Developers' Lives

More…

http://bit.ly/rake_ant

Wednesday, November 16, 11

Page 80: JRuby: Enhancing Java Developers' Lives

Maven and RubyGems

Wednesday, November 16, 11

Page 81: JRuby: Enhancing Java Developers' Lives

JRuby via Maven• Group ID: org.jruby• Artifact IDs: jruby, jruby-complete

<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jruby</groupId> <artifactId>jruby</artifactId> <version>1.6.5</version> </dependency></dependencies>

Wednesday, November 16, 11

Page 82: JRuby: Enhancing Java Developers' Lives

jruby -S gem install mvn:org.clojure:clojure

Maven artifacts as gems

maven

Wednesday, November 16, 11

Page 83: JRuby: Enhancing Java Developers' Lives

jruby -S gem install mvn:org.clojure:clojure

group ID

Maven artifacts as gems

Wednesday, November 16, 11

Page 84: JRuby: Enhancing Java Developers' Lives

jruby -S gem install mvn:org.clojure:clojure

artifact ID

Maven artifacts as gems

Wednesday, November 16, 11

Page 85: JRuby: Enhancing Java Developers' Lives

Successfully installed mvn:org.clojure:clojure-1.4.0.a.2-java1 gem installed

Maven artifacts as gems

Some restrictions apply

jruby -S gem install mvn:org.clojure:clojure

Wednesday, November 16, 11

Page 86: JRuby: Enhancing Java Developers' Lives

Maven artifacts as gems$ jruby -S irbirb(main):001:0> require 'mvn:org.clojure:clojure'=> trueirb(main):002:0> java_import Java::clojure.lang.PersistentHashMap=> Java::ClojureLang::PersistentHashMapirb(main):003:0> phm = PersistentHashMap.create({:a => 100, :b => 200, :c => 300})=> {:c=>300, :a=>100, :b=>200}irb(main):004:0> phm.delete_if {|k,v| k == :b}Java::JavaLang::UnsupportedOperationException: from clojure.lang.APersistentMap.remove(APersistentMap.java:273) from org.jruby.java.proxies.MapJavaProxy$RubyHashMap.internalDelete(MapJavaProxy.java:154) from org.jruby.RubyHash.delete(RubyHash.java:1407) from org.jruby.RubyHash$22.visit(RubyHash.java:1464) from org.jruby.java.proxies.MapJavaProxy$RubyHashMap.visitAll(MapJavaProxy.java:182)⋮

$ jruby -S irbirb(main):001:0> require 'mvn:org.clojure:clojure'=> trueirb(main):002:0> java_import Java::clojure.lang.PersistentHashMap=> Java::ClojureLang::PersistentHashMapirb(main):003:0> phm = PersistentHashMap.create({:a => 100, :b => 200, :c => 300})=> {:c=>300, :a=>100, :b=>200}irb(main):004:0> phm.delete_if {|k,v| k == :b}Java::JavaLang::UnsupportedOperationException: from clojure.lang.APersistentMap.remove(APersistentMap.java:273) from org.jruby.java.proxies.MapJavaProxy$RubyHashMap.internalDelete(MapJavaProxy.java:154) from org.jruby.RubyHash.delete(RubyHash.java:1407) from org.jruby.RubyHash$22.visit(RubyHash.java:1464) from org.jruby.java.proxies.MapJavaProxy$RubyHashMap.visitAll(MapJavaProxy.java:182)⋮

Wednesday, November 16, 11

Page 87: JRuby: Enhancing Java Developers' Lives

Foreign Function Interface

Calling native functions

Wednesday, November 16, 11

Page 88: JRuby: Enhancing Java Developers' Lives

Gamma function

=∫ tz-1e-1 dt0

Γ(z)

Wednesday, November 16, 11

Page 89: JRuby: Enhancing Java Developers' Lives

org.apache.commons.math.special Class Gammajava.lang.Object org.apache.commons.math.special.Gamma

public class Gammaextends java.lang.ObjectThis is a utility class that provides computation methods related to the Gamma family of functions.

Version:$Id: Gamma.java 1131229 2011-06-03 20:49:25Z luc $

org.apache.commons.math.special Class Gammajava.lang.Object org.apache.commons.math.special.Gamma

public class Gammaextends java.lang.ObjectThis is a utility class that provides computation methods related to the Gamma family of functions.

Version:$Id: Gamma.java 1131229 2011-06-03 20:49:25Z luc $

Apache Commons?

Wednesday, November 16, 11

Page 90: JRuby: Enhancing Java Developers' Lives

org.apache.commons.math.special Class Gammajava.lang.Object org.apache.commons.math.special.Gamma

public class Gammaextends java.lang.ObjectThis is a utility class that provides computation methods related to the Gamma family of functions.

Version:$Id: Gamma.java 1131229 2011-06-03 20:49:25Z luc $

Apache Commons?

License?

JAR

size

Wednesday, November 16, 11

Page 91: JRuby: Enhancing Java Developers' Lives

N

e

w

a

s

y

m

p

t

o

t

i

c

e

x

p

a

n

s

i

o

n

f

o

r

t

h

e

(

x

)

f

u

n

c

t

i

o

n

G

e

r

g

o

N

e

m

e

s

1

D

e

c

e

m

b

e

r

7

,

2

0

0

8

h

t

t

p

:

/

/

d

x

.

d

o

i

.

o

r

g

/

1

0

.

3

2

4

7

/

s

l

2

m

a

t

h

0

8

.

0

0

5

A

b

s

t

r

a

c

t

Using a series transformation, Stirling-De Moivre asymptotic series ap-

proximation to the Gamma function is convertedinto a new one with better

convergence properties.

The new formula is compared with those of Stir-

ling, Laplace and Ramanujan for real arguments greaterthan 0.5 and turns

out to be, for equal number of ’correction’ terms, numerically

superior to

all of them. As a side benefit, a closed-form approximation has turned up

during the analysis which is about as good as 3rd order Stirling’s (maxi-

mum relative error smaller than 1e-10 for real arguments greater

or equal

to 10). Note: this articleis an extended version

of an older one [7] to which

it adds the estimate of the remainder.

1

I

n

t

r

o

d

u

c

t

i

o

n

1

.

1

T

h

e

m

a

i

n

r

e

s

u

l

t

In this paper, as we claimed in the abstract,we present a new asymptotic expansion for the

gamma function for real arguments greateror equal than one. We give an explicit formula

for the coe�cients in the seriesand estimate the error.

After the proof, we compared

our new formula with some classical results. The numerical

comparisonshows that for

equal number of ’correction’ terms the new formula is the most accurate and it is highly

recommended for computing the Gamma function for large real arguments.

T

h

e

o

r

e

m

1

.

Let x

� 1, then for every n

� 1, the following expression holds:

� (x) =

x

e

n

�1X

k

=0

G

k

x

2k

+ R

n

(x)

!!x

r 2⇡x

,

(1.1)

where R

n

(x) = O� 1

x

2n

� and the G

k

coe�cients are given by

G

k

=

X

m

1,m2,..

.

,

m

k�0

2m

1+4m

2+.

.

.

+2k

m

k=2k

kY

r

=1

1m

r

!

✓B

2r

2r (2r � 1)

◆m

r

,

G

0 = 1,(1.2)

where B

r

denotes the r

t

h Bernoulli number [4]. Moreover, if x

� n

+ 1, then

|Rn

(x)|

(n + 1) e

+8e1

/

5

n

(2n� 1) (2⇡)2n

! ⇣n

x

⌘2n

.

(1.3)

1n

e

m

e

s

g

e

r

y

@

g

m

a

i

l

.

c

o

m

1

Read academic paper

New asymptotic expansion for the � (x) function

Gergo Nemes

1

December 7, 2008

http://dx.doi.org/10.3247/sl2math08.005

Abstract

Using a series transformation, Stirling-De Moivre asymptotic series ap-proximation to the Gamma function is converted into a new one with betterconvergence properties. The new formula is compared with those of Stir-ling, Laplace and Ramanujan for real arguments greater than 0.5 and turnsout to be, for equal number of ’correction’ terms, numerically superior toall of them. As a side benefit, a closed-form approximation has turned upduring the analysis which is about as good as 3rd order Stirling’s (maxi-mum relative error smaller than 1e-10 for real arguments greater or equalto 10). Note: this article is an extended version of an older one [7] to whichit adds the estimate of the remainder.

1 Introduction

1.1 The main result

In this paper, as we claimed in the abstract, we present a new asymptotic expansion for thegamma function for real arguments greater or equal than one. We give an explicit formulafor the coe�cients in the series and estimate the error. After the proof, we comparedour new formula with some classical results. The numerical comparison shows that forequal number of ’correction’ terms the new formula is the most accurate and it is highlyrecommended for computing the Gamma function for large real arguments.

Theorem 1. Let x � 1, then for every n � 1, the following expression holds:

� (x) =

x

e

n�1X

k=0

G

k

x

2k

+ R

n

(x)

!!x

r2⇡

x

, (1.1)

where R

n

(x) = O � 1x

2n

�and the G

k

coe�cients are given by

G

k

=X

m1,m2,...,mk�02m1+4m2+...+2kmk=2k

kY

r=1

1m

r

!

✓B2r

2r (2r � 1)

◆mr

, G0 = 1, (1.2)

where B

r

denotes the r

th Bernoulli number [4]. Moreover, if x � n + 1, then

|Rn

(x)|

(n + 1) e +8e

1/5

n (2n� 1) (2⇡)2n

!⇣n

x

⌘2n

. (1.3)

[email protected]

1

Wednesday, November 16, 11

Page 92: JRuby: Enhancing Java Developers' Lives

}

if (Double.isNaN(x)) { value = Double.NaN; return; }

double int_part = (int) x; sign = (int_part % 2 == 0 && (x - int_part) != 0.0 && (x < 0)) ? -1 : 1; if ((x - int_part) == 0.0 && 0 < int_part && int_part <= FACTORIAL.length) { value = Math.log(FACTORIAL[(int) int_part - 1]); } else if (x < 10) { double rising_factorial = 1; for (int i = 0; i < (int) Math.abs(x) - int_part + 10; i++) { rising_factorial *= (x + i); } NemesLogGamma l = new NemesLogGamma(x + (int) Math.abs(x) - int_part value = l.value - Math.log(Math.abs(rising_factorial)); } else { double temp = 0.0; for (int i = 0; i < NEMES_GAMMA_COEFF.length; i++) { temp += NEMES_GAMMA_COEFF[i] * 1.0 / Math.pow(x, i); }

value = x * (Math.log(x) - 1 + Math.log(temp)) + (Math.log(2) + Math.log(Math.PI) - Math.log(x)) / 2.0; }

…and implement

Hard!

Wednesday, November 16, 11

Page 93: JRuby: Enhancing Java Developers' Lives

man gamma

man…

Wednesday, November 16, 11

Page 94: JRuby: Enhancing Java Developers' Lives

Not reinventing the wheel

TGAMMA(3) BSD Library Functions Manual TGAMMA(3)

NAME tgamma, lgamma, gamma -- gamma and log of gamma

SYNOPSIS #include <math.h>

double tgamma(double x);⋮

DESCRIPTION tgamma() calculates the gamma function of x. lgamma() calculates the natural logorithm of the absolute value of the gamma function of x. gamma() is the same function as tgamma. Its use is deprecated.

Wednesday, November 16, 11

Page 95: JRuby: Enhancing Java Developers' Lives

$ java Example

Example.class

javac

JNI Workflow

Example.java Example.hjavah

gamma.c libgamma.dylibcc

Wednesday, November 16, 11

Page 96: JRuby: Enhancing Java Developers' Lives

import java.util.*;

class Example { native static double gamma(double x);

static { System.loadLibrary("gamma"); }

public static void main(String args[]) { System.out.println(gamma(0.5)); }}

Example.java

Wednesday, November 16, 11

Page 97: JRuby: Enhancing Java Developers' Lives

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class Example */

#ifndef _Included_Example#define _Included_Example#ifdef __cplusplusextern "C" {#endif/* * Class: Example * Method: gamma * Signature: (D)D */JNIEXPORT jdouble JNICALL Java_Example_gamma (JNIEnv *, jclass, jdouble);

#ifdef __cplusplus}#endif#endif

Example.h

Wednesday, November 16, 11

Page 98: JRuby: Enhancing Java Developers' Lives

#include "Example.h"#include <math.h>

JNIEXPORT jdouble JNICALL Java_Example_gamma(JNIEnv* env,jclass jclass, jdouble jdbl) { return tgamma(jdbl);}

gamma.c

Wednesday, November 16, 11

Page 99: JRuby: Enhancing Java Developers' Lives

$ javah Example.java$ javac Example.java$ gcc -shared gamma.c -o libgamma.dylib \ -I /Library/Java/JavaVirtualMachines/1.6.0_29-b11-397.jdk/Contents/Headers/

$ java Example1.772453850905516

Voilà!

Wednesday, November 16, 11

Page 100: JRuby: Enhancing Java Developers' Lives

require 'ffi'

module Gamma extend FFI::Library ffi_lib FFI::Library::LIBC attach_function :tgamma, [:double], :doubleend

puts Gamma::tgamma(0.5)

gamma.rb

Wednesday, November 16, 11

Page 101: JRuby: Enhancing Java Developers' Lives

Same result*!$ jruby gamma.rb 1.77245385090552

$ jruby --1.9 -e 'p Math::gamma(0.5)'1.77245385090552

Wednesday, November 16, 11

Page 102: JRuby: Enhancing Java Developers' Lives

Benchmark$ jruby --1.9 bench_gamma.rb Rehearsal ----------------------------------------------------------------pure_java 3.432000 0.000000 3.432000 ( 3.432000)JNI 0.409000 0.000000 0.409000 ( 0.409000)FFI 0.281000 0.000000 0.281000 ( 0.281000)-------------------------------------------------------- total: 4.122000sec

user system total realpure_java 2.849000 0.000000 2.849000 ( 2.849000)JNI 0.288000 0.000000 0.288000 ( 0.289000)FFI 0.219000 0.000000 0.219000 ( 0.219000)

Wednesday, November 16, 11

Page 103: JRuby: Enhancing Java Developers' Lives

But…

What ab

out Indy?

h0p://www.flickr.com/photos/evablue/5665409533/

Wednesday, November 16, 11

Page 104: JRuby: Enhancing Java Developers' Lives

Invokedynamic!• Only mainstream

alternative JVM language• Worked closely with

Hotspot team• JRuby master/1.7• Waiting for Java 1.7.0u2

release• What does it mean for

you?

Wednesday, November 16, 11

Page 105: JRuby: Enhancing Java Developers' Lives

0

4

8

12

16

fib +calls +consts +both richardsredblack

1.9x3.2x

7.4x

14.2x

3.6x

5.5x

1.6x1.8x

3.5x4.4x

1.7x2.7x

Times faster than Ruby 1.9.3

JRuby on Java 6JRuby on invokedynamic

Benchmark

Wednesday, November 16, 11

Page 106: JRuby: Enhancing Java Developers' Lives

0

0.075

0.150

0.225

0.300

currentTimeMillis Thread#name

Benchmark

No indy With indyWednesday, November 16, 11

Page 107: JRuby: Enhancing Java Developers' Lives

Indy TODOs• Remaining invocation paths

–varargs, super, all Java paths• Per-type specialization

–Faster block-receiving calls–Faster module methods

• More code in Ruby!

Wednesday, November 16, 11

Page 109: JRuby: Enhancing Java Developers' Lives

References• http://ruby-lang.org• http://jruby.org• http://pragprog.com/book/jruby/using-jruby• http://rubyonrails.org• http://torquebox.org• http://tomcat.apache.org• http://jetty.codehause.org• http://glassfish.java.net• https://www.relishapp.com/rspec• http://cukes.info

Wednesday, November 16, 11