- 浏览: 165366 次
- 性别:
- 来自: 广州
最新评论
-
dongxuef:
正奇怪呢,原来你也没深究.源码中_params被default ...
在Rails的controller中访问params的一个小细节 -
sunsonavaj:
Rails 3 下自定义错误信息显示页面 -
Hooopo:
Thx!
ubuntu下让netbeans的字体变得好看些 -
ybffnst:
paperclip 对错误消息的处理是对字符串进行处理的,不支 ...
如何自定义处理ActiveRecord中的errors信息 -
wozhidao:
这个方法有个很大的bug,远程图片的时候是取不到扩展名的,上传 ...
paperclip定制文件名
首先我是一个Java程序员,很喜欢Ruby.
公司由于业务的需要,在Java项目中引入动态语言,目的是可以快速地修改业务逻辑以响应快速变化的业务需求.于是我有幸当了一回JRuby的先锋.当初使用JRuby的时候,我对JRuby项目的了解其实就是知道它可以让Ruby运行在JVM上面,其余细节一概不知,都是在实际使用中一点点地摸索,一点点地积累回来.
在这一过程中,在 dennis_zane
同学身上,我学到了很多与Ruby相关或者不相关的东西,借机感谢一下.
JRuby的中文资料相当的稀少,在 Google上搜索,来来去去的就是介绍了下最基本的怎么从Java中调用Ruby代码,或者在Ruby中使用Java的类库.我从无数次遇到问题 => 解决问题的循环中也有那么一点点的使用心得,记录之,备忘.
* JRuby的入门资料,请访问 JRuby wiki 一般的使用方法这里都有介绍.
* 有两种方法可以使用JRuby,一是用BSF,二是使用JDK 6.BSF的方式已经过时了,JDK6中内置了对脚本语言的支持,默认的Javascript,要使用JRuby还要下载juby-engine.jar,当前最新版本是1.1.6 地址: https://scripting.dev.java.net/files/documents/4957/115972/jruby-engine-1.1.6.zip
=======================================华丽的分割线========================================
如果使用jar打包,在ruby代码中调用java的类
require "your_jar_file_name.jar" import your_packet_name
java 方法:
class JavaClazz { public void javaMethod(int i) { System.out.pintln(i); } }
在Ruby中如是调用:
java_clazz = JavaClazz.new java_clazz.javaMethod(1)
将会抛出类型不匹配的异常,因为所有ruby中的数值,传递到java那里都是 Long 类型,解决办法如下:
java_clazz = JavaClazz.new java_clazz.javaMethod(java.lang.Integer.new(1))
注:以上代码是运行在 JRuby 1.1.2 版本下,在最新版本 1.2.0中已经没有这个问题了, 多谢 RednaxelaFX 同学的指正.
=======================================华丽的分割线========================================
如果在java中使用了可变参数:
class JavaClazz { public void javaMethod(int i,String... s) { ... // your code } }
在ruby中应该这样调用:
java_clazz = JavaClazz.new java_clazz.javaMethod(java.lang.Integer.new(1),'this is a string') // 只有一个参数,如果你知道java中的可变参数其实是一个数组的话 java_clazz.javaMethod(java.lang.Integer.new(1),[].to_java(java.lang.String))
=======================================华丽的分割线========================================
调用java中的常量,枚举enum
class JavaClazz { public final String CONSTANT = "I can not change!" public enum Season { winter, spring, summer, fall } }
puts JavaClazz::CONSTANT puts JavaClazz::Season.winter
=======================================华丽的分割线========================================
如果你想使用ruby核心包,必须正确设置jruby的加载路径,从Sun实现的JRubyScriptEngine.java的源代码可以看到:
//加载核心包的路径就是放在这个系统属性中的 System.getProperty("com.sun.script.jruby.loadpath"); //可以设置自己的路径 System.setProperty("com.sun.script.jruby.loadpath","/root/.jruby/lib/ruby/1.8")
=======================================华丽的分割线========================================
关于官方JRuby引擎的问题
Sun官方实现的脚本引擎在多并发的情况下是会比较慢的,查看JRubyScriptEngine.java的源代码,可以看到eval方法是加上了synchronized
public synchronized Object eval(Reader reader, ScriptContext ctx) throws ScriptException { Node node = compileScript(reader, ctx); return evalNode(node, ctx); }
我至今想不明白,这个官方实现为什么会加上 synchronized
我自己山寨了一个JRubyScriptEngine的东西,直接调用JRuby的 JavaEmbedUtils 类来执行脚本,还是相当好用的.
/** * */ package org.opensource.script.jruby; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.jruby.Ruby; import org.jruby.RubyRuntimeAdapter; import org.jruby.javasupport.JavaEmbedUtils; import org.jruby.runtime.GlobalVariable; import org.jruby.runtime.builtin.IRubyObject; /** * 山寨版JRubyScriptEngine * 弃用官方版的原因是由于它封装的invokeMethod方法使用了synchronized关键字,在多并发的情况下性能极差. * * @author yanghuan * */ public class JRubyScriptEngine { private final Ruby runtime; private final RubyRuntimeAdapter evaler; private final Map<String, IRubyObject> rubyObjectCache = new HashMap<String, IRubyObject>(); public JRubyScriptEngine() { ArrayList<String> loadPaths = new ArrayList<String>(); loadPaths.add("/root/.jruby/lib/ruby/1.8"); loadPaths.add("/root/.jruby/lib/ruby/site_ruby/1.8"); runtime = JavaEmbedUtils.initialize(loadPaths, JavaEmbedUtils .createClassCache(this.getClass().getClassLoader())); evaler = JavaEmbedUtils.newRuntimeAdapter(); } /** * 根据脚本的路径,获取脚本eval后的Ruby对象,首先会从cache中检索,如有即时返回,如果没有则eval脚本,再返回.保证不会重复eval * * @param fullPath * 绝对路径 * @return * @throws FileNotFoundException * @throws Exception */ private IRubyObject getRubyObject(final String fullPath) throws FileNotFoundException { if (rubyObjectCache.get(fullPath) == null) { return evalScript(fullPath); } return rubyObjectCache.get(fullPath); } /** * 执行脚本,返回脚本对象 把这个方法从 * #getRubyObject分出来,并且加上synchronized关键字,纯粹是为了防止多并发重复eval脚本 * * @param fullPath * @return * @throws FileNotFoundException */ private synchronized IRubyObject evalScript(final String fullPath) throws FileNotFoundException { if (rubyObjectCache.get(fullPath) == null) { File scriptFile = new File(fullPath); InputStream in = new FileInputStream(scriptFile); IRubyObject rubyObject = evaler.parse(runtime, in, scriptFile.getAbsolutePath(), 1).run(); rubyObjectCache.put(fullPath, rubyObject); return rubyObject; } return rubyObjectCache.get(fullPath); } /** * 加载脚本 * * @param fullPath * @throws FileNotFoundException */ public void load(final String fullPath) throws FileNotFoundException { getRubyObject(fullPath); } /** * 清空已加载脚本对象 * * @param fullPath */ public void clean(final String fullPath) { if (rubyObjectCache.get(fullPath) != null) { rubyObjectCache.remove(fullPath); } } /** * 定义全局变量 * * @param name * 变量名,不用以$开头 * @param value * 值 */ public void defineGlobalVariable(final String name, final Object value) { IRubyObject rubyObject = JavaEmbedUtils.javaToRuby(runtime, value); /** * 这个全局变量的定义有点儿诡异,源代码是这样定义的:globalVariables.define(variable.name(), * newIAccessor() {}),所以必须手工加上 $ 开关 **/ GlobalVariable variable = new GlobalVariable(runtime, name.startsWith("$") ? name : "$" + name, rubyObject); runtime.defineVariable(variable); } /** * 执行脚本中定义的class的方法 * * @param fullPath * 脚本绝对路径 * @param method * 方法名 * @param args * 参数 * @return * @throws FileNotFoundException */ public Object invokeMethod(final String fullPath, final String method, Object[] args) throws FileNotFoundException { IRubyObject rubyObject = getRubyObject(fullPath); return JavaEmbedUtils.invokeMethod(runtime, rubyObject, method, args, Object.class); } }
评论
期待将来在应用中使用Ruby。。。
刚刚用jruby 1.2.0测试了一下已经没有问题了,应该是jruby已经修正了.
E:\sdk\jruby-1.1.5\bin>jirb irb(main):001:0> JInteger = java.lang.Integer => Java::JavaLang::Integer irb(main):002:0> JInteger.toString(1) => "1" irb(main):003:0> JInteger.toString(18, 16) => "12"
java.lang.Integer的静态toString()就这俩重载,直接在JRuby 1.1.5里用也没问题。新的1.1.6、1.2和即将出来的1.3应该都还好吧?
用自己写的类也没问题:
public class Foo { public int increment(int i) { return i + 1; } }
编译打包到Foo.jar后,
E:\sdk\jruby-1.1.5\bin>jirb irb(main):001:0> require 'Foo.jar' => true irb(main):002:0> Foo = Java::Foo => Java::Default::Foo irb(main):003:0> f = Foo.new => #<Java::Default::Foo:0x3e926 @java_object=Foo@bfd66a> irb(main):004:0> f.increment(1) => 2 irb(main):005:0> quit
require "java" include_class("java.lang.Integer") { |package, name| "J" + name } i = JInteger.new(1)
不能使用
import java.lang.Integer i = Integer.new(1)
是因为 Ruby 也有一个 Integer的类,会造成冲突,上面是使用重命名的方法来解决命名冲突的问题.
我比较懒,顺手就 java.lang.Integer 这样写了.
发表评论
-
Rails 2.3.12下遇到的named route的诡异问题
2011-08-14 21:18 1614周五的时候把网站升级到Rails 2.3.12,本来在本地测试 ... -
ActionMailer的一些配置
2011-08-14 20:59 1611一般情况下,如果你使用gmail的话,都是这样配置的: A ... -
如何自定义处理ActiveRecord中的errors信息
2011-07-26 23:33 2811今天写代码的时候,客服MM向我反馈了一个问题,这个问题本身是很 ... -
Rails 3 下自定义错误信息显示页面
2010-07-08 15:21 3710大家都知道想在Rails下自定义错误显示的页面是修改 resc ... -
paperclip定制文件名
2010-07-02 14:25 3304在新项目中使用了paperclip这个文件上传插件,一切都很满 ... -
Sinatra:一个可以作为Rails有益补充的框架. 简洁而不简单
2010-04-04 15:08 7124一个基于Sinatra的小程序 前些天有一个需求,需要写一个 ... -
require特定版本的gem
2010-03-31 21:07 2536今天有一个需求要单独地使用ActiveRecord,但是我的机 ... -
从Rails 2.3.5 升级到 Rails 3.0 beta
2010-03-27 22:12 2107因为有一个新的项目打算使用Rails 3.0 beta,所以先 ... -
命名时请留意Rails下的关键字
2010-01-22 17:36 2010前些天我在做一个支付集成的接口,对方返回的结果串里面有一个 e ... -
rails下自定义出错页面
2010-01-22 17:17 2316rails出错的时候,一般都是跳转到错误跟踪的页面下,这样在开 ... -
rails下修改http头(http header)
2010-01-22 17:08 5153其实就是修改response中一个叫做headers的Hash ... -
在Rails的controller中访问params的一个小细节
2009-12-02 22:36 7246大家都知道controller中的params其实是一个Has ... -
Rails开发工具之Vim
2009-10-19 16:06 12166学习和开发Ruby & Rails ... -
Thinking Sphinx + Coreseek + rmmseg的安装与使用
2009-10-06 23:48 3767要在Rails上使用全文检索,选择一直不多,以前我一直是使用F ... -
Migrations流水帐
2009-07-11 16:02 1193对于Rails的迁移功能Migrations,一直都只是看一下 ... -
重新安装ruby遇到的问题
2009-06-13 13:14 1288昨天重装了操作系统,要重新安装ruby环境. 因为以前 ... -
使用ri查看Rails的API
2009-03-25 23:31 4436我一直都比较习惯直接到 http://www.ruby-doc ... -
Ubuntu Linux下ruby 1.9.1和Rails 2.3升级记录
2009-03-22 00:22 4379安装 ... -
今晚用上了ruby的动态方法调用,open class和mixin三大神器
2009-01-12 00:43 2176今晚人品爆发,一举用上了ruby的动态方法调用,open cl ... -
让rails中多态关联的方法名更加人性化
2008-12-02 22:55 2400rails中的多态关联功能,很好很强大。 但是多态关联的方法 ...
相关推荐
本文介绍了JRuby的安装与配置。JRuby的安装需要JRuby以及JDK,本文使用的版本分别是JRuby 1.1.2以及Java 1.6。至于JRuby配置,文章主要介绍了测试JRuby安装的方法。
本文介绍了如何用JRuby开发Web Service。用JRuby开发Web Service,需要安装ActionWebService。安装完毕之后便可以开始调用及部署了。
jruby是一个ruby的解析器,可将ruby解析为java文件,jruby作为ruby解析器时刻调用java代码
jruby安装包 和 jruby的lib库 JRuby是面向Ruby、基于Java虚拟机(JVM)的一种解释程序,它结合了Ruby语言的简易性和功能强大的JVM的执行机制,包括与Java库 全面集成。Rails彻底加快及简化了Web应用的开发,不过它让...
jruby-1.3.1.jar包 解决org.jruby.exceptions.JumpException 等报错
jruby与java使用开发,听说jruby能是swing的调用变为更简单
jruby-src-1.0.zip
jruby-complete-1.7.19.jar,java版本的ruby解析器
JRuby在Java测试中的应用,使用脚本语言,高效快进行Java程序测试。
org.jruby.rar
This book introduces you to three JRuby deployment strategies that give you the performance and scalability you need, while you use a language designed for rapid development. Explore common ...
jruby-bin-1.3.1.zip 用于jruby语言研发的必要工具
JRuby window X64 开发软件
自述文件 这是一个示例应用程序,试图让JRuby与ActiveRecord 6和Postgres一起运行。... cd到该文件夹并运行ruby -v确保您正在使用JRuby。 .tool-versions文件将其设置为jruby-9.2.13.0我也尝试了jru
jRuby On Rails WEB 2.0
JRuby语言实战技术,java下运用ruby
jruby 1.9.6 win64
jruby-1.5.5+OperaWatir+RSpec
对于Jruby、Jython和Groovy三种动态语言,长期以来很多人犹豫于如何选择它们。本文提出一个非常有力的例证证明:如果你是一个基于Java虚拟机的开发者,那么请放弃Jruby和Jython。
Now you can bring the best of Ruby into the world of Java, with Using JRuby. Come to the source for the JRuby core team’s insights and insider tips. You’ll learn how to call Java objects seamlessly ...