Programifications

A mashup of technical quirks

Large Numbers in Ruby

| Comments

When dealing with large numbers you can use an underscore (in place of a comma) to make the numbers more readable and easier to write.

1
2
dollars = 1_000_000.00
# =>  1000000.0

Difference Between Include and Extend in Ruby

| Comments

A common thing to do in ruby is to share functionality among classes. Since ruby doesn’t support multiple inheritance, we simply import code by mixing in modules. So instead of classes having a crazy inheritance tree, they can have includes and/or extends at the top of the class. But what is the difference between include and extend?

They both mix in functionality into a class, but they are added to different places. Include mixes functionality into instances of a class, whereas extend mixes functionality into a class itself.

Take a look at the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module Explosion
  def explode
    puts "BOOM!"
  end
end

class Dynamite
  include Explosion
end

Dynamite.new.explode # => BOOM!
Dynamite.explode # => NoMethodError: undefined method `explode'

class Bomb
  extend Explosion
end

Bomb.new.explode # => NoMethodError: undefined method `explode'
Bomb.explode # => BOOM!

And of course with ruby being dynamic and all, you can include and/or extend modules at run time

1
2
3
4
5
6
7
8
9
10
class Chemical;end;
Chemical.extend Explosion
Chemical.explode # => BOOM!

# Class#include method is private so we have to use a workaround
Chemical.include Explosion
# => NoMethodError: private method `include' called

Chemical.send(:include, Explosion)
Chemical.new.explode # => BOOM!

If you want more information on include and extend check out the following links:

Caching With Instance Variables

| Comments

A performance trick that I use a lot, especially in models, is memoizing methods that are expensive. Usually these are methods that hit the database, make external API calls, involve longs loops, etc. Suppose we have a model Song that has a genre column in the database and a method jazz that queries for all songs that have the genre jazz. The model would look something like this:

1
2
3
4
5
class Song < ActiveRecord::Base
  def jazz
    all(:conditions => {:genre => "jazz"})
  end
end

Now this looks all fine and dandy but what if that method gets called several times? It will cause a query every time and will slow down performance.

Memoization to the Rescue

We can trade space for time by saving the results in an instance variable. So the first time the method is called, a query to the database will be executed. However all subsequent calls to the method will not query the database and will just return the saved result. That would look like this:

1
2
3
4
5
class Song < ActiveRecord::Base
  def jazz
    @jazz ||= all(:conditions => {:genre => "jazz"})
  end
end

Clearing the cache!

A common problem with caching is forgetting to clear it. Whenever a new song gets added, deleted, or modified, we’re going to need to clear the @jazz instance variable so that when the jazz method is called, it will get those new songs. Easy enough, we can just add callbacks to clear the cache after saving. Check it out:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Song < ActiveRecord::Base
  after_save :clear_memoization
  after_destroy :clear_memoization

  def jazz
    @jazz ||= all(:conditions => {:genre => "jazz"})
  end

  private
  def clear_memoization
    @jazz = nil
  end
end

Enumberable#group_by

| Comments

So I have another boy on the way and I was trying to think up of names so I created a ruby script to pick a random name out of a file beginning with a letter that you provide as an argument. So you’d call the script like this:

1
2
ruby boy_name.rb s
=> Sylen
1
2
3
4
5
6
7
8
9
10
11
# using ruby 1.8.7

if ARGV.empty?
  puts "USAGE: ruby boy_name.rb <letter>"
  exit
end

file = File.open("boy_names.txt")
names = file.lines.to_a.group_by{|name| name[0,1]}
selected_names = names[ARGV[0].capitalize]
puts selected_names[rand(selected_names.size)]

What’s cool about it is this line

1
names = file.lines.to_a.group_by{|name| name[0,1]}

Enumberable#group_by will group elements in an array by the result of the block passed in. In this case, we’re grouping by the first letter.

1
2
%w{apple banana cucumber}.group_by{|fruit| fruit[0,1]}
=> #<OrderedHash {"a"=>["apple"], "b"=>["banana"], "c"=>["cucumber"]}>

Deleting Tags With Git

| Comments

You can list tags by running this:

1
git tag

Suppose we see a tag called v1.0.1 that we want to remove. We’d simply remove it like this:

1
2
git tag -d v1.0.1
git push origin :refs/tags/v1.0.1

The first line will remove the tag locally and the second line will remove the remote tag.

For Loops in the Terminal

| Comments

Recently I’ve had to retrieve information from a set of remote servers. Using the for loop in the terminal, I was able to get all the information I needed in one line which was very convenient. I used the following code snippet:

1
for i in 1 2 3 4 5 6 7 8; do echo "search$i"; ssh root@search$i 'ls -alhrt /ip/sphinx_index/production'; done

Enable Logging to Rails Console

| Comments

To have the rails log output to the console you can add this to your ~/.irbrc file:

1
2
3
4
5
6
7
8
9
require 'logger'

if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER')
  # for rails 2
  RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
elsif defined?(Rails)
  # for rails 3
  ActiveRecord::Base.logger = Logger.new(STDOUT)
end

This only enables the log on the machine you’re currently on. If you want to enable logging to the console as a project wide feature so that anyone who checks out the project and runs the console also gets logging, then you can put this in your environment.rb file (or an environment config file like development.rb):

1
2
3
if "irb" == $0
  ActiveRecord::Base.logger = Logger.new(STDOUT)
end

Deleting Branches With Git

| Comments

Suppose we have a remote and local branch called foo. To delete it locally, just run:

1
git branch -D foo

You can verify that it has been deleted by listing your local branches. To do that, run:

1
git branch

To delete the remote branch run:

1
git push origin :foo

To list all branches (including remotes) run:

1
git branch -a