Mat Schaffer's Blog

Using Runnables in the Redcar Editor

So it’s been awhile since I’ve posted, and no I haven’t decided to take up cooking. Although I do use chef a lot at work.

I’ve been spending a lot of time lately working on the Redcar Text Editor. It’s become my favorite way to spend my personal hacking time. My most recent contribution has been some work on “Runnables” which is the Redcar plugin that lets you run commands from inside the editor. Even one of the collaborators on the project didn’t really know how to use it so I thought I’d write an explaination.

Overview

Like I said Runnables lets you run commands inside Redcar. It let’s you set up two types of commands:

  • Commands: These become list items that you can click on to run. You can view by selecting Project -> Runnables from the menu. They look like this.
  • File Runners: These are commands that get run when you hit Ctrl+R if your current file matches a regex.

You define these runners in .redcar/runnables/mycommands.json. Runnables will read any *.json file in that directory. The file also gets processed whenever you hit Ctrl+R so you can edit the file runners as much as you like. At the moment, it looks like you have to re-open your project for Commands to get refreshed. I might fix that soon though.

Example

So here’s my features.json file which allows me to run a full test suite as well as use Ctrl+R to run individual Cucumber and RSpec tests:

{
  "commands":[
    {
      "name":        "Full suite",
      "command":     "jruby -S rake",
      "description": "Run the full test suite",
      "type":        "task/ruby/rake"
    }
  ],
  "file_runners":[
    {
      "regex":   ".*\\.feature",
      "name":    "Run as feature",
      "command": "jruby -J-XstartOnFirstThread bin/cucumber __PATH__",
      "type":    "test/ruby/feature"
    },
    {
      "regex":   ".*_spec\\.rb",
      "name":    "Run a spec",
      "command": "jruby -J-XstartOnFirstThread -S spec __PATH__",
      "type":    "test/ruby/spec"
    }
  ]
}

So as you can see, the command is just the command that gets run if the file’s path matches regex and the file path gets substituted for the __PATH__ in the command. I still haven’t really figured out what the type and description fields do for you yet, but I expect I will soon.

Bonus

If you use my color-and-scrolling-runnables branch you’ll also get support for ANSI color output and automatic scrolling (courtesy of Delisa Mason). Hopefully both of these features will be in master soon. Here are the commands to force color if you want to give it a try:

# Force color in Cucumber
jruby -J-XstartOnFirstThread bin/cucumber --color __PATH__

# Force color in RSpec
AUTOTEST=true jruby -J-XstartOnFirstThread -S spec --color __PATH__

Future Enhancements

I’ve been told that this plugin only works on Unix systems right now. So Windows users can’t partake in the awesomeness just yet. I’ll see how I can help there.

I haven’t found a way to make a general *.rb matcher without having my specs run twice. Seems like the plugin needs support for a “last” flag to make sure that we don’t keep moving down the list and running more commands. Perhaps the type field has something to do with it.

I’d like to have a way to reuse the “Run File” tabs that get created so I can just keep re-running my specs without having to clean up old output. I haven’t decided the best workflow for that yet. Sometimes you want to be able to see old output and so I don’t want to just clobber that in all cases.

If you have any other ideas feel free to come chat about it in the Redcar IRC channel or on the Redcar mailing list.

Curried Chicken

Tonight Kaori talked me through cooking one of my favorite chicken dishes which we usually call カレー味チッケン or Curry-flavored chicken.

Ingredients

For the chicken:

  • 2 boneless chicken thighs
  • Corn starch, enough to coat the chicken
  • Vegetable oil, enough to coat your frying pan
  • 1 tbsp Sugar
  • 1 tbsp Mayonaise
  • 1 tbsp Soy Sauce
  • 1 tbsp Oyster Sauce
  • 1 tbsp Cooking Rice wine
  • 1 tbsp Curry Powder

To go with it

  • 1 cup Rice
  • A bag of pre-washed salad

For the soup:

  • Chicken boulion
  • 1 egg
  • Dried Wakame (seaweed) or other small green veggie

Step by step

Start the rice first since it’ll take awhile.


Cut the chicken into bite-sized chunks. This is easier if the chicken is still half-frozen so no need to get crazy with the defrost. Just nuke it enough so it’s a little soft on the outside.

Next coat the chicken in corn starch. Just pour it over the chicken while it’s still on the cutting board and mix by hand. Use enough to cover all sides of the chicken.

Start heating a frying pan on medium heat. Pour in enough vegetable oil so that you have a thin coat over most of the pan. Once the pan is warm, put in the chicken and stir a little bit with a spoon.

While the chicken cooks, get a small bowl and mix together 1 table spoon each of the Sugar, Mayonaise, Soy Sauce, Oyster Sauce, and Rice Wine. If you do it in that order you can use the same spoon for everything. Then add the curry powder. About 1 table spoon should do it, but you can add more if you want more kick. Mix it together until it looks like this.

Keep turning the chicken till it gets a bit golden, then stir in the sauce you just made. It’s pretty strong if you put in all of it, so feel free to leave some out.


Once you add the sauce keep it moving and don’t let it get too hot because the sauce can burn. Let it cook for another minute or two so it gets brown, then take it off the heat and the chicken is done.

You can serve it with some rice and salad. To get those nice little domes, just pack the rice into a small rice bowl then flip it over onto a plate. You may have to jiggle it a bit, but if the rice is hot it should fall out of the bowl pretty easily. And of course it looks best next to a beer.

As for the soup, this was pretty easy. Just boil enough water to fill your soup bowls, plus a little extra. Add in chicken boulion until the water has a bit of flavor. I used 1.5 tbsp of powdered boulion. Beat 1 egg in a bowl, then pour it into the boiling broth in a circular motion and follow it with a quick gentle stir. Add in the dried wakame, or whatever small green vegie you have handy (scalions, finely cut spinach or broccoli). One more quick stir and you’re done.

Where to find some of this stuff

So a couple of these things might be hard to find at your regular grocery store. Oyster Sauce should be available in most asian markets. Rice Wine for cooking might be in your grocery store, but if not, most asian markets should have this as well. As for the curry powder, I’m pretty sure a basic McCormick curry powder should work but you may need to adjust the amount. I recommend tasting the sauce as you make it to find the right mix. The dried wakame would be another asian market thing, but as I mentioned anything to give it a bit of green color and veggie flavor should work fine. The egg and boulion provide most of the soup’s substance.

How to mock out jQuery and Raphael

Most people are in agreement now that testing is a good thing. But most any JavaScript developer out there will tell you that testing browser-dependent code (jQuery, Raphael, etc.) can be a pain. You usually have to concede to running your tests in the browser, or spend lots time of pounding out env.js bugs to get something headless running.

But here at Hoopla, Trotter and I have found a very happy middle ground. As outlined in his post, it’s trivial to make a simple mock Raphael that satisfies your code and allows you to test what got called. But in practice, maintaining these mock classes gets repetitive quickly.

So I wrote recorderMock.js, which makes it easy to create full-featured mock objects for things like jQuery, Raphael and any other library that doesn’t run outside of the browser.

Say you wanted to test some code that used jQuery to resize a div:

$("#display").width(someComputedWidth).height(someComputedHeight);

I think I just heard your inner tester say “oh shit.” Worry no longer my friend. Building a mock for this with recorderMock is super simple. Just put this in your setup code.

$ = recorderMock("width", "height");

You can even check that they got called with the right values:

expect($.height.__calls[0].arguments).to(eql, [250]);
// or 
expect($.height.__calls.last.arguments).to(eql, [250]);  

And specifying return values is only slightly more complicated. Say you want to return mock html for different DOM elements:

this.startDate = $("#start-date").html();
this.endDate   = $("#end-date").html();

Mock it out like this:

$ = recorderMock("html");
$.html.__returns(function(call) {
  var selector = call.previous.arguments[0];
  return { "#start-date": "January 1st, 2010",
           "#end-date":   "January 31st, 2010" }[selector];
});

Need a basic mock of Raphael? Just use this:

Raphael = recorderMock("path", "rect", "text", "attr", "init", "push", "set",
                       "hide", "show", "animate", "animateWith", "rotate",
                       "translate", "setSize");

So there you have it. You can indeed test browser-related code outside a browser. And it’s pretty easy.

recorderMock has a handful of other tricks, and I’ll probably be adding more soon, so keep an eye on the specs for examples on how to use it more fully.

Update 2010-05-06:

I just released version 0.3.0 which includes better support for inspecting the call chain. The above examples have been updated to reflect the API changes and enhancements.

Things I Love About Bundler

So I’ve been working with working with Rails 3 and bundler full time for a month and a half now and it’s going swimmingly.

Here are some things that bundler does that I think are awesome.

Gems from git repositories

We use custom forks of arel and savon in our project. Before bundler, managing this would have been a mix of submodules/braid/piston and custom gem files that could easily become a mess. With bundler we just throw this in our Gemfile and we’re done.

gem 'savon', :git => 'git://github.com/hoopla/savon.git'
gem 'arel',  :git => 'git@github.com:hoopla/arel.git'

Gems from the local file system

Much like loading from git, bundler also handles loading gems from a local path. This is great if you want to try out some ideas on a gem, but you’re not yet sure if gem is worth forking.

gem 'mygem', :path => '/path/to/my/gem'

What’s especially awesome is that bundler wires things up so that source modifications get picked up without any sort of repackaging or reinstalling. This beats the pants off of the change source > repackage gem > reinstall gem > test cycle that was so easy to fall into before bundler.

It actually works

I don’t know about you, but I don’t think I’ve ever had a real Rails 2 project on which rake gems:install really worked. There were always a couple of gems (rspec) that you needed to install separately. bundle install on the other hand works pretty much every time.

Now of course it’s not all rainbows and unicorns. Bundler seems to take up some extra startup time beyond what I was used to on Rails 2. And I often wish there were a way to make it check git repositories for updates a little less aggressively. But for 0.9.22, I’m impressed. Hats off to carlhuda, indirect and any others that appear beyond page 3 of the commit log for all their hard work on it.

Managing Unix packages on OS X with Homebrew

This month I started a new gig which landed me with a new MacBook so I thought it seemed like a good time to try out the Homebrew package manager. It’s almost a month later and I am loving it. The beer-related jargon doesn’t hurt either.

Have you ever gotten annoyed at the time it takes for a package to get updated on MacPorts or Fink? Or tried to install a MacPorts package only to have it reinstall your ssh client or other core system component? I got fed up with this sort of thing over a year ago and have been compiling packages by hand ever since. Then I found Homebrew.

Installation is straightforward. You’ll need XCode of course, then you can just do this:

sudo chown -R $USER /usr/local
curl -Lsf http://github.com/mxcl/homebrew/tarball/master | tar xvz -C/usr/local --strip 1

Or they have more automated approaches in their README if you’re into that sort of thing.

The real win of Homebrew is how packages are defined: in Ruby. Have a look at this hotness for describing how to install redis:

require 'formula'

class Redis < Formula
  url 'http://redis.googlecode.com/files/redis-1.2.5.tar.gz'
  homepage 'http://code.google.com/p/redis/'
  sha1 'f28d840d8100586796cab02ccd8e91545a92179d'

  def install
    %w( run db/redis log ).each do |path|
      (var+path).mkpath
    end

    ENV.gcc_4_2
    system "make"
    bin.install %w( redis-benchmark redis-cli redis-server )
    
    # Fix up default conf file to match our paths
    inreplace "redis.conf" do |s|
      s.gsub! "/var/run/redis.pid", "#{var}/run/redis.pid"
      s.gsub! "dir ./", "dir #{var}/db/redis/"
    end
    
    etc.install "redis.conf"
  end

  def caveats
    "To start redis: $ redis-server #{etc}/redis.conf"
  end
end

Hot right? What’s more is that if you run brew update it’ll turn your /usr/local into a working git repository where you can tweak these scripts, push to your own fork and contribute back. Compare that to the MacPorts Portfile for redis which took me 5 minutes just to find, let alone tweak or contribute. Homebrew keeps all those files in /usr/local/Library/Formula, so have at it!

For more info on Homebrew check out their wiki or their collection of blog links as I’m sure they’re more accurate than anything I’d produce.

So go grab a beer and toast your package management woes farewell. Hope you enjoy Homebrew as much as I do!

mat@schaffer.me

I live and code in Philadelphia, Pennsylvania. I travel and take pictures when I can and also have family in Japan.

マイホームページへよこそう!フィラデルフィアで働くウェブのプログラマです。旅行へ行って写真をとることがすきです。

twitter.com/matschaffer
  • Loading tweets...
del.icio.us/schapht
  • Loading bookmarks...