Saturday, September 12, 2009

Up, Up, and Away

Let's say you are in a subdirectory, and there's a Makefile in a parent directory. How do you run make? You climb back up to the parent directory and type "make", or use "make -C parent_dir". In either case, you have to know what the parent dir is. Here are a pair of scripts that do that for you.

The findup script's job is to find a file in a parent directory. It prints the directory name if found, else it exits with status 1.


#! /bin/sh
#
# usage: findup file [file...]
#
# Finds any of the files in the current directory or any directory above and
# prints the directory name. If no such directory is found (we hit the root
# directory), exit 1. Note: will not find files in the '/' directory.

start_dir=`pwd`

while [ `pwd` != '/' ] ; do
    for f in $* ; do
        if [ -f $f ] ; then
            echo `pwd`
            exit 0
        fi
    done
    # Keep swimming...keep swimming...swimming, swimming, swimming...
    cd ..
done

# No parent directory
exit 1

The makeup script uses findup.


#! /bin/sh
#
# usage: makeup [args...]
#
# Finds the first makefile in the current directory or any directory above and
# then runs make, passing on any args given to this script.
#
# Relies on the "findup" command, which is found in this directory.

mfdir=`findup makefile Makefile`
if [ -z "$mfdir" ] ; then
    echo no makefile found
    exit 1
fi

# We've found a makefile. Use the -C flag to tell make to run from the
# directory where we found the makefile. We do this so that error messages
# produced during the make process are relative to the current directory. I
# think.
make -C $mfdir $*

Monday, August 3, 2009

ChucK Hack Fork

I've created a GitHub fork of ChucK, the "strongly-timed, concurrent, and on-the-fly audio programming language." In my fork I've started to add missing features like string methods, and hope to add many more such as raw file I/O and perhaps some form of MIDI file I/O.

So far, I've added string.ch which is a getter and setter for string characters (really one-character length substrings) and string.substr. This allowed me to write a function in ChucK that converts strings like "c#4" to MIDI note numbers.

It looks like ChucK's code was last updated in 2006, so I don't feel to bad about forking it.

Update: I just read in the chuck email list archive that the team is planning to start active development again, and they will be adding file I/O. If they get it done before I do, that would be very nice.

Monday, June 22, 2009

A Weak Man Begs Forgiveness

Dearest Colleagues,

I write this electronically-delivered letter to you in the hopes that you will forgive me. A terrible fate has befallen my lovely daughter V_______, and I am afrid that I now share in her misfortune. To protect you all from similarly horrible destinies, I must eschew your company this day.

It all started innocently enough, with a persistent cough. My eldest daughter would delicately hack to "clear her throat". The coughs became more frequent and urgent. She developed a fever which burned her pure, innocent forehead. As time passed, she begain to writhe in agony, delirious with dreams of God knows not what Heavenly retributions and Hellish tortures.

My dearest wife E____ conveyed her to the pediatrician's office on Sunday. Her doctor (a woman, by God! Ah, well. I know not what muse guides Science, but she must hold in favor the fairer sex) diagnosed V_______ with Swine Flu. The woman practiced her Art with confidence, perscribing the most modern treatments available.

We repaired to our home, powders and poultices in hand. The cure had barely taken hold of my dear daughter when I myself began to cough. At first, I denied the obvious. What strong man would not? Having fought in The War, my thoughts were not for my own safety or bodily condition but for that of my child.

I tell you now: Mr. Poe never wrote of horrors so small. The tiny demons that ravage my body even now defy all description, and to burden you with reports of the agony they cause does not merit further thought.

The submarine-like conditions of the Juicyorange office being the breeding grounds for animalcules it is, it is best that I remain far, far away. This is why I have decided to remain in an entirely different State of the Union. My sorrow at not joining you is only mitigated by the knowledge that you will not be exposed to the fiends that wrack my body.

In the fervent hope that this missive is not rerouted to your Spam folder,

With Deepest Respect,
James J. Menard
Babbage Engine Servitor

Saturday, April 18, 2009

Using will_paginate in Rails to Submit an AJAX Form

I'm using will_paginate for a Rails project. It works great, but I wanted to use it for a sidebar that performs searches and displays the results. It's not too hard to write a custom link renderer that will submit the will_paginate link using Ajax, but my situation was a bit different: I wanted will_paginate to inject the page number into the search form and submit the form using Ajax.

Here's what I ended up doing: writing a link renderer that calls a JavaScript function that injects the page number into the form and calls the form's onsubmit function (which then submits the form using Ajax).

The code. First the Haml, which is in a partial that gets rendered on a number of pages:

%h1 Asset Search
- form_remote_tag(:html => {:id => 'ssform', :name => 'ssform'}, ...) do
  %input{:type => 'hidden', :id => 'sspage', :name => 'sspage'}
  / ...
  %input{:type => 'submit', :value => 'Search'}

  - paginated_section(sidebar_assets, :class => 'rhs_pagination', :renderer => SidebarSearchLinkRenderer) do
    %table.list
    / ...

Next, the will_paginate renderer, in the file app/helpers/sidebar_search_link_renderer.rb. The "#" is the href value, and the onclick attribute calls a JavaScript funtion.

class SidebarSearchLinkRenderer < WillPaginate::LinkRenderer

  def page_link(page, text, attributes = {})
    @template.link_to text, '#', attributes.merge(:onclick => "return sidebar_search(#{page});")
  end

end

Finally, the JavaScript function which I put in public/javascripts/application.js:

function sidebar_search(page) {
  $('sspage').value = page;
  document.forms['ssform'].onsubmit();
  return false;
}

Wednesday, February 25, 2009

Time Keeps On Slipping, So Freeze It

A friend of a friend has trouble testing timestamps. I tried replying there, but don't think my answer got through so here it is.

The short answer: all time operations should not use the wall clock, but a system time object that you create. In production, the system time object returns wall clock time. In testing, you replace/mock/modify it so that it uses the time you give it. In other words, it becomes a clock that you can freeze and re-set whenever you need to.

Here is an example SystemClock class in Ruby. All of your classes should use this class to get the current date and time instead of using the Time or Date classes directly.

# Keeper of the current system time. This class is sometimes overridden during
# testing to return different times.
class SystemClock

  def self.date
    Date.today
  end

  def self.time
    Time.new
  end

end

Here is the mock used during testing. You can set the time using this mock object and it will not change until it is set again.

# This mock lets you set the system date and time during testing. For example,
# to set the date to tomorrow,
#
# A few examples of use:
#
#   SystemClock.date = Date.today + 1 # Time also set: to tomorrow 9:10:11 am
#   SystemClock.date = nil            # Go back to using system date and time
#   SystemClock.date = Date.civil(2006, 4, 15)
#   SystemClock.time = Time.local(2006, 3, 2, 8, 42, 42) # Date changed, too
#
# When you set the date, the time is set to 9:10:11 am of the same day, local
# time. When you set the time, the date is set to the same day.

require 'models/system_clock'

class SystemClock

  @mock_date = nil
  @mock_time = nil

  def self.reset
    @mock_date = nil
    @mock_time = nil
  end

  def self.date=(date)
    @mock_date = date
    @mock_time = date == nil ? nil :
      Time.local(date.year, date.month, date.day, 9, 10, 11)
  end

  def self.time=(time)
    @mock_time = time
    @mock_date = time == nil ? nil :
      Date.civil(time.year, time.month, time.day)
  end

  def self.date
    @mock_date || Date.today
  end

  def self.time
    @mock_time || Time.new
  end

end

So in your normal production code you get the current time by calling SystemClock.time instead of Time.now. In your test code, you'd do something like this:

# Make sure to include the mock class
SystemClock.time = Time.now # Or any arbitrary time
thing = Thing.new           # Uses SystemClock to set created_at attribute
assert_equal SystemClock.time, thing.created_at

Wednesday, January 28, 2009

text2midi App Uses midilib

Gabriel G has released text2midi, a Rails app that converts—wait for it—text that you paste into the Web page to MIDI, and plays it for you and lets you download the MIDI.

text2midi uses midilib, my Ruby MIDI manipulation library.

Go, Gabriel!

Thursday, January 15, 2009

10gen Shifting Emphasis to the Database

10gen has announced that it is Shifting Emphasis to the Database. They decided to focus on the Mongo database after finding that there was much more interest in it than in their Babble cloud computing app server.

Babble is still alive, though. It has a new web site and has shifted to the Apache license.

This may all be good news for 10gen, but it's bad news for me. Since I was working on bringing Ruby and Rails to Babble, I and a number of other fine engineers at 10gen have been let go. It hurts, but I've had a blast and learned a lot at 10gen.

For the next few weeks, I'm going to be finishing up work on the Ruby Mongo driver, MongoRecord (an ActiveRecord-like framework for Mongo that is independent of Rails), and Rails ActiveRecord support for Mongo.

Oh, yeah: here's my resume.