JRuby
java interfaces
JRuby classes can mixin Java interfaces as modules in order to implement them.
class SomeFlexibleClass
include java.lang.Runnable
include java.lang.Comparable
end
JRuby does a wonderful thing with Ruby’s blocks, where a block can be converted to the appropriate Java interface. It works by converting the block to a Proc, and then decorating it with a proxy object that runs the block for any method called on the interface. Runnable is the prime example here. You should try this yourself, also see using callbacks hype library examples for more sophisticated stuff.
button = javax.swing.JButton.new "Press me!"
button.add_action_listener { |event| event.source.text = "I done been pressed." }
Read more about java interface etc. Otherwise see wiki
java reflection
In vanilla processing, you can create libraries in java that can access the sketch pre
, draw
, post
, mouseEvent
and keyEvent
methods by java reflection, but you must register
these methods with the PApplet
. We can also register custom methods (but sadly only those without parameters, which is why we found another way of dealing with selectInput
see chooser, movieEvent
see video_event).
Here we show you how to registerMethods
in a ruby class by java reflection in JRuby (requires the !become_java
method).
# A simple demonstration of vanilla processing # 'reflection' methods
# in JRubyArt see register_send.rb for the guts...
require_relative 'register_send'
def settings
size 300, 200
end
def setup
sketch_title 'Reflection Voodoo'
RegisterSend.new self
no_loop
end
def draw
fill(0, 0, 200)
ellipse(170, 115, 70, 100)
end
Here is the class that does the reflection (it needs to become java so that self gets recognized as a java object)
require 'jruby/core_ext' # required to add become_java! method
# This class demonstrates how to use 'reflection' methods in ruby-processing
# NB: the class must become a java object to get registered. This is an
# advanced feature in vanilla processing, mainly used by libraries.
class RegisterSend
attr_reader :parent
def initialize(parent)
@parent = parent
parent.java_send :registerMethod, [java.lang.String, java.lang.Object], :draw, self
parent.java_send :registerMethod, [java.lang.String, java.lang.Object], :pre, self
end
def pre
puts 'before draw'
parent.background(100)
end
def draw
puts 'at begin draw...'
parent.fill(200, 100)
parent.ellipse(150, 100, 200, 60)
end
# putting become_java! here works OK
become_java!
end
Note how the transparent ellipse is placed on top of the solid ellipse, so the reflection element must get drawn after the original sketch element.
Java Extensions for JRuby
JRuby is a 100% Java implementation of the Ruby programming language. It is Ruby for the JVM. So it is quite possible to write your own ruby code in java, you might do this to better integrate jruby with java or to write your own ruby classes (modules etc) in java see Method Signatures and Annotations in JRuby extensions and jruby-examples.
Accessing java methods with overloaded signatures
Sometimes you may find that a java method is not-available from ruby, and this can be because the java signature is overloaded. The preferred way to access such methods is to use java_alias. Using java_alias to create signature-specific aliases of a given method, avoids the lookup overhead and allows invokedynamic to optimize the calls. See example:-
# Here we re-open the SinOsc class to deal with java signatures
class SinOsc
java_alias :just_play, :play
java_alias :freq_float, :freq, [Java::float]
java_alias :amp_float, :amp, [Java::float]
end
See full code listing here