Archive for the ‘Ruby’ Category

More JRuby Play: JFreeChart

Thursday, April 12th, 2007

I’ve been messing around at work trying to make some automated scheduling charts (basically Gantt-like) in Ruby. I’ve implemented it a couple of times using SVG::Graph, which is close to what I need, but I end up having to rewrite a lot of methods whenever I really start using it. It occurred to me today that I might be able to co-opt a sexy Java library to do my dirty work. JFreeChart to the rescue!

As before, I’m generally amazed at how little work goes into integrating Java and JRuby these days. It’s a testament to the JRuby team and to the wealth of well-written, well-documented Java libraries out there.

Here’s some toy code that makes a simple Gantt chart and saves it as a PNG to a file:

# have jfreechart.jar in your classpath, obviously, as well as jcommon.jar
# and use a recent jruby
require 'java'
module Gantt
  class Simple
    include_class 'org.jfree.chart.ChartFactory'
    include_class 'org.jfree.chart.ChartUtilities'
    include_class 'org.jfree.chart.JFreeChart'
    include_class 'org.jfree.data.gantt.Task'
    include_class 'org.jfree.data.gantt.TaskSeries'
    include_class 'org.jfree.data.gantt.TaskSeriesCollection'
    include_class 'org.jfree.data.time.SimpleTimePeriod'
    include_class 'java.lang.System'
    include_class 'java.io.File'

    MILLIS_IN_A_DAY = 86400000

    def initialize(title="Chunky Bacon", width=700, height=400, data=[])
      @width = width
      @height = height
      @title = title
      dataset = create_sample_data() if data.empty?
      @chart = create_chart(dataset)
    end

    def render_to_file(filename, format="png")
      javafile = java.io.File.new(filename)
      ChartUtilities.saveChartAsPNG(javafile, @chart, @width, @height)
    end

    private
    def create_sample_data
      # dates as milliseconds seems the easiet
      now = System.currentTimeMillis
      tomorrow = now + (MILLIS_IN_A_DAY * 1)
      day_after_tomorrow = now + (MILLIS_IN_A_DAY * 2)
      week_from_today = now + (MILLIS_IN_A_DAY * 7)

      s1 = TaskSeries.new("JRuby")
      s1.add(Task.new("Download JRuby",
                      SimpleTimePeriod.new(now, tomorrow)))
      s1.add(Task.new("Write Code",
                      SimpleTimePeriod.new(tomorrow, day_after_tomorrow)))
      s1.add(Task.new("Setup CLASSPATH",
                      SimpleTimePeriod.new(day_after_tomorrow, week_from_today)))

      s2 = TaskSeries.new("Java")
      s2.add(Task.new("Read Comics",
                      SimpleTimePeriod.new(now, tomorrow)))
      s2.add(Task.new("Write Code",
                      SimpleTimePeriod.new(tomorrow, day_after_tomorrow)))
      s2.add(Task.new("Setup CLASSPATH",
                      SimpleTimePeriod.new(day_after_tomorrow, week_from_today)))

      collection = TaskSeriesCollection.new
      collection.add(s1)
      collection.add(s2)
      return collection
    end

    def create_chart(dataset)
      opts = {
              :title => @title,
              :domain_axis_label => "Task",
              :range_axis_label => "Date",
              :data => dataset,
              :include_legend => true,
              :tooltips => false,
              :urls => false
             }
      chart = ChartFactory.createGanttChart(
                                              opts[:title],
                                              opts[:domain_axis_label],
                                              opts[:range_axis_label],
                                              opts[:data],
                                              opts[:include_legend],
                                              opts[:tooltips],
                                              opts[:urls]
                                            )
      return chart
    end

  end # class Simple
end # module Gantt

chart = Gantt::Simple.new("Gantt Chart Demo")
puts "Rendering chart"
chart.render_to_file("simplegantt.png")

Example PNG:

A Simple Gantt Chart Example

Code: http://kfahlgren.com/code/simple_gantt.jrb

Hiding Complexity

Saturday, April 7th, 2007

I just started reading the second edition of The Ruby Way by Hal Fulton and came across this gem:

We can’t avoid complexity, but we can push it around. We can bury it out of sight. This is the old “black box” principle at work; a black box performs a complex task, but it possesses simplicity on the outside.

This idea of managing complexity is one of the classic commandments of programming, of course, and a core theme of Structure and Interpretation of Computer Programs, but this was a nice restatement.

It looks like this edition (in all it’s 800+ page glory) will be quite a treat.

“Literate” Programming, Technical Writing

Friday, March 16th, 2007

There’s been some recent discussion on ruby-talk about “literate” programming after the new O’Reilly title Beautiful Code was announced (Matz has written an essay for it). Matz’s response made me listen to all-things-Knuth, so I was pleased to read Philip Wadler’s post today on Three ways to improve your writing, which includes a PDF link to Knuth (and others) lecturing on writing and “literate” programming. I’ve just started reading it, but have already found two laugh-worthy gems:

13. Many readers will skim over formulas on their first reading of your exposition. Therefore, your sentences should flow smoothly when all but the simplest formulas are replaced by “blah” or some other grunting noise.

20. Some handy maxims:
Watch out for prepositions that sentences end with.
When dangling, consider your participles.
About them sentence fragments.
Make each pronoun agree with their antecedent.
Don’t use commas, which aren’t necessary.
Try to never split infinitives.

I know the first is certainly true for me as I’ve been trying to wade through Haskell (a language into “literate programming”) introductions recently, which are very math-heavy.

Borrowing Java’s XSLT Support for Ruby

Friday, March 2nd, 2007

Well, I finally caught up with the crowd and got JRuby running on one of my dev boxes. The reason I’d been interested in it from the getgo was because Ruby lacks any support for internal XSLT processing. All those system()s were starting to get me down, especially as I’m trying to get a DocBook->PDF rendering webservice to be a lot faster. Much to my surprise, I was able to get simple transforms working in almost no time (thanks in part to lots of help). Without further ado, here’s a simple library for XSLT transforms using either Xalan-J or Saxon (make sure you have the jars for both in your CLASSPATH):

require 'java'
module JXslt
  include_class "javax.xml.transform.TransformerFactory"
  include_class "javax.xml.transform.Transformer"
  include_class "javax.xml.transform.stream.StreamSource"
  include_class "javax.xml.transform.stream.StreamResult"
  include_class "java.lang.System"

  class XsltProcessor
    def transform(xslt,infile,outfile)
      transformer = @tf.newTransformer(StreamSource.new(xslt))
      transformer.transform(StreamSource.new(infile), StreamResult.new(outfile))
    end 
  end # XsltProcessor  
  class Saxon < XsltProcessor
    TRANSFORMER_FACTORY_IMPL = "net.sf.saxon.TransformerFactoryImpl"
    def initialize
      System.setProperty("javax.xml.transform.TransformerFactory", TRANSFORMER_FACTORY_IMPL)
      @tf = TransformerFactory.newInstance
    end 
  end
  class Xalan < XsltProcessor
    TRANSFORMER_FACTORY_IMPL = "org.apache.xalan.processor.TransformerFactoryImpl"
    def initialize
      System.setProperty("javax.xml.transform.TransformerFactory", TRANSFORMER_FACTORY_IMPL)
      @tf = TransformerFactory.newInstance
    end 
  end
end 

# if you wanted to run this from the command line, do something like
# $ jruby lib/jxslt.rb a.xsl in.xml out.xml
xalan = JXslt::Xalan.new
xalan.transform(*ARGV)
#saxon = JXslt::Saxon.new
#saxon.transform(*ARGV)

Big props to Charles for helping me get going and writing the first version of the above.

darcs get http://kfahlgren.com/code/lib/jxslt/ or jxslt.rb

Ruby and the Atom Publishing Protocol

Saturday, February 24th, 2007

I gave a short talk at the first North Bay Ruby Users Group last Thursday (Feb 15, 2007) about my recent work implementing an Atom Publishing Protocol library in Ruby. Here’s the presentation:

Thumbnail of my Ruby APP talk

North Bay Ruby Users Group: First Meeting This Thursday

Monday, February 12th, 2007

I’m pleased to re-announce a new Ruby Users Group for folks north of San Francisco (or who like to go to Sebastopol, CA): the North Bay Ruby Users Group.

Our first meeting is this week; February 15th, 2007 at 7:00pm. O’Reilly has graciously offered us a place to meet, so we’ll be holding the meetings at O’Reilly HQ in Sebastopol, CA (directions).

Meetings are on the third Thursday of each month. If you’re interested in learning more, please sign up for the mailing list.

Our first meeting will feature Rob Orsini and myself, kicking things off by discussing how O’Reilly uses Ruby to make good things happen.

Please RSVP on the mailing list so we know how much pizza to buy. We hope to seeing you there!

Exploiting FrameMaker MIF as XML, Introduction

Saturday, February 3rd, 2007

My O’Reilly colleague Andy Bruno has just written a pair of posts on converting FrameMaker’s MIF (link may be old/die) format into XML (henceforth ‘MX’). I’ll be writing a few posts outlining the ways in which we’ve leveraged MX at O’Reilly.

[Update: Series continues here with getting back into MIF, and reading bookfiles.]

(more…)

Amazon Scrape -> SVG Graph in Ruby

Thursday, February 1st, 2007

I just spent a few minutes enjoying Mongrel and SVG::Graph while helping Rob visualize his Amazon Sales Rank for his book.

The code is available here with a running (maybe) example here. If all goes well, that should show you an SVG graph (thanks, Firefox) showing the changes in sales rank over time.

Rob’s code to generate the scrape is here.

Picture:
Rob Sales Rank

[Update: darcs get http://kfahlgren.com/code/]

North Bay Ruby Users Group Formed

Wednesday, January 24th, 2007

I’m pleased to announce a new Ruby Users Group for folks north of San Francisco (or who like to go to Sebastopol, CA): the North Bay Ruby Users Group with a first meeting on February 15th, 2007 at 7:30pm 7:00pm. O’Reilly has graciously offered us their meeting space, so we’ll be holding the meetings at the office in Sebastopol, CA (directions). The initial schedule for meetings is the third Thursday of each month, but we can have a discussion about whether other times work better at the first meeting. If you’re interested in learning more, please sign up for the mailing list.

[Full disclosure: Both Rob Orsini (the author of the recently released Rails Cookbook) and I are both employees of O’Reilly Media, so I can’t pretend that holding the meetings here was a total accident.]

The agenda, as well as everything else, for the first meeting is still in flux, but Rob and I are planning to do a presentation on how O’Reilly uses Ruby internally, from small internal Rails sites to Atom Publishing Protocol libraries to XML processing. We can spend the rest of the time getting to know each other, eating pizza, and planning upcoming meetings. If you’d like to make a presentation at a future meeting or know someone who should, please join the mailing list and make suggestions (even if you can’t make it every month).

Looking forward to seeing you there!

PS: Yeah, the website is pretty crappy right now, we’ll be making it more useful in the coming days, adding a wiki and all that. For now, just be happy it isn’t this.

BDD, rspec Worth the Fuss?

Friday, January 19th, 2007

So, I’ve been hearing a lot of buzz lately in the Ruby community about BDD and rspec. Like this person on ruby-talk, I didn’t really understand what all the fuss was about. However Dave Astels’ great Google Tech Talk video (worth watching in full rather than just a part, thanks James Britt) has at least inspired me to download rspec and start playing around.

I’m pleased to see that rspec has support for both rcov and heckle built-in, as I’ve been enjoying both recently.