JRuby Serial Interview 3

Posted by Nick Sieger Thu, 18 Jan 2007 03:59:31 GMT

This is part 3 in our ongoing conversation tracking the development of JRuby.

Official Rails support in February? That’s not far away! What do you mean by “official”?

Thomas Enebo: Largely, we just want to spend some extra TLC on fixing up various Rails issues between now and February. Basically, get rid of the remaining known issues with running Rails from JRuby. I think beyond marshalling we are very close to saying that today. We also want to provide a better deployment picture for Rails by then. So we will need to spend some time on that as well (the community has been doing a great job spearheading this).

Software is never perfect, so we know that there will continue to be Rails issues after we say it is supported. By setting this goal, we should give ourselves some pressure to polish what we have and also get a larger number of people some incentive to kick the tires.

Ola Bini: That’s a question of interpretation. In my view, “official” is some kind of high number. 95% of all test cases in 1.1.6, maybe? But the more important part of it is that all the common use cases should work. You should be able to work through AWDwR and everything should work.

It’s ambitious, but we can do it. What’s needed soon is to decide what needs to be done with ActiveRecord-JDBC, and do that, since AR-JDBC is one of the larger points in our Rails support, and sometimes I feel that the support there is our weak link.

Charles Nutter: We could probably say we support Rails today, with a whole list of caveats. Rails runs right now, people are using JRuby on Rails today (in some cases for production apps!), and things largely will “just work”. There’s also a lot of community effort behind alternative deployment scenarios like within a WAR file or behind a fast HTTP server like Grizzly. Rails does run on JRuby today.

Our challenge before making a big official announcement about “Rails support” is to shrink that list of caveats down as small as possible. We want marshalling to work so sessions function correctly. We want AR-JDBC to be cleaned up a bit more, with more testing and even wider database support. We want any remaining core library issues resolved. We want those peripheral deployment projects to work perfectly. There’s a lot of work to get there, but it’s now simply an incremental process; Rails runs today, and will run better tomorrow.

What’s this about YARV instruction interoperability?

Readers: here’s an IRC recap for you:

[1:31pm] olabini: HAHA
[1:31pm] olabini: YEAH BABY.
[1:31pm] olabini: hehe.
[1:31pm] olabini: echo 'puts "Hello world"' > test1.rb
[1:33pm] olabini: ruby-yarv ~/src/yarv/tool/compile.rb -o test1.rbc test1.rb
[1:33pm] olabini: jruby -y test1.rbc #=> "Hello world"
[1:33pm] headius: hah, awesome 
[1:33pm] nicksieger: no way!

So this is awesome that you guys are able to track so closely with YARV’s progress, but why do it? Hedge your bets?

Ola Bini: First of all, it shows the maturity of the JRuby runtime that we can implement basic parts of the YARV VM this easily. Second, it can be very interesting for us to try out parts of how 1.9/2.0 will work out within the current JRuby system. Third, we don’t have a YARV compiler yet, but being able to run files compiled with YARV ensures that we stay on track for Ruby compatibility. Fourth: Yeah, hedging your bets is always a good idea. Diversity breeds evolution. I believe where on the right track with the current AOT and JIT compiler works, but there is always a good idea to implement these things in more than one way. And of course, it ‘s just fun!

The next step for this will be to get the loading to handle more things. At the moment, it only runs extremely simple scripts. But I’m planning on handling the more complex things soon too, adding support for labels and defining YARV methods and other such things. The very next step to handle is a compiled recursive fibonacci script. The YARVMachine already has most things needed for it, but the YARV emitted by the compiler contains some tricks that needs to be fixed.

Charles Nutter: I’ve been the primary person responsible for our various interpreter rewrites over the past year or two. Originally I modified it to be mostly “stackless”, using an Instruction object for each element in the AST and pushing down an external stack of previous instructions to maintain context. That seemed like a neat idea, and it certainly did move toward a stackless design (I actually demoed a recursive fib(100_000) at RubyConf 2005), but it was rather slow and complicated enough that only I could maintain it. So in October of 2006 I did another rewrite, basically simplifying the interpreter down to a “big switch statement” that could quickly traverse the AST without a lot of objects and stack manipulation. This new C-like interpreter engine was quite a bit faster, but unfortunately the tradeoff was that we were again burning Java stack frames when we had to dig deeper into the AST, and our maximum stack depth suffered.

I’ve still always wanted the stackless design back in JRuby, and started to think about alternate routes to get there. The most obvious was having our own bytecode engine. The most readily-available set of bytecodes for Ruby...was YARV’s.

Implementing a stack machine is pretty trivial. You need an operand stack, instructions for manipulating it, and instructions that consume values from it. Over the past year, YARV’s core set of bytecodes have started to solidify to the point that I figured implementing a YARV machine in JRuby would be a good idea. So I did a very simple initial implementation that just handled local variables, method calls, while loops, and so on, to see if it would be feasible. I got it as far as running an iterative fib, and the results were very promising: it was quite a bit faster than the current interpreter.

I ended up putting that down for a while to look at Java bytecode compilation, which has been coming along very nicely. Recently, Ola decided to pick up the YARV machine work, and made it double cool by loading real compiled YARV bytecodes into it. And if that wasn’t good enough, the original partial machine I’d implemented was able to run them without modification!

We’re looking toward the future with this work. We know that YARV is now “The” Ruby VM, and that eventually people will start to run compiled Ruby bytecodes. We also know that JRuby will never be able to fully escape interpreted-mode execution. I believe both goals are answered by having a fast Ruby bytecode machine that works in concert with our Ruby-to-Java compilers. And that’s the current roadmap for JRuby’s execution model.

Thomas Enebo: Personally, I would like to see us move from walking our current tree to walking a set of instructions. I think dynamic optimizations (as well as static) will be much easier using instructions and we can also create a simpler AST/parser (the traditional AST in Ruby does quite a bit of static optimization which I think makes the grammar a little tougher to wrap your head around).

Anything YARV-related sort of hits my sweet spot since it may nudge us in this direction. JRuby will probably always mix execution between compiled and interpreted code. I think interpretation will be easier to support at an instruction level. It will also give us a good opportunity to flatten the Java stack more. YARV is a good place to start. It may be right solution for us too. Who knows? I think experimentation is the name of the game for this stuff. So I love to see it happening :)

Tags , ,  | no comments | no trackbacks

Self-cloning JRuby and RubyGems in a Jar

Posted by Nick Sieger Fri, 12 Jan 2007 04:27:07 GMT

As part of some work I’m doing to make JRuby more portable and easier to run standalone without all the $JRUBY_HOME launcher scripts, it’s now easier than ever to get up and running with JRuby, or to launch in your build scripts or IDE in a platform-neutral way. (Note: as of this writing, this feature is in 0.9.3 jruby-complete snapshots older than 2007/01/11 only.)

Here, give it a try:

IRB in a jar

$ curl -o jruby-complete.jar http://snapshots.repository.codehaus.org/org/jruby/jruby-complete/0.9.3-SNAPSHOT/jruby-complete-0.9.3-20070112.032908-4.jar
$ java -jar jruby-complete.jar --command irb
irb(main):001:0>

RubyGems in a jar

RubyGems needs a place to unpack and run gems, so JRuby currently will hide all that away from you in ~/.jruby. (Also, unfortunately we exceed Java’s default memory size when downloading the RubyGems index file, so you’ll have to add the -Xmx256m argument for now to avoid an out of memory condition.)

$ java -Xmx256m -jar jruby-complete.jar --command gem install tattle -y --no-rdoc --no-ri
creating /Users/nicksieger/.jruby/bin/gem
... more files extracted ...
copying /Users/nicksieger/jruby-complete.jar to /Users/nicksieger/.jruby/lib
Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed tattle-1.0.1
Successfully installed hoe-1.1.7
Successfully installed rubyforge-0.4.0
Successfully installed rake-0.7.1

You can still have JRuby unpack to a shared directory if you like, and use the regular shell scripts for launching JRuby. In this case, JRuby is actually replicating itself into the directory you choose. Simply add the bin subdirectory to your $PATH, and continue to use JRuby just as you would a regular Ruby installation.

$ sudo java -jar jruby-complete.jar --command extract /opt/local/jruby
Password:
creating /opt/local/jruby/bin/gem
... more files extracted ...
copying /Users/nicksieger/jruby-complete.jar to /opt/local/jruby/lib
$ PATH=/opt/local/jruby/bin:$PATH
$ which gem
/opt/local/jruby/bin/gem
$ jirb
irb(main):001:0>

Tattle-tale

The --command argument is not limited to just gem and irb. Once you’ve installed any gem that has an accompanying executable script, you can simply pass that argument as the --command:

$ java -jar jruby-complete.jar --command tattle report
ruby_install_name, jruby
LIBRUBY, jruby
target, java
arch, java
host_vendor, Apple Computer, Inc.
key, b1bd5eaf4254d9874ca297995b906be6f4975d395dd0136432f859c62a33cc8c
host_os, Mac OS X
ruby_version, 1.8.5
build, java
target_cpu, i386
prefix, /Users/nicksieger/.jruby
report_time, Thu Jan 11 22:21:57 CST 2007
rubygems_version, 0.9.0
host_cpu, i386
LIBRUBY_SO, jruby
SHELL, /bin/sh
$ java -jar jruby-complete.jar --command tattle
Posting information to Tattle server.  Thanks!

And lo and behold, there’s a ruby_install_name of java at the new Gem Tattle homepage!

Tags , ,  | 2 comments | no trackbacks

JRuby Serial Interview 2

Posted by Nick Sieger Thu, 11 Jan 2007 04:03:52 GMT

This is part 2 in our ongoing conversation tracking the development of JRuby.

It’s been exciting to see all the discussion between the JRuby developers and Rubinius developers, especially in #rubinius. What benefits do you see coming from this kind of cooperation?

Charles Nutter: Evan and I have been talking since this summer, actually, when he was working on early versions of Rubinius. We both have gone through many of the same growing pains dealing with Ruby’s quirkier features and evaluating interpreter/VM design options. I don’t know how Evan feels about it, but I was very glad to find someone else who was interested in such things.

Now that Rubinius is in the public eye and has some real momentum, there’s more sharing going on. We’ve been talking about those same design options, weighing them together and coming up with new choices we can both implement. Others on the Rubinius team have forwarded the idea of reusing portions of the Rubinius source in JRuby.

It’s also become apparent that we’re trying to solve very similar problems from different directions. In JRuby’s case, we already have a fully-functional Ruby interpreter, functional enough to run apps as complicated as Rails. Our challenge is to keep JRuby running well and evolve a working interpreter toward a more future proof, performant, and maintainable design. Rubinius is really just starting out, only to the point of running a small portion of the Ruby corpus, but the design is easier to follow and simpler to evolve. Their challenge is to keep the design simple while expanding compatibility and improving speed. JRuby is mostly Java with some Ruby code, though we’d like to make it more Ruby code in the future. Rubinius is obviously mostly Ruby code with some C, but they’re interested in being able to migrate it to other underlying languages. We’re both interested in a Java-based Rubinius.

I think it’s been very positive for everyone involved to have this level of cooperation, and it’s helped us all understand Ruby better.

Ola Bini: Well, the exchange with Rubinius is obviously very valuable. The more people working on implementations and sharing information, the better for all the implementations, of course. I also see Rubinius as something very intriguing, and it would be very interesting to see how much we could port to JRuby.

Thomas Enebo: I have not personally been in contact with Rubinius developers (Charles has though), but I can say more generally that many implementations will necessitate some level of cooperation. As we discover differences between implementations, we need dialogue to help understand why those differences exist. It is possible this dialogue will end up identifying poorly-identified cross-platform issues or general mis-features.

At an implementation level it will yield suggestions across the fence for how to do things differently. A thread in ruby-core a month or so ago had some exchanges on how MRI could be optimized. Charles and I chimed in about some of those ideas because we had considered and implemented some of them in JRuby. I think as time goes on, this exchange of ideas will increase.

The biggest news in Ruby land recently is probably the announcement of a fully merged YARV. What affect does this have on JRuby?

Thomas Enebo: This seems like great news for Ruby, but I am not sure it has much affect currently on JRuby. We are still focused on 1.8.x support. It is getting easier for us to change language semantics now and when 1.9/2 starts getting closer to release I feel comfortable that we can spin a Ruby 2 branch pretty quickly.

From a personal standpoint, it is great to see Ruby hit this next milestone. I think the perception of progress is pretty important and merging YARV will give Ruby 2 development a nice perceptual boost. Also this will mean many more people pounding on YARV, which will help run it through its paces better.

Ola Bini: YARV is important news. Very much so. But at the moment the effects will not be that noticeable. Right now we’re still working hard to get 1.8-compatibility complete. But, Charles have begun work on a YARVMachine that runs some basic scripts (including the famous iterative fib bench). I’ve started looking on this the last few days, and have some ideas. My first priority will probably be to implement a reader for YARV bytecode. This will make it easier to test our machine, since we can compile with YARV and then run the compiled files with JRuby. Alongside with that I am going to start tinkering on a new backend to Charles current compiler, so it will emit YARV bytecode instead. I’m not sure exactly when this is going to happen, though, but we try to stay on top of YARV.

Charles Nutter: The merging of YARV (no longer “yet another” Ruby VM but instead “the” Ruby VM) is a very big event for the Ruby world. Koichi has worked long and hard on it, and I’m very glad to see it’s now officially part of Ruby core. I had some time to talk with Koichi and Matz about implementation challenges at RubyConf 2006, and we came to agreement on a number of items, most prominently that critical= needs to go away. Again, more cross-project sharing.

We’re watching the newly-reset 2.0 design process closely, since we know it will eventually affect JRuby’s future. In the interim, however, we’re trying to solve at the 1.8 level many issues YARV is designed to solve in 1.9 and 2.0. So many of the design choices made by Koichi and Matz for 1.9 play directly into how we tackle those same decisions in JRuby.

I think in general the merging of YARV shows that Ruby is moving forward and evolving on all fronts.

Tags , ,  | no comments | no trackbacks

JRuby Serial Interview 1

Posted by Nick Sieger Sat, 06 Jan 2007 18:21:56 GMT

In cooperation with Pat Eyler, we present this conversation as a parallel thread to his recent string of Rubinius “serial” (ongoing) interviews. We aim to bring short, frequent, looks at the two alternate Ruby implementations’ developments, and have the conversations intersect from time to time.

A lot has happened since the last JRuby interview with Pat -- Java was open-sourced, you’ve been to Javapolis, pushed out another release, and a slew of new contributions have poured in. How have your plans and goals for JRuby changed (if at all) since then?

Charles Nutter: For me the biggest items are the following, in order:

  • We need to announce full Rails support as soon as possible
  • We need to resolve the remaining runtime performance bottlenecks
  • We need to keep working on the compiler

All these of these have been the hot topics on the JRuby mailing lists lately. I’ve launched into a newly-refactored compiler that’s showing great performance gains. Many of us have discussed how to speed method dispatch and finally push interpreted-mode performance up to or beyond Ruby’s speed. And we’ve started to test and track Rails 1.2, while continuing to resolve remaining issues running Rails 1.1.6.

Now there’s a lot of work to do, but we’ve seen steady, continuous growth among JRuby contributors. Just in the past week we’ve had a number of new names on the mailing lists, we’ve added a new committer (Nick Sieger), and we’ve seen patches pouring in for more and more bugs. Things are going great.

Ola Bini: I was very happy about the last release. It fulfilled the goals I had set for it, which was to get OpenSSL and complete Java-backed YAML into it. Besides that, we also got seriously many bugs fixed in just a few months. Since I have a tendency to plan mostly for the next release, what I want to see in 0.9.3 is support for Sandbox, all those strange block scope bugs that surface in Rails gone, our load times improved (by refactoring the LoadService code), and finalizers finally working.

The Sandbox stuff is mostly done, and I also hacked a Generator that is so much faster than MRI that we come out faster, all in all, in a test case with generators.

Thomas Enebo: Largely, I think three goals are important: 1. Support Rails well enough where people do not need to ask us if it is ready for prime time; 2. Round out java integration support to do what most people expect it to do; 3. Make the runtime ‘fast’ enough. These three goals existed before JavaPolis, so I do not feel much has changed goal-wise.

How much closer have you come to achieving them? What is your perception of delta in growth in the JRuby community and acceptance of JRuby as a viable alternative to MRI?

Ola Bini: What I like about the last few months - since RubyConf - is that it really feels like JRuby and the other implementations will actually be viable alternatives and that there is something really useful going on. With Java open source, one of the major roadblocks for adoption in certain circumstances has all but disappeared. The contributions we have gotten is mostly visible in how many bug reports we get. That is really great, because that makes it that much easier to fix things. So I would say that the future looks brighter than ever.

Thomas Enebo: If you look at the amount of time between releases then you get a better idea of how much development has sped up. The time between 0.9.1 and 0.9.2 was a little under two months. This is the shortest development cycle to date and it seemed like we got so much done. Sun hiring us obviously had something to do with this, but also our community involvement is at an all time high. We get so many emails, bug reports, patches, tests, ideas, and enthusiasm coming in from the JRuby community. The community impact on JRuby is huge.

I think acceptance of JRuby as a Ruby interpreter is certain. Compatibility keeps improving, we keep getting faster, and we also offer integration with Java. If you look at the trend of how often JRuby is mentioned in blogs or the volume of email on our mailing lists, then I think you can get a picture as to whether people are willing to accept JRuby as a Ruby runtime.

Charles Nutter: Rails is probably the most visible measure of success for JRuby right now, and I’d say we’re able to run something like 75% of Rails 1.1.6 code and test cases. We’ve been using Rails’ own test suite as a yardstick for compatibility, with the idea that if we can run all the Rails test cases, we can say we support it. And that 75% is better than it might sound, since it’s the most heavily-used functions.

Now this might change, but we’re really hoping to claim full Rails support some time in February. We’re not sure if that will mean 90% of 1.1.6 test cases or 100% of 1.2 test cases, but we’re weighing options now. Finally having Rails support behind us will let us change focus toward outward to other applications and inward to improving JRuby internals and performance.

We’re also seeing daily gains in the performance area, with more to come. Since this past summer, we’ve managed to eliminate all the major performance bottlenecks seen when profiling. The only remaining area is the interpreter itself. My work on the compiler will eventually resolve that, and our work to improve the performance of method lookup and dispatch will help both interpreted and compiled execution. Everything’s moving very fast now. It’s going to be a great Spring for JRuby.

Probably the most intriguing change of the past month is the support from Aslak Hellesøy, creator of RSpec. Aslak has helped us get JRuby running RSpec extremely well, and we’re looking forward to the RSpec team using JRuby as part of their regression testing. I hope more Ruby app developers will take this same path, since their users are going be running JRuby more and more. Compatibility and regression testing for those apps should include JRuby just like it includes different Ruby versions and host operating systems.

Tags , ,  | no comments | no trackbacks

Continuous Integration Goodness(TM) for Your Ruby Project

Posted by Nick Sieger Sat, 06 Jan 2007 15:42:00 GMT

As much as we’d like to think we live in a Ruby-glasses-colored world, the fact is there are plenty of neat toys out there that don’t know a bit about us. One that I’m currently enamoured with is Bamboo, Atlassian’s new continuous integration server. But, most commercial CI products are aiming for a wider market, and that means Java and Ant. Ant and JUnit predate Rake and Test::Unit by a few years, so I’m afraid they beat us to the punch, so that now the JUnit Ant task’s XML format is pretty much the first consideration for a continuous integration server to understand in order to display a test report for a build.

Where does that leave us Rubyists who want to play along with the bigs? Right here!. With support for not just RSpec, but Test::Unit too.

Right now, it’s packaged as a Rails plugin, because I’m lazy and I don’t need anything else right now. If you’re interested in a gem, please leave a comment. To install into your Rails app, the usual:

./script/plugin install http://svn.caldersphere.net/svn/main/ci_reporter

That’s it! Now all you have to do is have your CI server invoke an extra target before the main target that runs your tests.

For RSpec,

rake ci:setup_rspec spec

will leave one XML file per context in the spec/reports directory (creating it if it doesn’t exist).

For Test::Unit,

rake ci:setup_testunit test

will leave one XML file per test case class in the test/reports directory.

Most CI servers have configuration telling them where to look for test reports. Simply plug in one of these directories, and you’re set. Now sit back and watch your test or spec failures get tracked in your automated builds.

test results

Tags , , , ,  | 11 comments | no trackbacks

Customizing RSpec

Posted by Nick Sieger Tue, 02 Jan 2007 05:32:00 GMT

Update/Disclaimer: I refer to parts of RSpec that are not blessed as an extension API. Redefining before_context_eval and using the @context_eval_module variable directly may change in the future. I’ll keep this article updated to coincide with the changes. For now, these techniques should work fine with RSpec versions up to 0.7.5.

RSpec seems to be getting more attention lately as a viable, nay, preferred, alternative to Test::Unit. It’s possible that it’s just my personal feed-reader-echo-chamber, but consider this: Rubinius has started using RSpec alongside Test::Unit as an another way to test the alternate Ruby implementation. They’re even in the midst of building some snazzy extensions to allow the same specs to be run under a Ruby implementation of your choice. (Perhaps this will point the way to a new round of executable specs to accompany the fledgling community spec? Let’s wait and see how they do and leave that topic for another day.)

But extending and customizing RSpec to add a DSL on top of RSpec’s context/specify framework doesn’t have to be the realm of experts. Here are some templates for how you can DRY up your specs by adding your own helper methods in such a way that they will be available to all your specs. But first, a little background.

Spec Helper

Most usages of RSpec that I’ve seen in the wild use a “spec helper” (spec_helper.rb). This file, following the pattern of Rails’ test_helper.rb, minimally contains require statements to pull in the RSpec code and any supporting code for running specs. By requiring the spec helper via a path relative to your spec (usually with require File.dirname(__FILE__) + '/spec_helper' or similar), it also allows you the convenience of running your specs one at a time from anywhere (say, by launching from your editor) or with rake or spec. This file is where your shared helper methods will go, and where they’ll get registered to be pulled into the contexts.

What Context in context?

context "A new stack" do
  # <== What is the value of "self" here?
  specify "should be empty" do
  end
end

How do those contexts work anyway? The context method that defines a context in which specs can be defined and run takes a block to define the individual specs, but what can really go in that block?

It turns out that RSpec jumps through metaprogramming hoops (using class_eval) to make the block behave like a class definition. This means you can do things like put method definitions inside your context:

context "A new stack" do
  def a_new_stack
    Stack.new
  end
  specify "should be empty" do
    a_new_stack.should_be_empty
  end
end

Which is nice, but the reason we’re here is to hide that away in spec_helper.rb. So, to get back to the point of the comment in the first example above, the self inside the context block is an anonymous Module object. It’s constructed in the initialize method of a Context (condensed from spec/runner/context.rb in the RSpec codebase):

class Spec::Runner::Context
  def initialize(name, &context_block)
    @name = name

    @context_eval_module = Module.new
    @context_eval_module.extend ContextEval::ModuleMethods
    @context_eval_module.include ContextEval::InstanceMethods
    before_context_eval
    @context_eval_module.class_eval(&context_block)
  end

  def before_context_eval
  end
end

(Take note of that empty before_context_eval method and the fact that it’s invoked during context initialization; that’s where we can plug in our custom extensions.)

The object held by the @context_eval_module instance variable is being augmented in two ways: extension and inclusion. The object is extended with the ContextEval::ModuleMethods module; these methods are being added to the object’s singleton class. This has the effect of making these methods visible within the context block, functioning similar to “class” methods.

The object also has the ContextEval::InstanceMethods module included. This has the effect of adding these as instance methods, making them visible from within specify blocks, which are made to behave like instance methods on the same object.

Putting it together

Technique Visibility Use
@context_eval_module.extendContext blockCustom setup, shared state declaration
@context_eval_module.includeSpecify blockShared actions/functions, stub/expectation modification, encapsulate instance variables

Adding specialized setup methods

spec_helper.rb snippet:

module SharedSetupMethods
  def setup_new_stack
    setup do
      @stack = Stack.new
    end
  end
end

class Spec::Runner::Context
  def before_context_eval
    @context_eval_module.extend SharedSetupMethods
  end
end

Example spec:

context "A new stack" do
  setup_new_stack

  specify "should be empty" do
    @stack.should_be_empty
  end
end  

Adding shared accessors

spec_helper.rb snippet:

module StackMethods
  attr_accessor :stack

  def push_an_object
    stack << mock("some object")
  end
end

class Spec::Runner::Context
  def before_context_eval
    @context_eval_module.include StackMethods
  end
end

Example spec:

context "A stack with an object pushed" do
  setup do
    @stack = Stack.new
  end

  specify "should not be empty" do
    stack.should_be_empty
    push_an_object
    stack.should_not_be_empty
  end
end  

The examples are simple, but hopefully illustrate the techniques. For an example of some code that’s actually useful, check out my sample RSpec Selenium RC integration project, in particular the spec helper and the example spec. (More on this in the future if it proves useful, but for now if you check it out and run rake on it, it should launch Selenium RC and run the example spec in a Firefox browser.)

By mixing and matching these techniques, you can layer a mini-DSL on top of RSpec and achieve DRY-er and even more readable and intention-revealing specs. Let me know if you’re able to find uses for these tips!

Tags , ,  | 2 comments | no trackbacks

Ruby in the Twin Cities in 2006

Posted by Nick Sieger Fri, 22 Dec 2006 05:17:30 GMT

Mirroring the wider global trend, Ruby has seen a big uptick of growth in my hometown of Minneapolis over the past year.

A little over one year ago, the very first meeting of the Ruby Users of Minnesota (affectionately known as “Java Programmers Anonymous”) was held. I was not in attendance (until the second meeting in late December), but by the January/February timeframe we had a surprisingly good showing of 15-20 people. We’ve sustained or exceeded that number since, packing our group in the back of a Dunn Brothers Coffee on Loring Park the last Tuesday of every month.

More interesting a metric is how the number of people doing Ruby full-time has progressed. Somewhere around spring-time, guys were starting to itch for work. By summer time, Slantwise Design, formerly a mostly-web-design shop had been hired to do its first Rails contract, for what would turn out to be Sayswap. Slantwise is a Rails-exclusive shop now.

Rails Day had an entry from Bruno Bornsztein and Ben Moore, Sneakology. This prolific duo would go on to contract on YFly, and play around with a local one-page news aggregator at Acu.mn. Almost two months ago, they went live with their new startup, Curbly, a social-networking DIY design community.

We’re also happy to lay claim to RUM regulars Charles Oliver Nutter and Thomas Enebo, the two lead JRuby developers, who tirelessly give monthly updates on the lightning progress that JRuby is undergoing.

All in all, there are at least 20 full-time Rubyists in the Twin Cities, and the number is going up week by week.

Yours truly has been doing Ruby mostly-full-time for my current employer Digital River, where I’m proud to have sneaked Ruby into the system. There are at least two other programmers writing Ruby code at DR, and hopefully we’ll be hiring more in 2007. If you’re looking for work or interested in what we’re doing with Ruby, drop me a line!

So what happened this year in other user groups around the world?

Tags , , ,  | no comments | no trackbacks

Ruby and XML not-so-simple?

Posted by Nick Sieger Thu, 02 Nov 2006 02:12:00 GMT

Update: Koz already fixed the issue in trunk, and the changes are also going into the 1.2 release as well. Thanks!

Man, I think I’ve been reading too much Sam Ruby lately (ok, that was a year ago, but not much has changed). You have to admit, though, that XML handling in Ruby is one of those things that just doesn’t feel quite right. REXML is pretty much the standard API for Ruby, yet it suffers from two showstoppers in my opinion:

  • In Ruby 1.8.4 it still has the glaring hole Sam mentioned last year with well-formedness. (No exception raised below!)

    irb(main):001:0> require 'rexml/document'
    => true
    irb(main):002:0> d = REXML::Document.new '<div>at&t'
    => <UNDEFINED> ... </>
    irb(main):003:0> d.root
    => <div> ... </>
    irb(main):004:0> d.root.text
    => "at&t"
    
  • The REXML::Text#to_s method violates the principle of least surprise. In just about every other XML parser written, when you ask a text node for its contents, it returns you the value with entities resolved. Not so Text#to_s. You have to call Text#value instead. Unfortunately, this would be difficult to reverse in future versions of REXML without breaking existing apps.

    irb(main):001:0> require 'rexml/document'
    => true
    irb(main):002:0> t = REXML::Text.new('at&t')
    => "at&t"
    irb(main):003:0> t.to_s
    => "at&amp;t"
    irb(main):004:0> t.value
    => "at&t"
    

This second problem manifests itself in subtle ways. If you’re calling Element#text (which is probably the most common way), you’re fine, because it implicitly does self.texts.first.value under the hood. But if you want to make sure you’re grabbing all the text content, you might be inclined to write element.texts.join('') to concatenate them together. But this method bypasses the value method and instead uses to_s, leaving you with unresolved entities.

It turns out this problem is exhibited in the version of XmlSimple now included with Edge Rails as of rev 4453. So if you’re living on the edge using the newly minted ActiveResource fetching XML from remote resources like a champion, you just got benched as soon as you tried to fetch XML that had normalized entities inside.

XmlSimple version 1.0.9 has a partial fix for this issue, but I submitted another patch to Maik Schmidt for review that he subsequently released as 1.0.10. I’ve attached the 1.0.10 version to ticket 6532 in hopes that it will be patched in Rails soon.

Posted in ,  | Tags ,  | no comments | no trackbacks

Visualization of Ruby's Grammar

Posted by Nick Sieger Fri, 27 Oct 2006 16:48:00 GMT

As part of the momentum surrounding the Ruby implementer’s summit, I have decided to take on a pet project to understand Ruby’s grammar better, with the goal of contributing to an implementation-independent specification of the grammar. Matz mentioned during his keynote how parse.y was one of the uglier parts of Ruby, but just how ugly?

Well, judge for yourself. Below is a grammar dependency graph generated using ANTLRWorks and GraphViz. The steps I took are as follows. I took parse.y, stripped all C definitions, code and actions from it to give a bare YACC definition. Next, I did the equivalent of gsub(/[kt]([A-Z]+)/, '1') (since ANTLR’s convention is to have lexer tokens named starting with a capital letter). I then used the Bison-to-ANTLR converter to generate an ANTLR 2.x grammar, which I hand-modified to produce a v3 grammar. Opening the resulting grammar in ANTLRWorks allows you to generate a DOT file from which GraphViz can then generate a jpeg image. I’ve also included visualizations of the Java 1.5 and Javascript (ECMAScript) grammars for comparison.

I haven’t even begun to absorb all the meanings from this picture, but one stark difference between Ruby and the other two is the node in the middle of the picture with a high concentration of outgoing edges. That node is called primary in the grammar definition, and it is probably one of the reasons that Ruby syntax is so flexible and forgiving. A primary node’s direct children apparently represent a large portion of the syntax, and explain why in Ruby a single statement can either be a literal, a method invocation (or series of them), a standalone expression (such as a < b), all the way up to larger syntactic groupings such as if ... else ... end and begin ... rescue ... end, among many others.

Ruby

Ruby 1.8.4 grammar dependency graph

Java 1.5

Generated from Java 1.5 grammar on antlr.org

Java 1.5 grammar dependency graph

Javascript

Generated from ECMAScript grammar on antlr.org

ECMAScript (Javascript) grammar dependency graph

Posted in  | Tags  | 34 comments | no trackbacks

Caught redHanded

Posted by Nick Sieger Sat, 21 Oct 2006 03:22:00 GMT

Ok, ok, so I’ve been caught redHanded. Yeah I know, Tufte hates bullets. You might feel a strange sensation if you stare at my transcriptions of today too long. If anyone is offended or would like to claim I’m a card-carrying NRA whipping boy, let me know and I’ll try to tone it down a bit. Thanks for the mirror of truth, _why!

Tags  | 1 comment | no trackbacks

Older posts: 1 2 3 4 5