I was in Norway last week at the Norwegian Developers Conference, so I'm afraid the Weekly Source Code is the bi-weekly source code this month. It's amazing how international travel can really slow a body down. This trip just obliterated me. I'm slowly coming back to the world of the living, though.

I've been getting more and more interested in how folks extend their applications using plugins and things. In my new ongoing quest to read source code to be a better developer, Dear Reader, I present to you twenty-ninth in a infinite number of posts of "The Weekly Source Code."

This week's source is a clever "ClickOnce"-style hack for Ruby. It's cool because it brings together a number of technologies into a very clean end-user experience. The intent is to make the running of a Ruby GUI Application effortless, and it works and it's brilliant on several levels. Thanks to Sam Saffron for pointing me to it!

To start out, it's a hack says the author why the lucky stiff (or "_why" for short), so it's very early and there's bugs. You can check out the code on GitHub: http://github.com/why/shoes/tree/master or clone the whole tree using git via " git clone git://github.com/why/shoes.git "

Shoes

Ruby is a very aesthetically (to me) pleasing and flexible language. Shoes is a GUI Toolkit for making Windowing Applications using Ruby. I mentioned it back in TWSC12. Shoes is legendary for a number of reasons, but above all, it has the greatest API documentation in the history of all software documentation. The main book on Shoes Development called "nobody knows shoes" is fantastic. Even Chris Sells likes it!

Here's part of an example phone book application written in Ruby and Shoes):

Shoes.app :width => 320, :height => 350 do



stack :margin => 40 do

stack :margin => 10 do

para "Name"

@name = list_box :items => ["Yes, please!", "NO. No thankyou."]

end

stack :margin => 10 do

para "Address"

@address = edit_line

end

stack :margin => 10 do

para "Phone"

@phone = edit_line

end

stack :margin => 10 do

button "Save" do

Shoes.p [@name.text, @address.text, @phone.text]

end

end

end

end



It feels a lot like Tcl/Tk or Rebol. It'll be interesting to see if someone writes a mainstream application that is non-trivial. Shoes works on XP, Vista, MacOSX and Linux. Do note that you'll need to right click and run it as Administrator on Vista as _why hasn't put in an elevation prompt yet. You'll need Admin to do the initial bootstrap install.

However, in order to get Shoes to work, before today, you had to install Ruby, then get the Shoes libraries installed, usually via a gem. Then you'd need to run your app via ruby.exe yourapp.rb or a shortcut you'd setup. The second comment on _why's blog post announcement says it all:

"Wow, this is super. We can actually give our apps to other people now :)"

Here's an explanation from _why on how the Shoes "bootstrapper" (my word) works:

If you poke around with a hex editor inside Windows’ PE binary format, you’ll find an .rsrc section at the end of the file which contains the icons and dialog boxes. I insert the Ruby script into this mess. binj = Binject::EXE.new("blank.exe") binj.inject("SHOES_FILENAME", "simple-accordion.rb") File.open("simple-accordion.rb") do |f| binj.inject("SHOES_PAYLOAD", f) end binj.save("accordion.exe")

Fantastic hack. He shoves the Ruby script into a Windows Resource! He does the same thing for DMG (Disk Images) on Mac OSX, so you can create Ruby scripts that are portable to these two platforms.

When it runs, it checks for the existence of Shoes on your system. It's in C:\Program Files (x86)\Common Files\Shoes\. If Shoes (which includes a private copy of Ruby) is not there, it's downloaded and installed, and then your app runs. Bam, one-click cross-platform GUIs.

I'm not clear what the security ramifications are. Well, I am. I suspect there is no security that isn't already provided by the host operating system. Once you're running, the Ruby script has full control to do whatever it likes, so I suppose someone could write a malicious program just as they could write a malicious .NET app if they liked.

You can package your apps just by running shoes --package and you'll get this dialog. You can chose to include Shoes and Ruby inside the resulting EXE if you like.

Shoes also supports custom "Widgets." For example, here's a custom Speedometer control.

The code for the entire app, including the custom control is this:

class Speedometer < Widget

attr_accessor :range, :tick, :position

def initialize opts = {}

@range = opts[:range] || 200

@tick = opts[:tick] || 10

@position = opts[:position] || 0

@cx, @cy = self.left + 110, self.top + 100



nostroke

rect :top => self.top, :left => self.left,

:width => 220, :height => 200

nofill

stroke white

oval :left => @cx - 50, :top => @cy - 50, :radius => 100

(ticks + 1).times do |i|

radial_line 225 + ((270.0 / ticks) * i), 70..80

radial_line 225 + ((270.0 / ticks) * i), 45..49

end

strokewidth 2

oval :left => @cx - 70, :top => @cy - 70, :radius => 140

stroke lightgreen

oval :left => @cx - 5, :top => @cy - 5, :radius => 10

@needle = radial_line 225 + ((270.0 / @range) * @position), 0..90

end

def ticks; @range / @tick end

def radial_line deg, r

pos = ((deg / 360.0) * (2.0 * Math::PI)) - (Math::PI / 2.0)

line (Math.cos(pos) * r.begin) + @cx, (Math.sin(pos) * r.begin) + @cy,

(Math.cos(pos) * r.end) + @cx, (Math.sin(pos) * r.end) + @cy

end

def position= pos

@position = pos

@needle.remove

append do

@needle = radial_line 225 + ((270.0 / @range) * @position), 0..90

end

end

end



Shoes.app do

stack do

para "Enter a number between 0 and 100"

flow do

@p = edit_line

button "OK" do

@s.position = @p.text.to_i

end

end



@s = speedometer :range => 100, :ticks => 10

end

end



It's about 24 megs of libraries on disk when you're done, but you've got multimedia support and a lot of great library support in that space, not to mention a copy of Ruby itself. The download is only 2.5M bare or 6.8M with Video support.

I think it'd be great to build a Twitter Client using Shoes. The race is on! Hopefully we'll be able to get a Twitter Client done before some schmuck writes a Ruby Shoes virus. I for one, will be keeping the Ruby Shoes virus I wrote to myself. Well, not really a virus as it's a self propagating annoyance. But still. :)

It'll be fun to watch how this evolves. I hope there will be a clean upgrade process. If you want to try running your first Ruby/Shoes app, then run this EXE if you've got Windows or this DMG if you're on a Mac to see a basic demo application, but more importantly, to experience in the installer/bootstrapping process.