davor babic

Contributing to Shoes4

Let me start off by saying that if you’re unfamiliar with the project, you should first have a look at Tobias Pfeiffer’s presentation. Shoes is a great little cross-platform GUI library/DSL for Ruby and Tobias does a great job of explaining what’s new in Shoes 4 and why you should care.

But before we start, let me just show you an example of why Shoes rocks. Here are two versions of the code for displaying a window with the text “Hello, world!”. The first is written in Java and the second in Ruby using Shoes.

Javalink



















import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class SWTHelloWorld {
  public static void main (String [] args) {
    Display display = new Display ();
    Shell shell = new Shell(display);
    Text helloWorldTest = new Text(shell, SWT.NONE);
    helloWorldTest.setText("Hello, world!");
    helloWorldTest.pack();
    shell.pack();
    shell.open ();
    while (!shell.isDisposed ()) {
      if (!display.readAndDispatch ()) display.sleep ();
      }
      display.dispose ();
  }
}
Shoes 4/Ruby


Shoes.app do
  para "Hello, world!"
end

Introduction

In the following blog post I’m going to walk you through implementing a style for the list box element and by the end of it you should have the knowledge necessary to submit your first Shoes commit.

I’m going to assume that you have some familiarity with JRuby and RSpec, but even if you don’t most of the code is pretty easy to get a grasp of.

Please note that the code presented below isn’t written to be particularly eloquent, but to be easy for a newcomer to the project to understand.

Code Tour

The first thing you need do is head on over to the project’s Github repository and create your own fork. If you’re unfamiliar with git or Github, there are already excellent tutorials out there that will help get you started.

Basically there are just two folders that you need to worry about; specand lib. spec contains the Shoes-spec. In it there are two folders, shoes and swt_shoes. The first folder contains the spec for the DSL part of Shoes and should be somewhat language agnostic while the second folder contains very implementation specific tests. lib has two subfolders that function in the same manner. The language agnostic stuff is in lib/shoes, while the swt-stuff is in lib/shoes/swt.

The user’s program calls functions in lib/shoes/element_methods.rb, which in turn call the different classes found in lib/shoes that load the actual backend classes (right now in lib/shoes/swt/ or mock) by calling Shoes.configuration.backend. Shoes.configuration can be found in lib/shoes/configuration.rb and is responsible for loading the correct backend.

There’s a more info about the structure in the project wiki.

Implementing your first feature

We’re going to start off by implementing the :choose style for the list box. It is described more closely in the manual. When we’re done, the following code will create a window with a simple list box and the item “cat” pre-chosen.




Shoes.app do
  para "Here's a list box:"
  list_box :items => ["cat", "hat"], :choose => "cat"
end

The first thing we will do is open up spec/swt/list_box_spec.rb and add the following lines.

The manual states that the list box is supposed to have a method called choose that “Selects the option in the list box that matches the string given by item”. Let’s start off by implementing that feature. First, let’s make sure that list box actually has a method with that name.

spec/swt/list_box_spec.rb
  it { should respond_to :choose }

Now type in rake spec and make sure that the test fails. Did it fail? Good! Now, let’s actually create choose.

lib/shoes/list_box.rb


def choose(item)

end

Run the spec again and make sure that it passes. Please note that our choose-method doesn’t actually do anything yet. Let’s continue defining what we expect from it in the spec.

spec/shoes/list_box_spec.rb




it "should call @gui.choose when we choose something" do
  Shoes::Mock::List_box.any_instance.
           should_receive(:choose).with "Wine"
  subject.choose "Wine"
end
lib/shoes/list_box.rb


def choose(item)
  @gui.choose item
end

All we’ve done now is basically just made sure that shoes/list_box calls @gui.choose, when something calls its choose-method. In the future, we might want this method to check and make sure that item actually is a part of items. I leave this as an exercise to the reader. ;–)

Now let’s open up the swt part of the spec and finish what we started. Judging from the javadoc what we need to do is call setText on the SWT combo-object (@real). So basically we want to make sure that we call @real.text=value (thanks to JRuby, the same thing as @real.setText(value)) when we call choose.

spec/swt_shoes/list_box_spec.rb





it { should respond_to :choose }

it "should set the text when we call choose" do
  real.should_receive(:text=).with "Bacon"
  subject.choose "Bacon"
end
lib/shoes/swt/list_box.rb


def choose(item)
  @real.text = item
end

Now we just need to make sure that list_box actually responds to the :choose-option.

lib/shoes/list_box.rb



def initialize(parent, opts = {}, blk = nil)
  # …
  self.choose opts[:choose] if opts.has_key? :choose
end

And we’re done! Easy, right?

What’s next?

The best way to get acquainted with the code and the easiest features to implement are styles. To get started with that just take a look at the manual and try to figure out what styles aren’t yet implemented, and then simply add them.

I would caution you to stay away from Text_block.rb for a while. Most of the styles for that class are dependent on custom layout managers that haven’t been written yet.

Another great place to look for what needs to be done is the issue tracker on Github.

Other Resources

The following resources should be quite handy if you’re looking to help out.