Ruby
[ Aslak Hellesoy ] 18:52, Monday, 18 July 2005

If you have ever hosted a project on RubyForge, SourceForge or some other clone such as GForge, you have probably experienced the pain of making a release on these systems.

This is because these systems only offer an ugly form based interface for releases. No web services, no scp. Just these bloody forms. -And most people interact with them manually, uploading files, pasting in release notes and so forth. There are probably some odd, unknown, project-specific scripts lying around in random places that can automate this, but I haven't seen anything reusable.

In fact, I hadn't seen anything at all, so 4 months ago I wrote my own script to do this. Except I couldn't get the HTTP multipart posts (attachments) to work properly. So I left it fermenting for a while...

But two days ago I felt the pain again, and I came across DHH's Rake script which does something very similar. -And it had the multipart code I couldn't grok myself.

So I decided to take the best parts of my old attempt and DHH's code from Rails' Rake script and make a proper library, so that others can use it. -Not only on RubyForge, but hopefully also on SourceForge and other sites running SourceForge clones.

So if you're as lazy as me, check out XForge.

XForge is released using XForge (of course!), so it works fine on RubyForge. Please let me know if you get it to work anywhere else, or if you have bugs or improvements.

[ Aslak Hellesoy ] 05:28, Wednesday, 9 March 2005

The concept of templates are very common in many contexts of programming. A boiler-plate representation of something can be turned into a concrete instance by supplying some extra data. The important point is that the supplied data can vary, and that has an impact on the structure of the concrete instance of the template.

In HTML programming, common template techniques are JSP, PHP, ERB and ASP. By passing some extra data to a template engine, a template can be turned into an HTML page that displays the data, using the layout from the template.

In OO programming, the most common concept of a template is a Class. A piece of a program can supply some data to a class' constructor and get a new object.

Sometimes, instantiating a new object by simply calling a constructor with some extra data is not the optimal way to create an object though. Consider the common situation where the desired object is composed of an aggregation of several other objects. -A complex graph of objects.

One way to approach this is to design classes (aka templates) to honour Dependency Injection (DI), and use a DI container supporting a configuration file (in XML or other format). NanoContainer or Spring are two frameworks that use this approach to instantiate complex graphs of objects composed of "variable data" from a configuration file.

Assuming you want the ability to create object graphs that are configured in an external file, and your language is Java, then it doesn't get much simpler than with NanoContainer or Spring.

But in Ruby...

A similar effect that is radically simpler and extremely easy to use can be achieved with a dash of Ruby magic using YAML and eval under the covers. Consider this object template:

codehaus_project_template = Project.new
codehaus_project_template.home_page = "http://\#{unix_name}.codehaus.org"

jabber_publisher = JabberPublisher.new
jabber_publisher.id_resource = "damagecontrol@jabber.codehaus.org/#{unix_name}"

codehaus_project_template.publishers << jabber_publisher
(The template object can also be deserialised from a YAML file if we don't wish to do this in Ruby code, but this is not important from the perspective of describing how this object template technique works). The point I'm getting at is that I can create new instances from this template object like this:
project = codehaus_project_template.dupe("unix_name" => "mooky")      
assert_equal("http://mooky.codehaus.org", project.home_page);
assert_equal("damagecontrol@jabber.codehaus.org/mooky", project.publishers[0].id_resource);
The dupe method takes a Hash that should have one key/value pair for each variable in the object template. The dupe method simply creates a new object graph similar to the one in the template, but substitutes all variables with the values from the hash. -All the way out to the leaves of the object graph! The object template's variables are simply backslash-escaped #{blah} s in various String instance variable values (fields). In the example there is only one (#{unix_name}), but we could use as many as we like, at any level in our object graph. In Ruby it's ridiculously easy to make this happen. Just make the classes whose instances you want to use as templates include ObjectTemplate:
module ObjectTemplate
  def dupe(variables)
    template_yaml = YAML::dump(self)
    b = binding
    variables.each { |key, value| eval "#{key} = variables[\"#{key}\"]", b }
    new_yaml = eval(template_yaml.dump.gsub(/\\#/, "#"), b)
    YAML::load(new_yaml)
  end
end
A similar approach can be achieved in Java with XStream and Velocity (or Jelly, haha) and maybe a little bit of AOP - in 10 times or more as many lines of code - without the same ease of use.
[ Aslak Hellesoy ] 06:05, Friday, 25 February 2005

A couple of days ago I wished there was a way to use annotations in Ruby. I'm writing a Ruby on Rails application that renders a lot of objects in HTML. Many of these objects are "editable" via the web interface, and in order to make it easier for the user, I wanted the web interface to have both an explanatory text and a HTML tooltip for each object's field.

Because I like simple things I also like to keep things in one place (I don't want to maintain this metadata in a separate RHTML template).

Ruby doesn't support annotations out of the box, so I opened up the Class class and added support for annotations. Now I can do:

require 'rscm/annotations'

  class EmailSender
    ann :description => "IP address of the mail server", :tip => "Use 'localhost' if you have a good box, sister!"
    attr_accessor :server
  end

The class' annotations can then be accessed like this:

  EmailSender.server[:description] # => "IP address of the mail server"

It took the Java community forever to do stuff like this. First a couple of years of XDoclet, then JSR175. And tons of code too. In Ruby it's 1 hour's work and 25 lines of code. Go figure.

For more info see http://rscm.rubyforge.org/classes/Class.html

And oh, here's the code:

class Class
  def ann(anns)
    @@anns ||= {}
    def self.method_missing(sym, *args) #:nodoc:
      @@anns[sym]
    end
    $attr_anns ||= {}
    $attr_anns.merge!(anns)
  end

  alias old_attr_reader attr_reader #:nodoc:
  def attr_reader(*syms) #:nodoc:
    syms.each do |sym|
      @@anns[sym] = $attr_anns
    end
    $attr_anns = nil
    old_attr_reader(*syms)
  end

  def attr_accessor(*syms) #:nodoc:
    attr_reader(*syms)
    attr_writer(*syms)
  end
end
UPDATE (March 3 2005) An updated version of the Ruby annotations library is available at rafb