leah blogs

May 2005

15may2005 · Introducing Rye

After trying almost every web framework for Ruby out there, I still could not find one I really liked (Wee was close, but has non-restful URLs), so I simply decided to grow my own (hey, you know me ;-)), called Rye.

Rye is a framework of the different kind. I don’t have a lot of code yet, and lacks a lot of functionality, but I could extract the basic idea already and will try to explain it here.

Rye provides an RESTful interface to stored objects. So far, my objects are simply stored as YAML files, but that will not scale for bigger amounts of data. Rye maps these objects onto URLs like this:

http://<server>/<object-path...>/<method>/<arguments...>?<query>

So far, Rye can handle the two most commonly used (and supported, sigh) HTTP methods, GET and POST. In the case of GET, Rye will retrieve/load the object, call the method on it (possibly with the arguments and the parsed query) and, depending on the return value of the method, render the generated page or call show, the default renderer for the object. POST is treated similary, except that the object is saved to the store again before rendering the site. Therefore, GET can’t easily change any values and is idempotent, as required by REST. (Of course, you still can—and are free to—shoot yourself in the foot by manipulating the storage on your own, but it will really be your fault.)

The nice benefit of this is that there is not much to do to use Rye: Usually (so far, at least) you simply define a few YAML specific methods to store only the required instance variables of the object and make your class inherit from Rye::Base, which defines a few helper methods and attributes (maybe this should get a mix-in).

As an example, I developed a very simple to-do list manager:

class ToDoList < Rye::Base
  attr_accessor :title
  attr_accessor :todo
  attr_accessor :done

  def initialize(title)
    super()
    @title = title
    @todo, @done = [], []
  end

  def to_yaml_properties; ["@title", "@todo", "@done"]; end

  def show; template; end

  def add(params); @todo << params["item"]; self; end

  def finish(item)
    @done << item  if @todo.delete item
    self
  end

  def undo(item)
    @todo << item  if @done.delete item
    self
  end
end

As you can see, this is straight-forward Ruby code without any Web specific stuff—except maybe the show method that calls template, a helper defined in Rye::Base that renders the object using a class-specific Kashmir template (of course, you can easily interface with your favourite templating engine).

If you wonder why finish and undo return self, well, that means that Rye will redirect to show them, a useful and logic convention. finish and undo do change data, and therefore need to be called using POST. As of now, you would call finish("blubb") by writing HTML like this:

<form action="/myapp.rye/finish/blubb" method="post">
  <input type="submit" value="Finish blubb!" />
</form>

If you decide to pass additional values (for example, to call add using a form) you can do that too, as usual:

<form action="/myapp.rye/add" method="post">
  <input type="text" name="item" />
  <input type="submit" value="Add!" />
</form>

Since the code essentially only contains the real application logic, it is very easy to unit test. In fact, you test it just like any other class. (Nevertheless, I may add a helper library for unit testing which I dub “ergot” :-))

So far, Rye is only about 150 lines of code, but already covers a lot of the basic functionality. I’ll need to add a generic store, so one can use databases (for example with Og) too and isn’t forced to use YAML. Maybe I get a first release done this week (or possibly not, who knows).

I’d be interested in hearing your comments on Rye, just comment here or mail me.

NP: 33hz—Digital Lover

Copyright © 2004–2022