The Artima Developer Community
Sponsored Link

Ruby Code & Style
If It's Not Nailed Down, Steal It
Pattern Matching, S-Expressions, and Domain Specific Languages in Ruby
by Topher Cyll
May 23, 2006

<<  Page 5 of 5


Go, Turtle. Go!

Okay, let’s put multi to use again and build a method to run Logo S-expressions. We can put this in the initialize method along with the code to initialize our instance variables.

  def initialize
    @x, @y  = 100, 100
    @angle  = 0
    @buffer = "" 
    @pen    = true

    amulti(:run, :right, Numeric)   {|sym, r, rest| turn(r) ; run(rest)  }
    amulti(:run, :left, Numeric)    {|sym, l, rest| turn(-l) ; run(rest) }
    amulti(:run, :forward, Numeric) {|sym, f, rest| move(f) ; run(rest)  }
    amulti(:run, :penup)            {|sym, rest| @pen = true ; run(rest) }
    amulti(:run, :pendown)          {|sym, rest| @pen = false ; run(rest)}
    amulti(:run, :repeat, Numeric, Array) do |sym, i, code, rest|
      i.to_i.times{ run(code) }
    amulti(:run) {}

So what’s going on here?

The ‘run’ function takes a list of commands and arguments and consumes them as appropriate. The first two definitions pull the :right or :left command off the list along with a number of degrees to rotate. The turn() function does the dirty work. Note that all of the ‘run’ bodies recurse on the remaining arguments.

The definition that matches :forward moves the turtle, :penup and :pendown sets the value of @pen, and, finally, :repeat takes a number of times to repeat and an array of code to run. So let’s try this out.

(You can download the complete source here)

Testing Time

Running this code …

  logo =
  logo.eval %q{
    repeat 4 (forward 100 right 90)
    forward 50 right 90 forward 100
  puts logo.render

... gives us:

Logo output 2

Looks right!

Let’s Quit While We’re Ahead

Pattern-matching multiple dispatch, S-expressions, and Logo, that’s a pretty good haul. So next time you’re missing Haskell, or Lisp, or something really weird like Logo, why not just stick with Ruby? Of course, you might have to steal a few things first …


[0] DSLs in OCaml

[1] Internal versus External DSLs

[2] Why’s (Poignant) Guide to Ruby

[3] Introduction to Logo

About the Author

Topher Cyll is a software engineer in Portland, Oregon, who’s lucky enough to write about half of his projects in Ruby. Topher wrote the Multiple Dispatch and S-Expression RubyGems used in this article. He also volunteers on the Tech Team of the progressive political group The Oregon Bus Project and is an active member of the Portland Ruby Brigade.

<<  Page 5 of 5

Sponsored Links

Copyright © 1996-2018 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use