Hi all,
In the process of porting the hitimes C extension to java I came up with
a few
questions along the way. I initially read Ola’s blog post[1] and then
took a
look at the built in extensions (WeakRef, Readline, Socket, etc) and saw
they
used annotations intead of the MRI style from Ola’s blogpost. I decided
to
head down the annotations path.
In no particular order:
-
BasicLibraryService vs. Library
I started out looking at the built in extensions, and they all
implement
Library, not BasicLibraryService. I assume now that this is because
they are
‘built in extensions’ and hence are ‘require’ via a different path.
This
seems to be validated when you look at Ruby#initBuiltins[2].Of course it wasn’t until this point that I saw the javadoc at the
top
of BasicLibraryService:“This interface should be implemented by writers of Java extensions
to
JRuby.”[3]Just to clarify, if the extension ships in the same jar as jruby,
then it
implements Library and is added to initBuiltins(). If it is in an
external
jar, it implements BasicLibraryService.Is this correct?
-
Accessing the Runtime or ThreadContext inside the extension and
method first
arguments.I needed to access the ruby runtime to be able to return ‘nil’,
‘true’ and
‘false’ from various methods, and I needed to access the
ThreadContext to
implement yielding.Wayne pointed out[4] that when you need to access the Ruby runtime it
is
better to pass ThreadContext as the first argument to the method that
needs
to access the runtime than it is to access this.getRuntime().Is this the appropriate thing to do?
Also, should the first argument of the extension methods ALWAYS be
ThreadContext or IRubyObject? Even if it not used in the method
implementation? -
Annotations
First off, I really like this approach. It makes things really easy
to
understand. You get the declaration of ruby interface of the
method/class
right next to the java implemenation of that method/class.3.1) @JRubyMethod annotation
* Aliases, what to do? Are these equivalent? @JRubyMethod( name = "duration", alias = { "length", "to_f",
“to_seconds” } )
@JRubyMethod( name = { “duration”, “length”, “to_f”,
“to_seconds” } )
* For module methods (@JRubyMethod( name = "now", module = true
)) what
should the java signature look like? Is there a distinction
between
these two?
public static IRubyObject now( IRubyObject self ) { ... }
public static IRubyObject now( ThreadContext context ) { .. }
* For methods that yield (@JRubyMethod( name = "measure", module
= true, frame = true ))
should they always set ‘frame = true’ in the annotation and
what
should the java signatures look like:
public static IRubyObject measure( IRubyObject self, Block
block ) { … }
public static IRubyObject measure( ThreadContext context,
Block block ) { … }
3.2) @JRubyClass annotation
It appears that there are constraints on the actual java class
names
that implement ruby classes. This works and from inside ruby,
Hitimes::Stats is found.
@JRubyClass( name = "Hitimes::Stats" )
public class HitimesStats extends RubyObject { ... }
When implemented in this manner, Hitimes::Stats is NOT found
inside
ruby.
@JRubyClass( name = "Hitimes::Stats" )
public class Stats extends RubyObject { ... }
I did not try with inner classes. Maybe this works, I may give
it a try
later:
@JRubyModule( name = "Hitimes" )
public class Hitimes {
@JRubyClass( name = "Hitimes::Stats" )
public static class Stats { .. }
}
-
Jar file location in the gem
Initially I had the jar in the gem at ‘lib/hitimes/hitimes.jar’ which
worked
fine. Then, in preparation for release, I wanted to change the jar
location
so it would be in a similar directory structure to what I have for
the
Windows releases of hitimes
(“lib/hitimes/#{RUBY_VERSION.sub(/.\d$/,‘’)}/hitimes_ext.dll”).I wanted to put the jar in ‘lib/hitimes/java/hitimes.jar’ and then
require it
with ‘require “hitimes/java/hitimes”’ in the top level hitimes.rb.
This did
not work. The jar was never found, and I had to move it back to
‘lib/hitimes/hitimes.jar’.Is this working as designed?
-
ObjectAllocator
It seems that this is some boilerplate code that needs to go into
anything
that is registered with RubyModule#defineClassUnder(). Is this
strictly
required? Is there a default that can be used if you do not have
custom
allocation needs?
Thoughts? Questions? Comments?
enjoy,
-jeremy
[1]
[2]
http://github.com/jruby/jruby/blob/master/src/org/jruby/Ruby.java#L1421
[3]
http://github.com/jruby/jruby/blob/master/src/org/jruby/runtime/load/BasicLibraryService.java#L34
[4] http://markmail.org/message/2giww4tbzxxpnvl7
–
Jeremy H. [email protected]
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email