<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>richfisher</title>
    <link>https://ruby-china.org/richfisher</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>Getting started with JRuby</title>
      <description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;最近尝试在 JRuby 里集成&lt;a href="https://github.com/richfisher/jruby_activiti" rel="nofollow" target="_blank" title=""&gt;Java 工作流组件&lt;/a&gt;，遇到不少令人困惑的点，关于 JRuby 的资料不多，记录下一些心得。&lt;/p&gt;
&lt;h2 id="安装 JRuby"&gt;安装 JRuby&lt;/h2&gt;
&lt;p&gt;环境和工具：Mac, rvm&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rvm get head
rvm install jruby-9.0.4.0   
rvm use jruby-9.0.4.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你也可以创建一个&lt;code&gt;.ruby-version&lt;/code&gt;文件在项目目录，进入目录就会自动切换至 JRuby。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'jruby-9.0.4.0' &amp;gt; .ruby-version
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="调用 Java"&gt;调用 Java&lt;/h2&gt;
&lt;p&gt;首先创建一个目录 &lt;code&gt;getting-started-with-jruby&lt;/code&gt;, 下面的代码都可以在&lt;a href="https://github.com/richfisher/getting-started-with-jruby" rel="nofollow" target="_blank" title=""&gt;Github&lt;/a&gt;找到。&lt;/p&gt;
&lt;h3 id="quick start"&gt;quick start&lt;/h3&gt;
&lt;p&gt;创建一个 Java 文件 &lt;code&gt;Hello.java&lt;/code&gt; &lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Hello {
    public static void world(){
        System.out.println("Hello JRuby!");
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译成 class 文件 &lt;code&gt;javac Hello.java&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;在 JRuby 里&lt;code&gt;require 'java'&lt;/code&gt; 后你可以访问所有在 classpath 里的 java classes。&lt;/p&gt;

&lt;p&gt;创建一个 ruby 文件 &lt;code&gt;calling-class-in-root.rb&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'java'
Java::Hello.world()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在命令行运行 &lt;code&gt;ruby calling-class-in-root.rb&lt;/code&gt;, 看到输出 &lt;code&gt;Hello JRuby!&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="classpath"&gt;classpath&lt;/h3&gt;
&lt;p&gt;运行 jruby 所在的目录是 classpath, 所有运行目录里的&lt;code&gt;.class&lt;/code&gt;文件可以在 JRuby 里访问。&lt;/p&gt;

&lt;p&gt;classpath 可以通过设置 CLASSPATH 环境变量进行扩展&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$CLASSPATH &amp;lt;&amp;lt; "classes"
# or $CLASSPATH &amp;lt;&amp;lt; "file:///#{File.expand_path('classes')}/"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建一个 java 文件 &lt;code&gt;java/src/main/java/SubHello.java&lt;/code&gt;, 并编译。&lt;/p&gt;

&lt;p&gt;在项目目录创建一个 ruby 文件 &lt;code&gt;calling-class-in-sub-folder.rb&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'java'
$CLASSPATH &amp;lt;&amp;lt; "java/src/main/java"

Java::SubHello.world()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在命令行运行 &lt;code&gt;ruby calling-class-in-sub-folder.rb&lt;/code&gt;, 看到输出 &lt;code&gt;Hello jruby in sub folder!&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="import jar file"&gt;import jar file&lt;/h3&gt;
&lt;p&gt;jar 文件须在 classpath 或者手动 require&lt;/p&gt;

&lt;p&gt;require 'path/to/mycode.jar'&lt;/p&gt;

&lt;p&gt;在&lt;code&gt;java&lt;/code&gt;目录创建&lt;code&gt;pom.xml&lt;/code&gt;,  运行 &lt;code&gt;mvn package&lt;/code&gt; 打包成 &lt;code&gt;demo-1.0.jar&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;在项目目录创建一个 ruby 文件 &lt;code&gt;calling-jar.rb&lt;/code&gt;, &lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'java'
require './java/target/demo-1.0.jar'
Java::SubHello.world()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在命令行运行 &lt;code&gt;ruby calling-jar.rb&lt;/code&gt;, 看到输出 &lt;code&gt;Hello jruby in sub folder!&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="jbundler"&gt;jbundler&lt;/h3&gt;
&lt;p&gt;像&lt;code&gt;bundler&lt;/code&gt;一样管理 jar 依赖，首先安装&lt;/p&gt;

&lt;p&gt;gem install jbundler&lt;/p&gt;

&lt;p&gt;在项目目录创建&lt;code&gt;Jarfile&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;jar 'commons-io:commons-io', '2.4'&lt;/p&gt;

&lt;p&gt;在命令行运行 &lt;code&gt;jbundle install&lt;/code&gt; 安装声明的 jar 包。&lt;/p&gt;

&lt;p&gt;在 JRuby 里&lt;code&gt;require 'jbundler'&lt;/code&gt;后，你将能调用 Jarfile 里声明的包&lt;/p&gt;

&lt;p&gt;在项目目录创建一个 ruby 文件 &lt;code&gt;calling-jar-with-jbundler.rb&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'java'
require 'jbundler'

file = java.io.File.new('./Jarfile')
lines = org.apache.commons.io.FileUtils.readLines(file, "UTF-8")
puts lines
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你将看到输出 &lt;code&gt;[jar 'commons-io:commons-io', '2.4']&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;你也可以使用驼峰风格调用 java&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'java'
require 'jbundler'

file = Java::JavaIo::File.new('./Jarfile')
lines = Java::OrgApacheCommonsIo::FileUtils.readLines(file, "UTF-8")
puts lines
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="加速JRuby启动"&gt;加速 JRuby 启动&lt;/h2&gt;&lt;h3 id="JRuby 的 --dev 参数"&gt;JRuby 的 --dev 参数&lt;/h3&gt;
&lt;p&gt;使用 "--dev" 参数等价于同时设置以下几个 JRuby 参数：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;client mode where applicable (generally older 32-bit JVMs). The client mode is designed to start up quickly and not optimize as much. &lt;/li&gt;
&lt;li&gt;TieredCompilation and TieredStopAtLevel=1, equivalent to client mode on newer Hotspot-based JVMs&lt;/li&gt;
&lt;li&gt;compile.mode=OFF to disable JRuby's JVM bytecode compiler&lt;/li&gt;
&lt;li&gt;jruby.compile.invokedynamic=false to disable the slow-to-warmup invokedynamic features of JRuby&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在开发过程，想要程序启动更快而不关心运行效率，--dev 参数应该不错。&lt;/p&gt;
&lt;h3 id="在rvm使用 --dev 参数"&gt;在 rvm 使用 --dev 参数&lt;/h3&gt;
&lt;p&gt;RVM 提供了一个 hook 文件&lt;code&gt;$rvm_path/hooks/after_use_jruby_opts&lt;/code&gt;，将它变成可执行之后，每次切换至 JRuby 会根据环境变量 PROJECT_JRUBY_OPTS 添加 JRuby 的启动参数。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod +x $rvm_path/hooks/after_use_jruby_opts
echo 'PROJECT_JRUBY_OPTS=(--dev)' &amp;gt; ~/.rvmrc
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="其他工具"&gt;其他工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;[X] rails/spring 只支持 MRI Ruby, JRuby 不支持&lt;code&gt;fork&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[X] spork, 启动报错 &lt;code&gt;TypeError: no implicit conversion of Fixnum into String&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[✓] &lt;a href="https://github.com/mrbrdo/theine" rel="nofollow" target="_blank" title=""&gt;theine&lt;/a&gt; 与 Spork 类似
&lt;code&gt;theine_server&lt;/code&gt;
&lt;code&gt;thenine some command&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[X] &lt;a href="https://github.com/ninjudd/drip" rel="nofollow" target="_blank" title=""&gt;drip&lt;/a&gt;
运行&lt;code&gt;rails runner&lt;/code&gt;挂死&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="启动速度测试"&gt;启动速度测试&lt;/h3&gt;
&lt;p&gt;分别用 MRI Ruby 和 JRuby 创建两个 Rails 项目。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rvm use 2.2.3
gem install rails
rails new ruby-on-rails

rvm use jruby-9.0.4.0
gem install rails
rails new jruby-on-rails

time rake test
time rails s
time rails runner "puts Rails.env"
&lt;/code&gt;&lt;/pre&gt;&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ruby&lt;/th&gt;
&lt;th&gt;jruby&lt;/th&gt;
&lt;th&gt;jruby --dev&lt;/th&gt;
&lt;th&gt;theine&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rake test&lt;/td&gt;
&lt;td&gt;3.841s&lt;/td&gt;
&lt;td&gt;13.547s&lt;/td&gt;
&lt;td&gt;7.451s&lt;/td&gt;
&lt;td&gt;4.882s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rails s&lt;/td&gt;
&lt;td&gt;4.796s&lt;/td&gt;
&lt;td&gt;20.914s&lt;/td&gt;
&lt;td&gt;11.833s&lt;/td&gt;
&lt;td&gt;5.084s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rails runner&lt;/td&gt;
&lt;td&gt;2.128s&lt;/td&gt;
&lt;td&gt;17.116s&lt;/td&gt;
&lt;td&gt;9.718s&lt;/td&gt;
&lt;td&gt;4.464s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;总结：使用 &lt;code&gt;--dev&lt;/code&gt; 参数可以减少大约 45% 的启动时间，使用 &lt;code&gt;theine&lt;/code&gt; 还能进一步加速。&lt;/p&gt;
&lt;h2 id="关于JRuby的运行效率"&gt;关于 JRuby 的运行效率&lt;/h2&gt;
&lt;p&gt;JRuby 的启动速度比较糟糕，运行效率又怎么样呢？&lt;/p&gt;

&lt;p&gt;还是对两个空白的 Rails 项目进行简单的测试&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Ruby on Rails&lt;/th&gt;
&lt;th&gt;JRuby on Rails&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ab -n 1000 -c 1&lt;/td&gt;
&lt;td&gt;22.103ms&lt;/td&gt;
&lt;td&gt;16.275ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ab -n 1000 -c 10&lt;/td&gt;
&lt;td&gt;22.079ms&lt;/td&gt;
&lt;td&gt;12.622ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ab -n 1000 -c 50&lt;/td&gt;
&lt;td&gt;22.051ms&lt;/td&gt;
&lt;td&gt;12.236ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;虽然不代表真实的项目，从结果来看 JRuby 的运行效率是不错的。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jruby/jruby/wiki/ClasspathAndLoadPath" rel="nofollow" target="_blank"&gt;https://github.com/jruby/jruby/wiki/ClasspathAndLoadPath&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mkristian/jbundler" rel="nofollow" target="_blank"&gt;https://github.com/mkristian/jbundler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jruby/jruby/wiki/Improving-startup-time" rel="nofollow" target="_blank"&gt;https://github.com/jruby/jruby/wiki/Improving-startup-time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/8283300/how-do-i-use-jruby-opts-with-rvm" rel="nofollow" target="_blank"&gt;http://stackoverflow.com/questions/8283300/how-do-i-use-jruby-opts-with-rvm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.headius.com/2009/05/jruby-nailgun-support-in-130.html" rel="nofollow" target="_blank"&gt;http://blog.headius.com/2009/05/jruby-nailgun-support-in-130.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mrbrdo/theine" rel="nofollow" target="_blank"&gt;https://github.com/mrbrdo/theine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/2224178/how-to-improve-jruby-load-time" rel="nofollow" target="_blank"&gt;http://stackoverflow.com/questions/2224178/how-to-improve-jruby-load-time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ninjudd/drip" rel="nofollow" target="_blank"&gt;https://github.com/ninjudd/drip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/rwjblue/4582914" rel="nofollow" target="_blank"&gt;https://gist.github.com/rwjblue/4582914&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>richfisher</author>
      <pubDate>Fri, 05 Feb 2016 18:19:57 +0800</pubDate>
      <link>https://ruby-china.org/topics/28960</link>
      <guid>https://ruby-china.org/topics/28960</guid>
    </item>
    <item>
      <title>view 中的逻辑处理，helper vs draper?</title>
      <description>&lt;p&gt;helper 大家都很熟悉，不多说。&lt;/p&gt;

&lt;p&gt;Draper 的英文介绍是 View Models for Rails，给 model 对象添加显示相关的职责，以下是自己写的两个例子。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserDecorator &amp;lt; ApplicationDecorator
  decorates :user

  def full_name
    model.first_name + model.second_name
  end
end

class ArticleDecorator &amp;lt; ApplicationDecorator
  decorates :article

  def created_at
    model.created_at.to_s(:db)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;假设 Article belongs_to Category
要在 view 中显示 cateogry 的连接
1、Drapper 的做法：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ArticleDecorator &amp;lt; ApplicationDecorator
  decorates :article

  def category_name
    model.category.name if model.category.present?
  end

  def category_link
    h.link_to category_name,h.category_path(model.category) if model.category.present?
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 view 中
= &lt;a href="/article.category_lin" class="user-mention" title="@article.category_lin"&gt;&lt;i&gt;@&lt;/i&gt;article.category_lin&lt;/a&gt;k&lt;/p&gt;

&lt;p&gt;2、helper 的做法&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module ArticleHelper
  def show_category_link(article)
    link_to article.category.name, category_path(article.category) if article.category.present?
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 view 中
=show_category_link(article)&lt;/p&gt;

&lt;p&gt;哪种方法更好呢？大家对 draper 怎么看呢？
如何区分两者的适用场合呢？  &lt;/p&gt;</description>
      <author>richfisher</author>
      <pubDate>Thu, 05 Jan 2012 12:38:40 +0800</pubDate>
      <link>https://ruby-china.org/topics/741</link>
      <guid>https://ruby-china.org/topics/741</guid>
    </item>
  </channel>
</rss>
