Strange Symphonies The best way to predict the future is to invent it

7Feb/090

Bookmarking Directories in Bash

Well not in the same sense as bookmarking in your web browsers. But what it does do is make it easy to jump to the many directories that you may commonly visit.

[block:important]I'm no pro at bash, but this is a simple solution I came up with and thought others may benefit from it.[/block]

Some directories I would may occasionally visit:

  • /opt/local/lib/ruby/gems/1.8/gems/
  • /Users/aizat/src/projectA
  • /User/aizat/src/companyB/projectC
  • /User/aizat/src/companyB/projectD

I may use the bash expansion ~/ to easily go to my home directory, but I'm still rather limited in what I can access.

So here is a simple gem you can place in either your ~/.bashrc, or ~/.bash_profile
[block:file]

function bookmark {
  case "$1" in
    projectA)  pushd /Users/aizat/src/projectA ;;
    projectC)  pushd /Users/aizat/src/companyB/projectC ;;
    projectD)  pushd /Users/aizat/src/companyB/projectD ;;
    gems)      pushd /opt/local/lib/ruby/gems/1.8/gems ;;
    *)           echo "forgot something?" ;;
  esac
}

[/block]

Replace as required with your own directories, but don't remove the line with the asterisk!

Before you start using the function, you have to either start a new bash session, terminal, or execute source ~/.bash_profile. Which ever fancies you.

So in your bash session, try it out.
[block:terminal]
bookmark projectA
bookmark gems
bookmark projectC
bookmark projectB
[/block]

Now you can easily jump directories in convenience! But wait, oops! Did you accidently go to the wrong project? Want to easily go back to your previous directory? No problem. Since we used pushd, its as easy as a popd away!

Don't forget tab completion, so you don't have to type the code bookmark command!

[block:important]Know something even more convenient? Do share![/block]

Tagged as: No Comments
19Nov/070

autotest-ting your Rails Application with Visual and Audio Feedback using Growl and mpg321

autotest is a commandline tool that comes packaged together with ZenTest. Designed to continually test your Rails application, autotest makes a slight notch easier by removing the need to repeatedly call the rake task to run your application's various tests.

Note: autotest is not limited to the default Ruby Test::Unit::TestCase. It will even work out of the box with RSpec.

Installing autotest

autotest is actually in the ZenTest gem.

sudo gem install -y ZenTest

Go to your application root directory and run autotest and watch it go!

autotest

Dead simple right? But still slightly irritating having to switch back to the terminal to see the results of test. So lets spruce it up a little, lets make it notify us of the results.

Visual Feedback with Growl

Growl is a notification that is over layed on top of your desktop, so that other applications are able to notify/inform you of anything, generally updates. For example Adium uses it to notify you of people logging in or out.

Note: Growl is a Mac OS X application. For other platforms you'll have to look at integration with their notification apps, for example knotify, or gnome-notification.

Combined together with Growl, you will continuously be notified of the current status of your test suite through a nice non disruptive interface. Thus helping to ensure the integrity of your code base.

Installing Growl

Download Growl and install it. But don't eject the Disc Image yet. We have to install the growlnotify command as well. This has to be done via the command line, so pull up your Terminal again.

We need to find out where Growl has been mounted to.

mount | grep -i growl

Possible Result:

/dev/disk2s2 on /Volumes/Growl 1.1.2 (local, nodev, nosuid, read-only, mounted by aizat)

From here you can see it has been mounted on /Volumes/Growl 1.1.2. Now go back to your Terminal, and we'll install growlnotify.

cd "/Volumes/Growl 1.1.2/"
cd Extras/growlnotify
sudo ./install.sh

By default growlnotify is installed into /usr/local/bin, your applications may not be able to see that this exists. So let's find out.

Execute:

which growlnotify

Desired Result:

/usr/local/bin/growlnotify

Possible Result:

no growlnotify in /opt/local/bin /opt/local/sbin /usr/local/bin /bin /sbin /usr/bin /usr/sbin

We want the desired result, so what do you do if you don't get it?

echo "export PATH=/usr/local/bin:$PATH" >> ~/.bashrc

Now growlnotify is accessible by all new Terminal sessions.

Let's give it a shot, and test out Growl!

growlnotify -m "Hey <a href="http://en.wikipedia.org/wiki/Tony_the_Tiger">Tony</a>, isn't this just grrrrrrreat?

Integrating Growl with autotest

We need to create a .autotest (yes with the period) file in your home directory.

touch ~/.autotest
open ~/.autotest

Now stuff this in there!

module Autotest::Growl

  def self.growl title, msg, img, pri=0, sticky=""
    system "growlnotify -n autotest --image #{img.inspect} -p #{pri} -m #{msg.inspect} #{title} #{sticky}"
  end

  Autotest.add_hook :ran_command do |at|
    results = [at.results].flatten.join("\n")
    output = results.slice(/(\d+)\s+examples?,\s*(\d+)\s+failures?(,\s*(\d+)\s+not implemented)?/)
    if output
      if $~[2].to_i > 0
        growl "Test Results", "#{output}", File.join(ENV['HOME'], %w[Library Application\ Support autotest rails_fail.png]), 2
      else
        growl "Test Results", "#{output}", File.join(ENV['HOME'], %w[Library Application\ Support autotest rails_ok.png])
      end
    end
  end

end

Note: Adapted from Wincent Knowledge Base. I also took the personal liability to move files to the ~/Library/Application Support/ directory as I thought it would be more appropriate. Your choice, just change as desired.

Now for the final touch, the elusive images!

mkdir -p ~/Library/Application\ Support/autotest
cd ~/Library/Application\ Support/autotest
curl -O http://blog.internautdesign.com/files/rails_fail.png
curl -O http://blog.internautdesign.com/files/rails_ok.png

Note: If you want, you can even change the images to whatever you want yourself, just change lines 12 and 14 to point to the image location.

autotest-ing

Now go to the root directory of your Rails application, and simply execute:

autotest

and you should soon be notified of the results of your test.

Note: You can further customize Growl in the System Preferences!

Audio Feedback

Visual feedback is cool, but it would be even more awesome if it had audio feedback to accompany it.

Note: This method is cross platform.

This was first described on FozWorks (read on how to Install)

As I aggregated my autotest images into the ~/Library/Application Support/autotest directory, I thought I'd dump the sound files in there as well. Just pay attention when you have to modify your ~/.autotest to accommodate the different path.

The only disappointment with the default sounds they provide is that, they are a little bit soft, and is often drowned out by my music player. But no worries, you can decide to use your own effects, or if your like me, increase the gain with Audacity.

In the mean time, anyone have some interesting replacement sound effects?

1Jun/070

Ruby and Open Classes

When I introduce people to Ruby (at least to programmers) I tend to highlight the differences between Ruby and established programming languages, such as Java, PHP, and C/C++. I opt highlight the differences because at least all (if not those that based around C) generally have the same structure, with regards to conditions, loops, etc.

Note: The intention is not to create a flame war, or to do any bashing

Disclaimer: Out of the listed programming languages, my strength is primarily in PHP, so if I am wrong about something, do bring it up! It will make for a good discussion, and I'll learn something new.

Note: If you are unfamiliar with Ruby, the last statement in Ruby is always returned. You can opt to use a return statement, but why? Especially when you expect the method to return something.

Classes are Open

Ruby is unique in that classes are open. Generally once you close off those brackets in that class your writing, you can't continue adding methods to it. In Ruby you can. You can extend (not in the same way as inheritance) a class once it's been "closed".

You can also extend Ruby's core classes, such as String, Hash, Numeric, Fixnum, etc.

Example: Sanitizing a String

Say for instance you want to sanitize a string of all non alphanumeric characters. Let's say the definition of sanitize, is to replace all non alphanumeric characters with an underscore.

In PHP, you'd probably have to do this:

function sanitize_string($string) {
  return preg_replace('/[^[:alnum:]]/+', '_', $string)
}

echo sanitize_string("Let's sanitize this string baby")

In Ruby, you can do this:

class String
  def sanitize
    self.gsub(/[^[:alnum:]]+/, '_')
  end
end

puts "Let's sanitize this string baby".sanitize

Now which one seems more intuitive?

In PHP we are calling a separate function entirely, that may operate on any variable type. This can be improved in several ways: Adding error checking code. Following PHP naming conventions for String functions, and call it strsanitize.

In Ruby we are basically redeclaring a new method for the String class, which operates on itself.

Example: Getting a Random Element from an Array

PHP already comes with a function to do precisely this: array_rand.

Sadly Ruby doesn't, but hey. Let's plug it in!

class Array
  def rand
    self[Kernel::rand(self.size)]
   end
end

Example: Easier Time Calculations

class Numeric
  def seconds
    self
  end
  alias :second :seconds

  def minutes
    self * 60
  end
  alias :minute :minutes

  def hours
    self * 60.minutes
  end
  alias :hour :hours

  def days
    self * 24.hours
  end
  alias :day :days

  def weeks
    self * 7.days
  end
  alias :week :weeks
end

Note: the alias statement allows us to easily duplicate a method, so I'm just duplicating them here to make singular representations

1.second # 1
1.minute # 60
7.5.minutes # 450.0
3.hours # 10800
10.75.hours # 38700
24.hours # 86400
31.days # 2678400
101.days # 8726400
51.weeks # 30844800
365.days # 31536000
15.minutes + 3.days + 4.hours # 274500

Cool eh?

Well lets extend it once again to give us the time in relation to now.

class Numeric
  def ago(time = Time.now)
    time - self
  end
  alias :until :ago

  def since(time = Time.now)
    time + self
  end
  alias :from_now
end

So now we'll be using the core class Time, which when used with the addition and subtraction methods removes seconds from the time.

Time.now # Thu May 31 23:46:44 0800 2007
5.minutes.ago # Thu May 31 23:41:44 0800 2007
20.minutes.from_now # Thu June 1 00:06:44 0800 2007
2.hours.since(4.hours.ago) # Thu May 31 17:21:09 0800 2007

Note: Ruby on Rails actually uses this to extend much of the functionality not found by default in the Ruby core classes. They are packaged inside ActiveSupport, and are called Core Extensions. These blocks of code is the same as found in ActiveSupport. (activesupport/lib/active_support/core_ext/numeric/time.rb File)

The Rails Way

To achieve the simplicity found in Rails, Rails extends alot of Ruby's core classes as seen above. Have a look into activesupport/lib/active_support/core_ext/ File. As of ActiveSupport v1.4.2 there are 63 files, providing a plethora of methods that make life easier.

Advance Example: Extending ActiveRecord

Lets pull out the big guns now and see how to extend ActiveRecord.

The convention in Rails is to put things in name space. In this I'll use an Aizatto namespace inside ActiveRecord (ActiveRecord::Aizatto). Similarly they tend to separate the class methods and instance methods into two different modules. Giving them a unique namespace each.

So here is a rough skeleton for you to work with and see how things go:

module ActiveRecord
  module Aizatto
    def self.included(base)
      base.extend ClassMethods
      base.class_eval do
        include InstanceMethods
      end
    end

    module ClassMethods
      def acts_as_aizatto
        logger.warn "Why would you want to do that?"
      end
    end

    module InstanceMethods
    end
  end
end

ActiveRecord::Base.send :include, ActiveRecord::Aizatto

Conclusion

Well thats the basics of Open Classes in Ruby. As can be seen open classes makes it easier to introduce new methods to existing Classes (even core classes), to add any additional methods. Sadly there isn't really much else for me to discuss here, so enjoy!