ITコンサルの日常

ITコンサル会社に勤務する普通のITエンジニアの日常です。

JavaからFixturesを使ってみる - Rubyコードを使わずJavaコードのみで実現する編

といっても、evalScriptletを使っているので、少しはRubyコード出てきますが。。
FixturesをRails外で使ってみるRubyコードをJavaに移植するイメージ。

import org.jruby.*;
import org.jruby.runtime.*;
import org.jruby.runtime.builtin.*;

public class CallRuby
{
	public static void main(String[] args) throws Exception
	{
		// JRuby環境を取得
		Ruby runtime = Ruby.newInstance();
		ThreadContext context = runtime.getCurrentContext();

		// 必要なgemをrequire
		runtime.evalScriptlet("require 'rubygems'");
		runtime.evalScriptlet("require 'active_record'");
		runtime.evalScriptlet("require 'active_record/fixtures'");

		// runtime.getClass("ActiveRecord::Base")は不可
		// ActiveRecordモジュールを取得
		RubyModule activeRecordModule = runtime.getModule("ActiveRecord");
		// ActiveRecord::Baseクラスを取得
		RubyClass activeRecordBaseClass = activeRecordModule.getClass("Base");

		// コネクションを確立
		RubyHash arg = new RubyHash(runtime);
		arg.put(RubySymbol.newSymbol(runtime, "adapter"), "jdbcderby");
		arg.put(RubySymbol.newSymbol(runtime, "database"), "hoge");
		activeRecordBaseClass.callMethod(context, "establish_connection", arg);

		// Fixturesクラスを取得
		System.out.println("insert");
		RubyClass fixturesClass = runtime.getClass("Fixtures");
		RubyString arg1 = runtime.newString("data");
		RubyArray arg2 = runtime.newArray();
		arg2.add("PEOPLE");
		IRubyObject[] arguments = {arg1, arg2};

		// Fixtures#create_fixtures呼び出し
		IRubyObject fixturesObj = fixturesClass.callMethod(context, "create_fixtures", arguments);

		// Personクラスを定義
		//RubyClass personClass = runtime.defineClass("Person", activeRecordBaseClass, ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
		runtime.evalScriptlet("class Person < ActiveRecord::Base\nend");
		RubyClass personClass = runtime.getClass("Person");

		// 全レコードを表示
		System.out.println("select all");
		showAllPersons(runtime, context, personClass);

		// Fixtures#delete_existing_fixtures呼び出し
		System.out.println("delete");
		fixturesObj.callMethod(context, "delete_existing_fixtures");

		// 全レコードを表示
		System.out.println("select all");
		showAllPersons(runtime, context, personClass);

		System.out.println("finish");
	}

	/**
	 *	PEOPLEテーブルの全レコードを表示
	 */
	private static void showAllPersons(Ruby runtime, ThreadContext context, RubyClass personClass)
	{
		RubySymbol arg1 = RubySymbol.newSymbol(runtime, "all");
		RubyHash arg2 = new RubyHash(runtime);
		arg2.put(RubySymbol.newSymbol(runtime, "order"), "ID");
		IRubyObject[] arguments = {arg1, arg2};

		// Person#find呼び出し
		IRubyObject personObjArray = personClass.callMethod(context, "find", arguments);
		RubyArray persons = (RubyArray)personObjArray;

		for(int i=0; i<RubyNumeric.num2int(persons.length()); i++)
		{
			RubyObject personObj = (RubyObject)persons.get(i);
			IRubyObject id = personObj.callMethod(context, "id");
			IRubyObject name = personObj.callMethod(context, "name");
			System.out.println(id + "/" + name);
		}
	}
}

というわけで、なんかうまく動かないところは、evalScriptletに逃げるという策を使えば、
わりとできてしまうことが分かりました。
JRubyAPIって、JavaのリフレクションAPIをたたくのに似てますね。