Snarl: Growl Notifications for Windows

It’s been a while since I’ve been developing under OSX, and one of the things I definitely miss is Growl notifications. I looked around and found Snarl, a windows app inspired by Growl.

With my new toy in hand, I set out to get some notifications going. We’ve been playing around with Redmine, which is a a very nice issue tracking system built on Rails. Redmine features great Subversion integration, and has an Activity page that summarizes updates to issues, Subversion checkins, wiki updates, and pretty much anything else that would go on in the project. There’s an Atom page that you can subscribe to for updates, and I thought it would be a good place to poll for Snarl notifications.

I wrote this little script (which could probably use a little love) to poll a feed and provide Snarl updates. It requires the FeedTools and ruby-snarl gems. So far, it’s making me love Redmine more and more.

require 'feed_tools'
require 'snarl'

source = ARGV[0]
last_item = nil
old_guids = []
while true
  puts "Checking for updates..."
  feed = FeedTools::Feed.open(source)
  feed.items.sort_by{|i|i.updated}.reverse.each do |item|
    if !old_guids.include? item.guid
      old_guids << item.guid
      title = item.title.nil? ? "" : item.title[0..1023]
      description = item.description.nil? ?
        "" : item.description.gsub(/<\/?[^>]*>/, "")[0..1023]
      Snarl.show_message title, description
    end
  end
  sleep 1*60*1000
end

Posted by Scott Wed, 16 Jul 2008 19:36:00 GMT


Fun With Extend in IronRuby

Building on the implements idea from the last post, I’ve been playing around with extending CLR objects on the fly as I bring them at runtime. I wrote a quickie load_assemblies method that checks objects to see if they implement an interface, and extend them if they do.

I think this pattern will be very useful when importing existing .NET objects into IronRuby. For instance, if you wanted all of the objects governed by your ORM to take on ActiveRecord-like behavior, you could catch them and extend them like this:

class Class
  def implements? interface
    !to_clr_type.nil? && !to_clr_type.get_interface(interface).nil?
  end
end

def load_assemblies(assemblies)
  assemblies.each do |assembly| 
    require assembly
    System::Reflection::Assembly.load(assembly).get_types.each do |t|
      if t.to_class.implements? "IPersistence"
        t.to_class.extend ActsAsActiveRecord 
      end
    end
  end
  true
end

I’m sure there’s lots of other cool uses for the pattern… If anyone actually reads this shit and thinks of some, let me know. :)

Posted by Scott Mon, 30 Jun 2008 20:17:00 GMT


I'm in love with IronRuby

I’ve been playing with IronRuby a lot lately, and it’s turning out to be every bit as amazing as I’d hoped it would be. I’m constantly thinking about new stuff to do with it, but one of the easiest low hanging fruits is rewriting our existing unit tests in ruby.

I’ve been putting together a little library of IronRuby specific modules for tests. You’ve got to love being able to do things like this:

class Class
  def should_implement(interface)
    !to_clr_type.nil? && !to_clr_type.get_interface(interface).nil?
  end
end

>>> MyClass.should_implement "ISomething"
=> true

Bringing the power of Ruby to .NET is going to be incredible. It feels great clicking both the Ruby and .NET tags on a post. More on this to come…

Posted by Scott Sat, 21 Jun 2008 17:08:00 GMT


Javascript Gotchas Are Fun!

And by fun I mean "will make you bang your head against the wall repeatedly."

fail

Explanation here: http://www.jibbering.com/faq/#FAQ4_7

Posted by Scott Wed, 04 Jun 2008 20:28:00 GMT


Restful Routing with ASP MVC Preview 2

There is still very little documentation available for ASP MVC 2, and I had a bit of trouble finding out how to put HTTP method constraints on routes. After a bit of poking around I found out that the Method value was changed to httpMethod. I generally follow the convention that my controller is named the same as my resource. For instance, a resource named “Rates” would have a Rates controller. I use this little utility method to map the REST routes for the Rates resource.

Posted by Scott Tue, 15 Apr 2008 21:30:00 GMT


This Is Why Dreamhost Sucks

[eggnog]$ time ./dispatch.fcgi
real    2m48.176s
user    0m2.090s
sys     0m0.550s

And they want me to renew my hosting tomorrow.

Posted by Scott Thu, 28 Feb 2008 22:08:00 GMT


Playing Nice with Legacy Data

I was working with a database that had its own rules for pluralization and I wrote a quick hack to try to get ActiveRecord to play nice with their naming conventions. It still crashes and burns a lot, but it’s a work in progress.

module Inflector
  def pluralize(word)
    if (  word[-1..-1].downcase == 's' ||
          word[-1..-2].downcase == 'sh' ||
          word[-1..-2].downcase == 'ch' ||
          word[-1..-1].downcase == 'x'        
       )
      word << 'es'
    elsif word[-1..-1].downcase == 'y'
      if ['a', 'e', 'i', 'o', 'u'].include? word[-2..-2]
        word << 's'
      else
        word = word[0..word.length-2] << 'ies'
      end
    else
      word << 's'
    end
  end

  def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
    class_name
  end
end

class ActiveRecord::Base
  class << self
    def reset_primary_key #:nodoc:
      key = "#{base_class.name}ID"
      set_primary_key(key)
      key
    end

    private
    def undecorated_table_name(class_name = base_class.name)
      table_name = Inflector.pluralize(class_name)
      puts table_name
      table_name
    end
  end
end

It still needs a lot of work, but I think it will be pretty cool to get active record to make correct assumptions about table names and keys without explicitly defining them.

Posted by Scott Wed, 13 Feb 2008 23:54:00 GMT


Because it's better than text files

So I finally caved and made a blog. I found myself saving code snippets of cool things that I’d picked up in text files on whatever machine I happened to be working on. This brought on a few problems.

First, I am extremely unorganized, and would forget about (and soon after lose forever) the text file containing whatever gem of knowledge I had come across.

Second, a text file saved at work doesn’t help me much at home.

Third (theoretically) someone else out there might have some bizzare desire to read the contents of whatever text file I was in the process of losing.

Thus, this blog was born. I doubt anyone will ever read this, but if it does somehow end up serving a greater good than my personal online sticky note, all the better. Enjoy.

Posted by Scott Wed, 13 Feb 2008 23:21:00 GMT