锁定老帖子 主题:JRuby使用经验
精华帖 (1) :: 良好帖 (17) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-05-10
最后修改:2009-05-15
首先我是一个Java程序员,很喜欢Ruby.
在这一过程中,在 dennis_zane
同学身上,我学到了很多与Ruby相关或者不相关的东西,借机感谢一下.
require "your_jar_file_name.jar" import your_packet_name
class JavaClazz { public void javaMethod(int i) { System.out.pintln(i); } }
java_clazz = JavaClazz.new java_clazz.javaMethod(1)
java_clazz = JavaClazz.new java_clazz.javaMethod(java.lang.Integer.new(1)) 注:以上代码是运行在 JRuby 1.1.2 版本下,在最新版本 1.2.0中已经没有这个问题了, 多谢 RednaxelaFX 同学的指正.
class JavaClazz { public void javaMethod(int i,String... s) { ... // your code } }
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))
=======================================华丽的分割线========================================
class JavaClazz { public final String CONSTANT = "I can not change!" public enum Season { winter, spring, summer, fall } }
puts JavaClazz::CONSTANT puts JavaClazz::Season.winter
//加载核心包的路径就是放在这个系统属性中的 System.getProperty("com.sun.script.jruby.loadpath"); //可以设置自己的路径 System.setProperty("com.sun.script.jruby.loadpath","/root/.jruby/lib/ruby/1.8")
public synchronized Object eval(Reader reader, ScriptContext ctx) throws ScriptException { Node node = compileScript(reader, ctx); return evalNode(node, ctx); }
/** * */ 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); } }
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-05-14
楼主强,赞一个。 关于整数传递,看着代码有些难受,有没有优雅一点的解决方法?
|
|
返回顶楼 | |
发表时间:2009-05-15
关于整数传递,还是有办法可以看代码好看些.
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 这样写了. |
|
返回顶楼 | |
发表时间:2009-05-15
奇怪,之前我用JRuby的时候只是在可变长度参数那边痛苦过一阵,在整型上好像……我也不记得了。总之在Windows XP上用JRuby 1.1.5来测的话,
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 |
|
返回顶楼 | |
发表时间:2009-05-15
最后修改:2009-05-15
整型的转换有问题,是在 jruby 1.1.2 下面,已经注明了版本.
刚刚用jruby 1.2.0测试了一下已经没有问题了,应该是jruby已经修正了. |
|
返回顶楼 | |
发表时间:2009-09-11
一直不解Ruby,主要是没有机会使用。
期待将来在应用中使用Ruby。。。 |
|
返回顶楼 | |
浏览 5730 次