For day 3 of the Io programming language a very simple XML-like markup builder was given (the book named it LispML). The book gave the code to take a list of node names and the text value for those nodes and then it would put it into a markup language format So you could enter something like this:

Builder ul(
  li("Io"),
  li("Lua"),
  li("JavaScript"),
)

And get output like this:

<ul>
  <li>
  Io
  </li>
  <li>
  Lua
  </li>
  <li>
  JavaScript
  </li>
</ul>

Then for the exercises the book asked for this to be extended in two ways (there was also a 3rd that I haven't gotten around to yet). First was to have it indent each level of nested tags rather than printing them all at the same level. After that the goal was to add the ability to pass in attributes for the tag as the first argument within curly brackets.

So example input would look like this:

Builder ul(
  li({"whee","whoo"}, "Io"),
  li("Lua"),
  li("JavaScript"),
  li(li("wheee"))
)

And the corresponding output now looks like this:

<ul>
 <li whee="whoo">
 Io
 </li>
 <li>
 Lua
 </li>
 <li>
 JavaScript
 </li>
 <li>
  <li>
  wheee
  </li>
 </li>
</ul>

And now for the full code how I wrote it.

Builder := Object clone()
Builder newSlot("level",0)

#override curlyBrackets which is the method called
#when {} is seen by Io
Builder curlyBrackets := method(
  paramString := ""
  argArray := call message arguments
  for(i,0,argArray size - 1, 2,
    key := argArray at(i) asString asMutable strip("\"")
    val := argArray at(i + 1)
    paramString := "#{paramString} #{key}=#{val}" interpolate
  )

  return paramString
)

Builder forward := method(

  # There's probably a better way to add the indent
  # by formatting the string being printed directly
  # rather than using the spacer
  # but none of the obvious solutions have worked
  spacer := "" alignRight(level," ")
  attributes := ""
  if(call argAt(0) name == "curlyBrackets",
    attributes := doMessage(call message argAt(0));
  )

  writeln(spacer,"<", call message name, attributes,  ">")
  self level := self level + 1

  call message arguments foreach(
    arg,
    if(arg name != "curlyBrackets",
    content := self doMessage(arg);
    if(content type == "Sequence", writeln(spacer,content))))
  writeln(spacer,"</", call message name, ">");
  self level := self level - 1;
)

I wish this exercise had given me a reason to use the concurrency abilities of Io since that seems to be where the language really shines. It has easy to use support for coroutines, actors, and futures and even the book author and language creator say that concurrency is where this language is strong and gives really great performance.