JRuby: Enhancing Java Developers' Lives

  • 1,784 views
Uploaded on

This is a talk from Devoxx 2011. …

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.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,784
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
51
Comments
0
Likes
7

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. JRuby: Enhancing Java Developers Lives Hiro Asari @hiro_asari JRuby Support Engineer Engine Yard @engineyardWednesday, November 16, 11
  • 2. JRuby: a Brief History Where it came from, and where it is nowWednesday, November 16, 11
  • 3. History • September 10, 2001 Source:(WikipediaWednesday, November 16, 11
  • 4. HistoryWednesday, November 16, 11
  • 5. History • 10+ years old • Led by Charles Nutter and Tom Enebo • 14.800+ commitsWednesday, November 16, 11
  • 6. Project Status • Current Stable Release: 1.6.5 • Compatible with Ruby 1.8.7 and 1.9.2 • Supports Rails 3.1Wednesday, November 16, 11
  • 7. Getting JRuby h0p://jruby.org/downloadWednesday, November 16, 11
  • 8. Trying JRuby h0p://jruby.org/tryjrubyWednesday, November 16, 11
  • 9. BookWednesday, November 16, 11
  • 10. Quick Tour of Ruby A brief overview of the languageWednesday, November 16, 11
  • 11. Classes public class Circle extends Shape { class Circle < Shape private final int radius; def initialize(radius) @radius = radius public Circle(int radius) { end this.radius = radius; } attr_reader :radius public int getRadius() { return radius; def area } Math::PI*(@radius ** public double getArea() { 2) return Math.PI * Math.pow(radius,2); end } end public static void main(String[] a) { double area=new Circle(2).getArea(); puts Circle.new(2).area System.out.println(area); } }Wednesday, November 16, 11
  • 12. Single Inheritance Same Thing public class Circle extends Shape { class Circle < Shape private final int radius; def initialize(radius) @radius = radius public Circle(int radius) { end this.radius = radius; } attr_reader :radius public int getRadius() { return radius; def area } Math::PI*(@radius ** public double getArea() { 2) return Math.PI * Math.pow(radius,2); end } end public static void main(String[] a) { double area=new Circle(2).getArea(); puts Circle.new(2).area System.out.println(area); } }Wednesday, November 16, 11
  • 13. Constructor public class Circle extends Shape { class Circle < Shape private final int radius; def initialize(radius) @radius = radius public Circle(int radius) { end this.radius = radius; } attr_reader :radius public int getRadius() { return radius; def area } Math::PI*(@radius ** public double getArea() { 2) return Math.PI * Math.pow(radius,2); end } end public static void main(String[] a) { double area=new Circle(2).getArea(); puts Circle.new(2).area System.out.println(area); } }Wednesday, November 16, 11
  • 14. No Type Declarations public class Circle extends Shape { class Circle < Shape private final int radius; def initialize(radius) @radius = radius public Circle(int radius) { end this.radius = radius; } attr_reader :radius public int getRadius() { return radius; def area } Math::PI*(@radius ** public double getArea() { 2) return Math.PI * Math.pow(radius,2); end } end public static void main(String[] a) { double area=new Circle(2).getArea(); puts Circle.new(2).area System.out.println(area); } }Wednesday, November 16, 11
  • 15. Instance Variables ‘@’ == ‘this.’ and is mandatory public class Circle extends Shape { class Circle < Shape private final int radius; def initialize(radius) @radius = radius public Circle(int radius) { end this.radius = radius; } attr_reader :radius public int getRadius() { return radius; def area } Math::PI*(@radius ** public double getArea() { 2) return Math.PI * Math.pow(radius,2); end } end public static void main(String[] a) { double area=new Circle(2).getArea(); puts Circle.new(2).area System.out.println(area); } }Wednesday, November 16, 11
  • 16. Working with Instance Variables Common tasks are easy public class Circle extends Shape { class Circle < Shape private final int radius; def initialize(radius) @radius = radius public Circle(int radius) { end this.radius = radius; } attr_reader :radius public int getRadius() { return radius; def area } Math::PI*(@radius ** public double getArea() { 2) return Math.PI * Math.pow(radius,2); end } end public static void main(String[] a) { double area=new Circle(2).getArea(); puts Circle.new(2).area System.out.println(area); } }Wednesday, November 16, 11
  • 17. Symbols :identifier • Prefixed with a colon • Uniquely defined in a runtimeWednesday, November 16, 11
  • 18. Point of No Return Last Expression is always return value public class Circle extends Shape { class Circle < Shape private final int radius; def initialize(radius) @radius = radius public Circle(int radius) { end this.radius = radius; } attr_reader :radius public int getRadius() { return radius; def area } Math::PI*(@radius ** public double getArea() { 2) return Math.PI * Math.pow(radius,2); end } end public static void main(String[] a) { double area=new Circle(2).getArea(); puts Circle.new(2).area System.out.println(area); } }Wednesday, November 16, 11
  • 19. .new is just a class method public class Circle extends Shape { class Circle < Shape private final int radius; def initialize(radius) @radius = radius public Circle(int radius) { end this.radius = radius; } attr_reader :radius public int getRadius() { return radius; def area } Math::PI*(@radius ** public double getArea() { 2) return Math.PI * Math.pow(radius,2); end } end public static void main(String[] a) { double area=new Circle(2).getArea(); puts Circle.new(2).area System.out.println(area); } }Wednesday, November 16, 11
  • 20. Blocks/Closures • Pass an anonymous function to a method call # Look mom...no boilerplate! my_open(file) do |io| letters.group_by {|b| b.zip_code } first_line = io.gets # ... end def my_open(file, mode=r) io = File.open(file) yield io button.action_performed do ensure exit io.close end endWednesday, November 16, 11
  • 21. Modules module Enumerable class MyTree def find(if_none = nil) include Enumerable each { |o| return o if yield(o) } if_none # tree impl not shown :) end def each # Many other methods not shown # yield each element # in tree def collect end ary = [] end each { |o| ary << yield(o) } ary end end dude = people.find { |person| person.id == 123 } floats = [1,2].collect { |int| int.to_f } # => [1.0, 2.0]Wednesday, November 16, 11
  • 22. Everything is an Expression class Color COLORS = {:red => 0xff0000, :green => 0x00ff00, :blue => 0x0000ff} COLORS.each do |name, value| define_method(name) do value end end endWednesday, November 16, 11
  • 23. Classes/Modules are open class MyTree def each #... end end #... later in source #... maybe even different file class MyTree def debug #... end endWednesday, November 16, 11
  • 24. Pure OO Language • Everything is an object MyTree.foo #=> method call 12 + 8 #=> here, + is a method on Fixnum, 12. 12.to_s(8) #=> "14" puts 11.odd? #=> trueWednesday, November 16, 11
  • 25. JRuby on Rails Rubys Killer appWednesday, November 16, 11
  • 26. Java Web Frameworks Devoxx 2010Wednesday, November 16, 11
  • 27. Java Web Frameworks h0p://j.mp/raible<jvm<frameworks COMPARING JVM WEB FRAMEWORKS Matt Raible http://raibledesigns.com Images by Stuck in Customs - http://www.flickr.com/photos/stuckincustoms © 2010, Raible Designs © 2010 Raible DesignsWednesday, November 16, 11
  • 28. Install Rails $ jruby -S gem install rails Fetching: 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.3 Successfully installed activesupport-3.1.1 ⋮ Successfully installed thor-0.14.6 Successfully installed rack-ssl-1.3.2 Successfully installed json-1.6.1-java Successfully installed rdoc-3.11 Successfully installed railties-3.1.1 Successfully installed bundler-1.0.21 Successfully installed rails-3.1.1 31 gems installedWednesday, November 16, 11
  • 29. Generate Rails app $ jruby -S rails new awesomeapp create ⋮ create vendor/plugins create vendor/plugins/.gitkeep run bundle install Fetching 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
  • 30. 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.scssWednesday, November 16, 11
  • 31. Migrate Database $ jruby -S rake db:migrate == CreatePeople: migrating ==================================== -- create_table(:people) -> 0.0040s -> 0 rows == CreatePeople: migrated (0.0040s) ===========================Wednesday, November 16, 11
  • 32. Start Server $ 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=3000Wednesday, November 16, 11
  • 33. First PageWednesday, November 16, 11
  • 34. app/controllers/people_controller.rb class 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 ⋮ endWednesday, November 16, 11
  • 35. JSON out of the boxWednesday, November 16, 11
  • 36. app/models/person.rb class Person < ActiveRecord::Base endWednesday, November 16, 11
  • 37. Rails DeploymentWednesday, November 16, 11
  • 38. Rails IDE and text editors jetbrains.com/ruby/ redcareditor.com netbeans.org •emacs •vi(m) •TextMateWednesday, November 16, 11
  • 39. JRuby in Java web app Requests JRuby / /vets /rack/ Java/ Spring AppWednesday, November 16, 11
  • 40. JRuby in Java web app diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 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
  • 41. Rails in Java web app Requests / /vets JRuby /owners Java/ / /vets /owners /1/pets Spring AppWednesday, November 16, 11
  • 42. Rails in Java web app diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 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
  • 43. More… h0p://bit.ly/refactoring<to<rails h0p://vimeo.com/25410705Wednesday, November 16, 11
  • 44. Testing Libraries Test-Driven DevelopmentWednesday, November 16, 11
  • 45. Testing Number of Tests Written (1000s) 100 75 50 25 Easy Hard Ease of Writing TestsWednesday, November 16, 11
  • 46. 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.scssWednesday, November 16, 11
  • 47. DeepThought.java class DeepThought { public static int answerToEverything(Object obj) { return 42; } public static String getName() { return "DeepThought"; } }Wednesday, November 16, 11
  • 48. RSpec require 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 end endWednesday, November 16, 11
  • 49. RSpec $ javac DeepThrought.java $ jruby -rubygems deep_thought_spec.rb .. Finished in 0.013 seconds 2 examples, 0 failuresWednesday, November 16, 11
  • 50. Cucumber Feature: AnswerToEverything Ask DeepThought the answer to everything Scenario: Ask a question Given nil as input Then the result should be 42 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
  • 51. Cucumber $ jruby -S cucumber Feature: 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.065sWednesday, November 16, 11
  • 52. 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 BiniWednesday, November 16, 11
  • 53. JTestr Example my_project/ build.xml! test/ test_hashmap.rb hashmap_spec.rb lib/ jtestr.jar src/ <your source ;) >Wednesday, November 16, 11
  • 54. 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
  • 55. Ruby’s test/unit test/test_hashmap.rb 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 end endWednesday, November 16, 11
  • 56. RSpec revisited test/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 end endWednesday, November 16, 11
  • 57. Results $ ant test Buildfile: /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 SUCCESSFUL Total time: 7 secondsWednesday, November 16, 11
  • 58. Ant-Rake IntegrationWednesday, November 16, 11
  • 59. Problem… NUL Windows dev.null /dev/null dev_null Un*x everything elseWednesday, November 16, 11
  • 60. 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
  • 61. Ruby if os.family == unix :dev_null = /dev/null elsif os.family == windows :dev_null = NUL else :dev_null = dev_null endWednesday, November 16, 11
  • 62. 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
  • 63. Ruby def 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 => 0 endWednesday, November 16, 11
  • 64. 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 end endWednesday, November 16, 11
  • 65. 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"/> build.xml </target> </project> task :its_in_rake => [:setup, :its_in_ant] do puts "its in Rake" end task :setup do puts "setup in Rake" end RakefileWednesday, November 16, 11
  • 66. 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"/> build.xml </target> </project> task :its_in_rake => [:setup, :its_in_ant] do puts "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 67. 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 "its in Rake" end task :setup do puts "setup in Rake" end RakefileWednesday, November 16, 11
  • 68. 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 "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 69. 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 "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 70. 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 "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 71. 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 "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 72. Rake tasks as Ant targets Buildfile: build.xml <project name="foobar" default="top-level" basedir="."> [rakeimport] (in /tmp/example2) <description>Builds, tests, and runs foobar.</description> <taskdef name="rakeimport" setup: 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 "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 73. Rake tasks as Ant targets Buildfile: build.xml <project name="foobar" default="top-level" basedir="."> [rakeimport] (in /tmp/example2) <description>Builds, tests, and runs foobar.</description> <taskdef name="rakeimport" setup: setup in Rake 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 "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 74. Rake tasks as Ant targets Buildfile: build.xml <project name="foobar" default="top-level" basedir="."> [rakeimport] (in /tmp/example2) <description>Builds, tests, and runs foobar.</description> <taskdef name="rakeimport" setup: setup in Rake classname="org.jruby.ant.RakeImport"/> <rakeimport/> its_in_ant: <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 "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 75. Rake tasks as Ant targets Buildfile: build.xml <project name="foobar" default="top-level" basedir="."> [rakeimport] (in /tmp/example2) <description>Builds, tests, and runs foobar.</description> <taskdef name="rakeimport" setup: setup in Rake classname="org.jruby.ant.RakeImport"/> <rakeimport/> its_in_ant: <target name="top-level" depends="its_in_rake" ant: its_in_ant [echo] /> <target name="its_in_ant"> <echo message="ant: its_in_ant"/> </target> </project> task :its_in_rake => [:setup, :its_in_ant] do puts "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 76. Rake tasks as Ant targets Buildfile: build.xml <project name="foobar" default="top-level" basedir="."> [rakeimport] (in /tmp/example2) <description>Builds, tests, and runs foobar.</description> <taskdef name="rakeimport" setup: setup in Rake classname="org.jruby.ant.RakeImport"/> <rakeimport/> its_in_ant: <target name="top-level" depends="its_in_rake" ant: its_in_ant [echo] /> <target name="its_in_ant"> its_in_rake: <echo message="ant: its_in_ant"/> </target> </project> task :its_in_rake => [:setup, :its_in_ant] do puts "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 77. Rake tasks as Ant targets Buildfile: build.xml <project name="foobar" default="top-level" basedir="."> [rakeimport] (in /tmp/example2) <description>Builds, tests, and runs foobar.</description> <taskdef name="rakeimport" setup: setup in Rake classname="org.jruby.ant.RakeImport"/> <rakeimport/> its_in_ant: <target name="top-level" depends="its_in_rake" ant: its_in_ant [echo] /> <target name="its_in_ant"> its_in_rake: its in Rake <echo message="ant: its_in_ant"/> </target> </project> task :its_in_rake => [:setup, :its_in_ant] do puts "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 78. Rake tasks as Ant targets Buildfile: build.xml <project name="foobar" default="top-level" basedir="."> [rakeimport] (in /tmp/example2) <description>Builds, tests, and runs foobar.</description> <taskdef name="rakeimport" setup: setup in Rake classname="org.jruby.ant.RakeImport"/> <rakeimport/> its_in_ant: <target name="top-level" depends="its_in_rake" ant: its_in_ant [echo] /> <target name="its_in_ant"> its_in_rake: its in Rake <echo message="ant: its_in_ant"/> </target> </project> top-level: BUILD SUCCESSFUL task :its_in_rake => [:setup, :its_in_ant] time: 7 seconds Total do puts "its in Rake" end task :setup do puts "setup in Rake" endWednesday, November 16, 11
  • 79. More… http://bit.ly/rake_antWednesday, November 16, 11
  • 80. Maven and RubyGemsWednesday, November 16, 11
  • 81. 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
  • 82. Maven artifacts as gems jruby -S gem install mvn:org.clojure:clojure mavenWednesday, November 16, 11
  • 83. Maven artifacts as gems jruby -S gem install mvn:org.clojure:clojure group IDWednesday, November 16, 11
  • 84. Maven artifacts as gems jruby -S gem install mvn:org.clojure:clojure artifact IDWednesday, November 16, 11
  • 85. Maven artifacts as gems jruby -S gem install mvn:org.clojure:clojure Successfully installed mvn:org.clojure:clojure-1.4.0.a.2-java 1 gem installed Some restrictions applyWednesday, November 16, 11
  • 86. Maven artifacts as gems $ jruby -S irb irb(main):001:0> require mvn:org.clojure:clojure => true irb(main):002:0> java_import Java::clojure.lang.PersistentHashMap => Java::ClojureLang::PersistentHashMap irb(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
  • 87. Foreign Function Interface Calling native functionsWednesday, November 16, 11
  • 88. Gamma function ∞ Γ(z) = ∫ t 0 z-1e-1 dtWednesday, November 16, 11
  • 89. Apache Commons? org.apache.commons.math.special Class Gamma java.lang.Object org.apache.commons.math.special.Gamma public class Gamma extends java.lang.Object This 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 $Wednesday, November 16, 11
  • 90. Apache Commons? org.apache.commons.math.special Class Gamma ize ? java.lang.Object e org.apache.commons.math.special.Gamma s Rs public class Gamma en extends java.lang.Object Lic This is a utility class that provides computation methods related JA to the Gamma family of functions. Version: $Id: Gamma.java 1131229 2011-06-03 20:49:25Z luc $Wednesday, November 16, 11
  • 91. for the coe cients in the series and estimate the error. After the Read academic paper our new formula with some classical results. The numerical comp equal number of ’correction’ terms the new formula is the most acc recommended for computing the Gamma function for large real arg Theorem 1. Let x 1, unction every n then for 1, the following express ( x) f or the !!x r sion f n 1 X Gk 2⇡ expan x ptotic (x) = + Rn (x) 1 Neme s , New asym G ˝ ergo e x2k x 8 er 7, 200 05 k=0 ecemb t h08.0 D sl2ma 7/ 0.324 wherex.don.o = O d R i (x) rg/1 1 x2n and the Gk coe cients are given by - // ap http: otic series ter ract re as ympt with bet - Abst , St -De Moiv a new one se of Stir irling erted into X wit h tho nd turns Y 1 ✓ k B2r ◆mr ation n is conv pared than 0.5 a rior to sform G = io k com s tran ma funct formula is ts greater ically sup ed up e , U serie m n sing a to the Ga The new al argume rms, num on has tu maxi- er rn m ! 2r (2r 1)r atio n ertie s. for re n’ te m1 ,m2 ,...,msk( 0 al ima ti ing’ r=1 p roxim nce prop amanujan ’correctio 2m p+4mer+...+2kmu =2k p rox rd Stirl r or eq e f rm a 1 e co nverg lace and R number o closed-fo d as 3rd o nts great to which 2 k Lap ual t, a goo ume e [7] ling, be, for eq side benefi about as al arg n older on or re o ut to em. As a ich is an 1e-10 f ersion th of a where B denotes the r th si all of the analy r rmall g o s wh er th s ne xtend ed v Bernoulli number [4]. Moreover, if x n durin elative err article is a mainder. r s e mum Note: thi te of the r ! ). a to 10 the estim 8e1/5 the ⇣ n ⌘2 adds n for a it |Rn (x)|  mptot+expxpeci+ormu ed (n ic 1) li t f ansio l 2n n w as y an e mnr(2n pa 1) (2⇡) x uctio nt a n e e give of, we co for Introd se pre ct, we ual than one. W ro the p n shows tha t hly 1 esult nr a abstr r or eq . After pariso is higWednesday, November 16, 11 1 i e ma in the ate error com and i t
  • 92. …and implementif (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.leng value = Math.log(FACTORIAL[(int) int_part - 1]); d} relse if (x < 10) { double rising_factorial = 1; a for (int i = 0; i < (int) Math.abs(x) - int_part + 10; i++) { rising_factorial *= (x + i); H } NemesLogGamma l = new NemesLogGamma(x + (int) Math.abs(x) - int_par 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;}Wednesday, November 16, 11
  • 93. man… man gammaWednesday, November 16, 11
  • 94. 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
  • 95. JNI Workflow javah Example.java Example.h cc gamma.c libgamma.dylib javac Example.class $ java ExampleWednesday, November 16, 11
  • 96. Example.java 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)); } }Wednesday, November 16, 11
  • 97. Example.h /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class Example */ #ifndef _Included_Example #define _Included_Example #ifdef __cplusplus extern "C" { #endif /* * Class: Example * Method: gamma * Signature: (D)D */ JNIEXPORT jdouble JNICALL Java_Example_gamma (JNIEnv *, jclass, jdouble); #ifdef __cplusplus } #endif #endifWednesday, November 16, 11
  • 98. gamma.c #include "Example.h" #include <math.h> JNIEXPORT jdouble JNICALL Java_Example_gamma(JNIEnv* env, jclass jclass, jdouble jdbl) { return tgamma(jdbl); }Wednesday, November 16, 11
  • 99. Voilà! $ 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 Example 1.772453850905516Wednesday, November 16, 11
  • 100. gamma.rb require ffi module Gamma extend FFI::Library ffi_lib FFI::Library::LIBC attach_function :tgamma, [:double], :double end puts Gamma::tgamma(0.5)Wednesday, November 16, 11
  • 101. Same result*! $ jruby gamma.rb 1.77245385090552 $ jruby --1.9 -e p Math::gamma(0.5) 1.77245385090552Wednesday, November 16, 11
  • 102. 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 real pure_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
  • 103. But… d y? I n ut a b o ha t W h0p://www.flickr.com/photos/evablue/5665409533/Wednesday, November 16, 11
  • 104. 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
  • 105. Benchmark Times faster than Ruby 1.9.3 16 14.2x 12 8 7.4x 5.5x 4.4x 4 2.7x 3.6x 3.5x 3.2x 1.7x 1.8x 1.6x 1.9x 0 fib +calls +consts +both richardsredblack JRuby on Java 6 JRuby on invokedynamicWednesday, November 16, 11
  • 106. Benchmark 0.300 0.225 0.150 0.075 0 currentTimeMillis Thread#name No indy With indyWednesday, November 16, 11
  • 107. 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
  • 108. 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
  • 109. 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.infoWednesday, November 16, 11
  • 110. 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=292Wednesday, November 16, 11