View
1.881
Download
2
Category
Tags:
Preview:
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.
Citation preview
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
Thank you!• Twitter: @hiro_asari• Github: BanzaiMan
– Code examples:• jtestr-example • jni-gamma• test_example_deepthought• http://github.com/jruby/jruby
http://www.engineyard.com/tryjrubyWednesday, 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
References• http://jtestr.codehaus.org/• http://www.ebyte.it/library/docs/math07/
GammaApproximation.html• http://download.oracle.com/javase/6/docs/
technotes/guides/jni/• http://jcp.org/en/jsr/detail?id=292
Wednesday, November 16, 11
Recommended