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]
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?
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
)
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/
. 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!
