Skip to content

Instantly share code, notes, and snippets.

@headius
Created January 22, 2010 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save headius/284140 to your computer and use it in GitHub Desktop.
Save headius/284140 to your computer and use it in GitHub Desktop.
require 'clojure'
class MyClojureObj < Clojure::Object
def initialize
dosync { @foo = 'foo' }
end
def foo; @foo; end
def foo=(f); @foo = f; end
end
obj = MyClojureObj.new
puts "obj.foo = " + obj.foo
begin
puts "Setting obj.foo to 'bar'"
obj.foo = 'bar'
rescue ConcurrencyError
puts "Oops, need a transaction"
end
puts "Trying again with a transaction"
dosync { obj.foo = 'bar' }
puts "Success"
puts "obj.foo = " + obj.foo
~/projects/jruby ➔ jruby -J-Xbootclasspath/a:build_lib/clojure-1.0.0.jar cloby.rb
obj.foo = foo
Setting obj.foo to 'bar'
Oops, need a transaction
Trying again with a transaction
Success
obj.foo = bar
package org.jruby.clojure;
import clojure.lang.IPersistentVector;
import clojure.lang.LockingTransaction;
import clojure.lang.PersistentVector;
import clojure.lang.Ref;
import java.io.IOException;
import java.util.concurrent.Callable;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.Block;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.load.Library;
public class ClojureLibrary implements Library{
public void load(Ruby runtime, boolean wrap) throws IOException {
RubyModule cljModule = runtime.defineModule("Clojure");
runtime.defineClassUnder("Object", runtime.getObject(), new ClojureObjectAllocator(), cljModule);
runtime.getKernel().defineAnnotatedMethods(ClojureDosync.class);
}
public static class ClojureObjectAllocator implements ObjectAllocator {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new ClojureObject(runtime, klazz);
}
}
public static class ClojureObject extends RubyObject {
public ClojureObject(Ruby runtime, RubyClass klass) {
super(runtime, klass);
try {
variableTable = new Ref(PersistentVector.EMPTY);
} catch (Exception e) {
throw runtime.newConcurrencyError(e.getLocalizedMessage());
}
}
@Override
public Object getVariable(int index) {
return ((IPersistentVector)variableTable.deref()).nth(index);
}
@Override
public void setVariable(int index, Object value) {
try {
variableTable.set(((IPersistentVector)variableTable.deref()).assocN(index, value));
} catch (IllegalStateException ise) {
throw getRuntime().newConcurrencyError(ise.getLocalizedMessage());
}
}
private final Ref variableTable;
}
public static class ClojureDosync {
@JRubyMethod
public static IRubyObject dosync(final ThreadContext context, final IRubyObject self, final Block block) {
final Ruby ruby = context.getRuntime();
try {
return (IRubyObject)LockingTransaction.runInTransaction(new Callable() {
public Object call() throws Exception {
// re-get transaction in case this gets run in different threads
return block.call(ruby.getCurrentContext());
}
});
} catch (Exception e) {
throw ruby.newConcurrencyError(e.getLocalizedMessage());
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment