Jan
30
2007
Julian Doherty
swiby is a proof of concept framework inspired by F3. Both use a hierarchical block format for defining Java/Swing visual elements. eg:
Frame {
title "Hello World F3"
width 200
content {
Label {
text bind(model, :saying)
}
}
visible true
}
I was looking through the documentation, and got curious as to how the class level block declaration is actually implemented in swiby. After a bit of digging around, it is relatively straight forward.
There is some code in swiby that looks kinda like this:
def component_factory(class_name)
eval %{
def #{class_name}(&block)
x = #{class_name}.new
x.instance_eval(&block)
x
end
}
end
I’ve removed the error handling and some extra functionality, but the basic idea is the same. component_factory is called for each class that is required to be instantiated as a declared block. Here’s an example:
class Foo
end
class Bar
end
component_factory :Foo
component_factory :Bar
my_foo = Foo {
@my_bar = Bar {
@baz = 'baz'
}
}
puts my_foo.inspect
Which outputs:
#<Foo:0x60544 @my_bar=#<Bar:0x604e0 @baz="baz">>
A Foo instance has been created containing a Bar instance, with a variable of baz. This sort of syntax could be useful for DSL implemented in Ruby.
One limitation I ran into, is that calling attr_accessor methods don’t get recognized (they just get defined as local variables that go out of scope at the end of the block) - but that may just be a limitation of useing instance_eval to set the newly created object as the object in scope as self.
no comments | tags: F3, swiby | posted in ruby
Jan
25
2007
Julian Doherty
As part of a project to write some nice Ruby APIs for creating Swing GUIs, I’ve been a little frustrated with the exceptions from JRuby in the Java code that calls it - particularly getting stack traces, and error messages.
Say you’ve got some code like this:
try {
new ScriptEngineManager().
getEngineByName("jruby").
eval("raise 'foo is too bar'");
} catch (Exception e) {
e.printStackTrace();
}
You’ll get output that looks something like:
javax.script.ScriptException: org.jruby.exceptions.RaiseException
at com.sun.script.jruby.JRubyScriptEngine.evalNode(JRubyScriptEngine.java:376)
at com.sun.script.jruby.JRubyScriptEngine.eval(JRubyScriptEngine.java:138)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:245)
at Borked.main(Borked.java:9)
Caused by: org.jruby.exceptions.RaiseException
Not very helpful. How are you supposed to know what went wrong where?
After a bit of poking round with the debugger, it turns out there is more information in the exception you get back. You just have to work to get it. The following code will grab the Ruby exception message and stacktrace and spit it back out in the same style as native Java exceptions are output.
try {
new ScriptEngineManager().
getEngineByName("jruby").
eval("raise 'foo is too bar'");
} catch (Exception e) {
RaiseException re = (RaiseException)e.getCause();
System.out.println(re.getException().getMetaClass() + ":" + re.getException().toString());
RubyArray rubyStackTrace = (RubyArray) re.getException().backtrace();
for(Object stackLine : rubyStackTrace) {
System.out.println("\tat " + stackLine);
}
}
Here’s the output from some code I’ve been working on
ArgumentError:unknown key:foo
at /development/wring/classes/wrung_test.rb:17:in `each'
at /development/wring/classes/wrung.rb:43:in `populate_defaults'
at /development/wring/classes/wrung_test.rb:17:in `add_comp'
at /development/wring/classes/wrung_test.rb:17
at :0:in `require'
at :0
Which is pretty much exactly what a Java stack trace would look like - except its for the Ruby code running inside JRuby called by Java.
no comments | tags: java | posted in java, jruby