jruby: enhancing java developers' lives

Post on 15-May-2015

1.875 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

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

JRuby:Enhancing Java Developers' Lives

Hiro Asari@hiro_asariJRuby Support EngineerEngine Yard@engineyard

Wednesday, November 16, 11

JRuby: a Brief History

Where it came from, and where it is now

Wednesday, November 16, 11

History• September 10, 2001Source:(Wikipedia

Wednesday, November 16, 11

History

Wednesday, November 16, 11

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

Tom Enebo• 14.800+ commits

Wednesday, November 16, 11

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

Getting JRuby

h0p://jruby.org/download

Wednesday, November 16, 11

Trying JRubyh0p://jruby.org/tryjruby

Wednesday, November 16, 11

Book

Wednesday, November 16, 11

Quick Tour of Ruby

A brief overview of the language

Wednesday, November 16, 11

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

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

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

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

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

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

Symbols:identifier

• Prefixed with a colon• Uniquely defined in a runtime

Wednesday, November 16, 11

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

.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

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

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

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

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

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

JRuby on RailsRuby's Killer app

Wednesday, November 16, 11

Java Web Frameworks

Devoxx 2010

Wednesday, November 16, 11

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

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

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

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

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

Migrate Database

Wednesday, November 16, 11

$ 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

First Page

Wednesday, November 16, 11

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

JSON out of the box

Wednesday, November 16, 11

class Person < ActiveRecord::Baseend

app/models/person.rb

Wednesday, November 16, 11

Rails Deployment

Wednesday, November 16, 11

netbeans.org

Rails IDE and text editors

jetbrains.com/ruby/

redcareditor.com

•emacs•vi(m)•TextMate

Wednesday, November 16, 11

App

Requests

/vets/ Java/Spring

JRuby

/rack/

JRuby in Java web app

Wednesday, November 16, 11

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

App

/vets /owners/ /owners/1/pets

Requests

Java/Spring

/vets/ JRuby

Rails in Java web app

Wednesday, November 16, 11

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

More…

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

Wednesday, November 16, 11

Testing LibrariesTest-Driven Development

Wednesday, November 16, 11

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

$ 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

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

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

Wednesday, November 16, 11

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

$ javac DeepThrought.java

$ jruby -rubygems deep_thought_spec.rb ..

Finished in 0.013 seconds2 examples, 0 failures

RSpec

Wednesday, November 16, 11

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

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

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

JTestr Example

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

Wednesday, November 16, 11

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

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

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

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

Ant-Rake Integration

Wednesday, November 16, 11

Problem…

dev.null

NUL

Windows

/dev/null

Un*x

dev_null

everything else

Wednesday, November 16, 11

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

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

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

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

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

<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

<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

<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

<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

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

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

<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

<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

<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

<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

<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

<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

<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

<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

More…

http://bit.ly/rake_ant

Wednesday, November 16, 11

Maven and RubyGems

Wednesday, November 16, 11

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

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

Maven artifacts as gems

maven

Wednesday, November 16, 11

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

group ID

Maven artifacts as gems

Wednesday, November 16, 11

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

artifact ID

Maven artifacts as gems

Wednesday, November 16, 11

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

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

Foreign Function Interface

Calling native functions

Wednesday, November 16, 11

Gamma function

=∫ tz-1e-1 dt0

Γ(z)

Wednesday, November 16, 11

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

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

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)

1nemesgery@gmail.com

1

Wednesday, November 16, 11

}

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

man gamma

man…

Wednesday, November 16, 11

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

$ java Example

Example.class

javac

JNI Workflow

Example.java Example.hjavah

gamma.c libgamma.dylibcc

Wednesday, November 16, 11

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

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

#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

$ 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

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

Same result*!$ jruby gamma.rb 1.77245385090552

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

Wednesday, November 16, 11

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

But…

What ab

out Indy?

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

Wednesday, November 16, 11

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

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

0

0.075

0.150

0.225

0.300

currentTimeMillis Thread#name

Benchmark

No indy With indyWednesday, November 16, 11

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

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

top related