54
現実世界のJRuby 日本JRubyユーザ会 中村浩士(なひ) @nahi [email protected]

現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

  • Upload
    lemien

  • View
    223

  • Download
    4

Embed Size (px)

Citation preview

Page 1: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

現実世界のJRuby日本JRubyユーザ会 中村浩士(なひ)@nahi [email protected]

Page 2: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

自己紹介

株式会社サリオンシステムズリサーチ勤務セキュリティ・ネットワーク関連のシステム開発

C/C++ (18年)、Java (13年)、Ruby (13年) 余暇のOSS開発:CRuby (8年)、JRuby (2年)、

soap4r、httpclient他

Page 3: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRubyとは - http://jruby.org/

最新リリース版は1.6.5 JVM上で動作するRuby言語

Open Source (CPL, GPL, LGPL) 開発開始から10年

フルタイム開発者登場から5年

Page 4: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

本日のゴール

Java開発者の皆様向け

RubyとJRubyについて学ぶ

JRubyはどんなところに使える?

Page 5: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Ruby入門

Java開発者向け

Page 6: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Rubyの特徴

人に優しい文法 豊富なメタプログラミング機能 高い生産性 Ruby on Rails + githubの存在

Page 7: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Rubyツアー 1/8: クラス定義

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[] args) { double area = new Circle(2).getArea(); System.out.println(area); }}

extends → <継承は単一継承

メソッド定義 → defコンストラクタ → initialize

class Circle < Shape def initialize(radius) @radius = radius end attr_reader :radius def area Math::PI * (@radius ** 2) endendputs Circle.new(2).area

Page 8: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

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[] args) { 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) endendputs Circle.new(2).area

Rubyツアー 2/8: インスタンス変数

this → @

attr_readerはアクセサメソッド定義用メソッド

Page 9: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

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[] args) { 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) endendputs Circle.new(2).area

Rubyツアー 3/8: 動的型付け

変数に型なしduck-typing

引数の型・数の違いによるメソッドoverloadなし

Page 10: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

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[] args) { 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) endendputs Circle.new(2).area

Rubyツアー 4/8: 全てが値を持つ

return不要文の値は最後の式

Page 11: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

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[] args) { 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) endendputs Circle.new(2).area

Rubyツアー 5/8:全てがオブジェクト、全てがメソッド

Circle: 定数a*2 == a.*(2)

Circle.new: クラスオブジェクトのnewメソッドを呼び出す

Page 12: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Rubyツアー 6/8: ブロック(クロージャ)

def aaa(name, &block) File.open(name) do |file| file.each_line do |line| yield line end endend

aaa('a.txt') do |line| p lineend

(1) File.open用ブロックブロック実行後に自動close (2) each_line用ブロック1行読み込む毎に呼ばれる (3) aaa用ブロックaaa内部のyieldに呼ばれる ← その他利用例

people.group_by { |e| e.lang }

button1 = ...label1 = ...button1.on_action do |event| label1.text = 'sending...'end

(1)(2)

(3)

Page 13: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Rubyツアー 7/8:Mix-in、オープンクラス

module Utils def name self.class.name endendclass Book include Utils def say "Hello from #{name}" endendobj = Book.newp obj.say #=> "Hello from Book"

class Book def say "I'm #{name}" endendp obj.say #=> "I'm Book"

Mix-in: 実装の継承Utilsモジュールの実装を

BookクラスにMix-in オープンクラス:Bookクラスのsayメソッドを再定義

実装

継承

Page 14: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Rubyツアー 8/8: フックメソッド

class Base @@all = [] def self.inherited(klass) @@all << klass endend

class Sub < Base p @@allend

class SubSub < Sub p @@allend

inherited: クラスが継承された場合に、継承したクラスを引数に呼ばれる その他: included、method_added、method_removed、method_missing、const_missing等※@@はクラス変数の接頭辞

※クラスオブジェクトのキャッシュは リークの元なので普通やらない

Page 15: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Ruby言語の特徴(まとめ)

動的型付け 全てがオブジェクト、全てがメソッド ブロック(クロージャ)の活用 メタプログラミング支援

Mix-in、オープンクラス、各種フックメソッド

Page 16: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRubyの特長

Ruby on Railsを含む100%の互換性

C言語版Rubyと同等の実行速度

高いスケーラビリティ(並行動作) Javaとの親和性の高さ

Page 17: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Real-World JRubyJRuby利用実例

Page 18: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Real-World JRuby: JRuby利用実例

Java連携 (Java -> Ruby) Java連携 (Ruby -> Java) Javaテスト (RSpec, JtestR) 開発支援 (Ant, Maven, Jenkins) ウェブ開発 (JRuby on Rails)

Page 19: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Java連携

(Java -> Ruby)ユースケース

Page 20: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Java連携 (Java -> Ruby)

JavaからRubyライブラリを利用

例: 独自定義ファイル解析の

DSL処理系として

import org.jruby.embed.ScriptingContainer;public class HelloWorld { public static void main(String[] args) { ScriptingContainer ruby = new ScriptingContainer(); ruby.runScriptlet("puts \"hello,world!\""); }}

source 'http://localhost/'

group :development do host 'localhost' port 12345 reloadable true debug trueend

group :production do host 'www.example.com'end

Page 21: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

例: gitdiff.rb - gitライブラリを利用し、リビジョ

ンの変更サマリを取得するRubyコード

Java連携 (Java -> Ruby)

require 'rubygems'require 'git'def diff_summary(dir, from, to) diff = Git.open(dir).diff(from, to) diff.stats[:files].map { |file, st| insertions = st[:insertions] || 0 deletions = st[:deletions] || 0 "#{file} +#{insertions} -#{deletions}" }end# =>[ "src/org/jruby/Ruby.java +32 -20",# "src/org/jruby/RubyArray.java +93 -17",# "src/org/jruby/RubyBasicObject.java +7 -0", ...

Page 22: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Javaからの呼び出しと抽出

Java連携 (Java -> Ruby)

public class GitDiff { public static void main(String[] args) throws Exception {

ScriptingContainer ruby = new ScriptingContainer();ruby.runScriptlet("require 'gitdiff'");

ruby.put("dir", "/home/nahi/git/jruby/");ruby.put("from", "8c6dba0f...");ruby.put("to", "7837c84a...");

List array = (List) ruby.runScriptlet( "diff_summary(dir, from, to)");for (Object obj : array) {

System.out.println(obj.toString());}...

Page 23: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Java連携

(Ruby -> Java)ユースケース

Page 24: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Java連携 (Ruby -> Java)

RubyからJavaの機能を利用する

Javaの対話環境としての利用も可能% jruby -S irb> require 'java'=> true> ni = java.net.NetworkInterface.networkInterfaces.to_a.first=> #<Java::JavaNet::NetworkInterface:0x4d33b92c>> ni.getName=> "eth0"> ni.isUp=> true> ni.getMtu=> 1500> ni.inetAddresses.map { |addr| addr.to_s }=> ["/fe80:0:0:0:20c:29ff:fead:4bed%2", "/192.168.96.129"]

Page 25: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Flying Saucerを使ってHTMLをPDF変換http://code.google.com/p/flying-saucer/

Java連携 (Ruby -> Java)

% ls flyingsaucer-R8core-renderer.jar iText-2.0.8.jar ...% jruby -S irb -Iflyingsaucer-R8> require 'java'> require 'iText-2.0.8.jar'> require 'core-renderer.jar'> rr = org.xhtmlrenderer.pdf.ITextRenderer.new> doc = <<EOD<html><body><h1>Hello JRuby</h1><p>from <a href="http://code.google.com/p/flying-saucer/">Flying Saucer</a>.</p></body></html>EOD> rr.set_document_from_string(doc)> rr.layout> File.open("out.pdf", "w") { |f| rr.create_pdf(f.to_outputstream) }

Page 26: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRubyFX:JRuby binding for JavaFX 2.0

Java FX 2.0を利用してJRuby GUIアプリ開発https://github.com/nahi/jrubyfx (デモ)

Page 27: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRubyFX: SVGLoader example

Javaライブラリの組み合わせrequire 'jrubyfx'# https://github.com/skrb/SVGLoaderrequire 'SVGLoader.jar'java_import 'net.javainthebox.caraibe.svg.SVGLoader'class SVGLoaderApp include JRubyFX def start(stage) root = build(Group) { children << SVGLoader.load("/duke.svg").root } with(stage, title: 'SVGLoader sample', scene: build(Scene, root)).show endendSVGLoaderApp.start

Page 28: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Javaテスト

(RSpec, JtestR)ユースケース

Page 29: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

RubyとJRubyの利点を活かしてJavaをテスト

RSpec:振る舞いをテストhttp://rspec.info

Javaテスト (RSpec)

describe 'ScriptingContainer#put' do before :each do @x = org.jruby.embed.ScriptingContainer.new end it "sets an object to local variable" do obj = Object.new @x.put("var", obj) @x.run_scriptlet("var").should == obj end it "overrides the previous object" do obj = Object.new @x.put("var", obj) @x.put("var", nil) @x.run_scriptlet("var").should be_nil endend

% jruby -S rspec jruby_spec.rb..

Finished in 0.044 seconds2 examples, 0 failures%

Page 30: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Javaテスト (JtestR)

JtestR: 各種Ruby用テストライブラリ同梱http://jtestr.codehaus.org/

describe "X509Name" do it "should use given converter for ASN1 encode" do converter = mock(X509NameEntryConverter) name = X509Name.new('CN=localhost', converter) converter.stubs('getConvertedValue'). with(DERObjectIdentifier.new(CN), 'localhost'). returns(DERPrintableString.new('converted')). times(1) name.toASN1Object.to_string.should == '...' endend

Page 31: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Javaテスト (JtestR)

Ant/Maven統合 + テストサーバ

% ant testBuildfile: /path/to/build.xml

test: [jtestr] Other Spec: 4 examples, 0 failures, 0 errors [jtestr] [jtestr] Total: 4 tests, 0 failures, 0 errors, 0 pending [jtestr]

BUILD SUCCESSFULTotal time: 9 seconds

<?xml version="1.0" encoding="utf-8"?><project basedir="." default="test" name="simple1"> <taskdef name="jtestr" classname="org.jtestr.ant.JtestRAntRunner" classpath="build_lib/jtestr.jar" /> <taskdef name="jtestr-server" classname="org.jtestr.ant.JtestRAntServer" classpath="build_lib/jtestr.jar" /> <target name="test"> <jtestr port="20333"/> </target> <target name="test-server"> <jtestr-server port="20333" runtimes="3"/> </target></project>

Page 32: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

開発支援

(Ant, Maven, Jenkins)ユースケース

Page 33: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

開発支援 (Ant連携)

Rake: Rubyの記述力を活かしてビルド手順を記述 Ant、Rakeから相互にタスクを利用可能

desc "Build JRuby"task :build do ant "jar"endtask :jar => :builddesc "Clean all built output"task :clean do delete_files = FileList.new do |fl| fl. include("#{BUILD_DIR}/**"). exclude("#{BUILD_DIR}/rubyspec"). include(DIST_DIR). include(API_DOCS_DIR) end ...<target name=”load-rake-task”>

<taskdef name=”rake” classname=”org.jruby.ant.Rake”/></target><target name=”default” depends=”load-rake-task”> <rake task=”jar”/></target>

Page 34: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

開発支援 (Maven連携)

Maven配布物はrubygemsとしてインストール可能

開発環境の部分的Ruby化を支援

% jruby -S gem install bouncycastle:bcprov-jdk15

require 'rubygems'require 'maven/bouncycastle/bcprov-jdk15'...

Page 35: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Ruby Plugins for Jenkinshttp://bit.ly/JenkinsRuby JenkinsのプラグインをRubyで記述可能

開発支援 (Jenkins連携)

Page 36: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

開発支援 (Jenkins連携)例: Travis CI設定を読んで自動ビルド

class TravisScriptBuilder < Jenkins::Tasks::Builder def prebuild(build, listener) travis_file = build.workspace + '.travis.yml' unless travis_file.exist? listener.error "Travis config `#{travis_file}' not found" raise "Travis config file not found" end ... def perform(build, launcher, listener) run_scripts(setup_env) ... def run_scripts(env) %w{before_script script after_script}.each do |type| scan_multiline_scripts(config[type]).each do |script| launcher.execute(env, script, :chdir => workspace, :out => listener) ...

Page 37: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

ウェブ開発

(JRuby on Rails)ユースケース

Page 38: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

ウェブ開発 (JRuby on Rails)

Ruby on Rails - http://rubyonrails.org

ウェブアプリケーションフレームワーク フルスタック CoC: (XML)設定より規約(に従って開発)

DRY: 同じことを繰り返さない

Page 39: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Railsツアー 1/7:アプリケーションの生成

MVC、テスト、サードパーティライブラリ等常に同じディレクトリ構成

% jruby -S rails new myapp create create README create Rakefile ... create vendor/plugins create vendor/plugins/.gitkeep run bundle installFetching source index for http://rubygems.org/Using rake (0.9.2.2)Installing multi_json (1.0.3)...Installing sass-rails (3.1.5)Installing uglifier (1.1.0)Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

Page 40: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Railsツアー 2/7: scaffold

アプリの雛形作り(慣れると不要)

% jruby -S rails g scaffold todo done:boolean description:string invoke active_record create db/migrate/20111128065332_create_todos.rb create app/models/todo.rb invoke test_unit create test/unit/todo_test.rb create test/fixtures/todos.yml route resources :todos invoke scaffold_controller create app/controllers/todos_controller.rb invoke erb create app/views/todos ... invoke scss create app/assets/stylesheets/scaffolds.css.scss%

Page 41: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Railsツアー 3/7: DBマイグレーション

スクリプトによるDBスキーマ履歴管理class CreateTodos < ActiveRecord::Migration def change create_table :todos do |t| t.boolean :done t.string :description t.timestamps end endend % jruby -S rake db:migrate== CreateTodos: migrating ====================================================-- create_table(:todos) -> 0.0040s -> 0 rows

Page 42: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

scaffoldだけでも動く

% jruby -S rails server=> Booting WEBrick=> Rails 3.1.3 application starting in development on http://0.0.0.0:3000=> Call with -d to detach=> Ctrl-C to shutdown server[2011-11-28 15:58:15] INFO WEBrick 1.3.1[2011-11-28 15:58:15] INFO ruby 1.8.7 (2011-11-27) [java]

Railsツアー 4/7: サーバ起動

Page 43: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Railsツアー 5/7: 生成されたコード

モデル

ビュー

コントローラ

class Todo < ActiveRecord::Baseend

class TodosController < ApplicationController def index @todos = Todo.all respond_to do |format| format.html # index.html.erb format.json { render :json => @todos } end end def create ...end

<%= form_for(@todo) do |f| %> <div class="field"> <%= f.label :done %><br /> <%= f.check_box :done %> </div> <div class="field"> <%= f.label :description %><br /> <%= f.text_field :description %> </div> <div class="actions"> <%= f.submit %> </div><% end %>

Page 44: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Railsツアー 6/7:ActiveRelation (Arel)

遅延SQL生成用のDSL スコープ

Todo.where(:done => false) SELECT "todos".* FROM "todos" WHERE "todos"."done" = 'f'Todo.where(:done => false).where('created_at < "2011-11-29"') SELECT "todos".* FROM "todos" WHERE "todos"."done" = 'f' AND (created_at < "2011-11-29")Todo.where(:done => false).order("created_at DESC").limit(1) SELECT "todos".* FROM "todos" WHERE "todos"."done" = 'f' ORDER BY created_at DESC LIMIT 1

class Todo < ActiveRecord::Base scope :finished, where(:done => true)end Todo.finished.size SELECT COUNT(*) FROM "todos" WHERE "todos"."done" = 't'

Page 45: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JSONでのCRUD

Railsツアー 7/7: RESTインターフェース

% jruby -rubygems -e 'require "httpclient"; puts HTTPClient.get("http://localhost:3000/todos/1.json").body'=>{ "created_at":"2011-11-28T06:59:14Z", "description":"牛乳を買う", ... }

% jruby -rubygems -e 'require "json"; require "httpclient";puts HTTPClient.post("http://localhost:3000/todos", JSON.generate(:todo => {:description => "JRubyのベンチマーク", :done => false}), "Accept" => "application/json", "Content-Type" => "application/json").body'=>{ "created_at":"2011-11-28T07:36:19Z", "description":"JRubyのベンチマーク", ... }

Page 46: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

ウェブ開発 (JRuby on Rails)

Railsの全ての機能 + 既存Javaライブラリ活用

Javaアプリと同居可能

SpringMVCからRailsへのリファクタリング事例

1) "Petclinic"にJRubyでREST APIを追加

2) Railsの同居

3) Spring利用の機能をRailsで置き換えhttp://bit.ly/refactoring-to-rails

Page 47: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRuby on Railsのデプロイ

WAR形式 → 任意のアプリサーバで動作専用アプリサーバ:

Trinidad (Tomcatベース)http://www.engineyard.com/

TorqueBox (JBossベース)clustering、messaging、scheduling他http://torquebox.org/

PaaS: Engine Yard Cloudhttp://www.engineyard.com

Page 48: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRubyのこれから

InvokeDynamic と IR

Page 49: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

Java SE 7: InvokeDynamic

新たなメソッド呼び出しバイトコード

bootstrapメソッド

dynamic language support (java.lang.invoke.*)

MethodHandleMethodTypeSwitchPointCallSite

Page 50: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRubyにおけるInvokeDynamic効果

Java 5/6でのメソッド呼び出し

Page 51: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRubyにおけるInvokeDynamic効果

Java 7 +JRuby 1.7.0.dev(開発中)

Page 52: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

JRubyにおけるInvokeDynamic効果

Java 6/7上で動作させたJRubyの比較※横軸は速度(大きいほうが速い)

Page 53: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

IR: JRubyの新しい内部表現形式

最適化方式の抜本的な変更を模索 構文木ベースの最適化から新中間表現ベースへ

Page 54: 現実世界のJRuby - · PDF file% ls flyingsaucer-R8 core-renderer.jar iText-2.0.8.jar ... % jruby -S irb -Iflyingsaucer-R8 > require 'java' ... RubyとJRubyの利点を活かしてJava

まとめ: JRuby - http://jruby.org

Java開発者にも学び易いRuby言語

JavaとRubyの連携方式が豊富

現実世界で使われるフレームワーク、ライブラリ

Rails、RSpec、JtestR、Jenkinsgit、scripting、DSL

Java開発者のツールベルトに