Richie Vos

More from me

September 22, 2009

GitHub Post-Receive Hook for Coop

At Business Logic we use Harvest to track our time. Harvest offers an integrated campfire-style chat room called Coop. The cool feature of Coop is it shows the time entries of members in a group, interspersed with the messages in the group. While it’s sometimes useful to see what others are doing as they go, our main use is to look at what your pair was doing 3 days ago when you forgot to do your time. This gives a pretty good idea of what’s going on, but when there isn’t an entry for that day, and you’re trying to do your time, I usually go back and look at our commit history on github.

The trick is to integrate those together, and for that, enter the coop api, github post-receive hooks and sinatra.

Implementation notes

Because the coop api is sort of Restful, but not totally, it took a bit of finagling to get it all together, but it did and is now on github as coop_github_hook. I personally haven’t ever used ActiveResource or sinatra for anything but toying around, so it was nice to be able to use both.

I’m now a big sinatra fan since it makes short-and-simple web services incredibly simple. Here’s the sinatra portion of this hook:

post '/hooks/coop' do
  push = JSON.parse(params[:payload])
  push['commits'].each do |commit|
    Coop::Status.from_github_commit_info(group_id, commit).save
  end
  "Thanks for playing"
end

The other interesting thing was dealing with the “sort of Restful” Coop status api (chat entries in the group). “Sort of Restful” really means “sort of useable by ActiveResource.” The issue arose in the way coop expects you to send the content for a post. If you have something called a Status which represents a text message, ActiveResource assumes, and Rails by default provides, data that looks like:

<status>
  <message>Good morning</message>
</status>

Coop’s api however wants that data to be sent as:

<status>Good morning</status>

To get the data into that format all you have to do is override ActiveResource::Base#encode in your ActiveResource class:

module Coop
  class Status < ActiveResource::Base
    self.site = "http://coopapp.com/groups/:group_id"

    # Co-op takes a non-ActiveResource friendly format for their status, so manually write that format
    def encode(options={})
      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<status>#{attributes['text']}</status>\n"
    end
  end
end

I’m not sure if this is something people normally do, but it is a pretty handy way to switch formats.

For usage info hook feel free to checkout the github repo and it’s associated Readme. If you have any problems feel free to shoot me a message over github or email.

August 18, 2008

Gmail POP & Outlook Tip

Gmail doesn’t pull read messages down when accessing a POP account. Therefore, if you’re using gmail and outlook on the same email account, you have to make sure to mark the messages you read in outlook as unread when you’re done looking at them. Otherwise they won’t make it to gmail.

To simplify your life, a better solution is to just tell Outlook not to automatically mark messages as read. Then messages will make their way to gmail unless you specifically mark it as read.

Stealing directions from a Faq:

Q: How can I avoid the message be marked as read?

A: To avoid the message to be marked as read, you can do the followings:

  1. In Outlook » Tool menu » Options
  2. Click on Other tab  » Preview Pane » click on the Preview Pane button
  3. Uncheck the Mark Messages as Read in Preview Pane section.
  4. If you use the Preview Pane to read messages, use the space bar to mark the message as read. Otherwise, opening the message will mark the message as read as well. This way, you won’t miss some important messages be marked as read by accident.
August 12, 2008

Inserting a rake dependency first

Usually, if you’re trying to extend a rake task by adding new dependencies to it you just redefine the task with the new dependency.

namespace :tickle do
  task :cow => 'relax'
end

So if originally tickling the cow would first milk it, typing rake tickle:cow will now:

  1. Milk the cow
  2. Relax the cow
  3. Tickle the cow

If you instead want the relaxing to happen first, you have to go straight at the definition of the task and alter its prerequisites. These prerequisites are just an array of task names, so to make your new task happen first, just insert your task at the beginning.

# fetch the task definition
task = Rake::Task['tickle:cow']
# insert our new prerequisite at the beginning
task.prerequisites.insert(0, 'relax')

A real-life example of this is if you want to pull some data down before resetting your database with a rake db:migrate:reset. If you define a task like rake data:retrieve and don’t want to remember to do rake data:retrieve db:migrate:reset you can insert data:retrieve as an early prerequisite for db:migrate:reset.

Rake::Task['db:migrate:reset'].prerequisites.insert(0, 'data:retrieve')

And if you have to do this a lot, this may be handy

module Rake
  module OrderedPrerequisites
    def require_first(*tasks)
      prerequisites.insert(0, *tasks)
    end
  end
 
  class Task
    include OrderedPrerequisites
  end
end

And now you can do

Rake::Task['db:migrate:reset'].require_first('data:retrieve')
July 22, 2008

TypeError: Error #1115: ClassName.as$123::Cabbage is not a constructor.

Had this happen today, I believe the cause for this message is the specified class’s definition has not been loaded.

Example where this can happen is you have code like:

package good {
    public class Muppet {
        private static var ball:Ball = new Ball();
    }
}

class Ball {}

At the time of the running of the ball = new Ball(); code, the class definition of Ball has not yet been evaluated.

Solution is to move Ball into its own file.

July 14, 2008

workaround actionscript’s sucky map function

Instead of writing

function(element:Object, i:uint, a:Array):Object{ … }

and then always ignoring everything but element, just make your function var-arg and ignore the var-arg:

function(element:Object, …a):Object {..}

still ugly, but less characters and noise.

July 14, 2008

respond_to? in actionscript

The ruby code

object.respond_to?(‘methodName’)

in actionscript is

'methodName' in object