Good notes posted to Ruby

RSS feed
November 9, 2010
8 thanks

NOT Equivalent to Array#reject!

@tadman is wrong. There is a difference and, trust me, it can bite:

1.9.2 > [1,2,3,4].delete_if {|x| x > 10}
 => [1, 2, 3, 4] 
1.9.2 > [1,2,3,4].reject! {|x| x > 10}
 => nil 

That is, if reject! hasn’t rejected anything, it returns nil.

October 9, 2010
4 thanks

Be Advised

Also may convert original string into Jamaican.


"green moon".squeeze  #=> "gren mon"
July 29, 2010
4 thanks

Getting (n..end) reloaded

You can do

April 16, 2010
5 thanks

Require file from the same folder

If you want to require file from the same folder, the simplest way is

require File.expand_path('../file-to-require', __FILE__)

If your file is /lib/book.rb

File.expand_path('../page', '/lib/book.rb') => '/lib/page.rb'
March 31, 2010
3 thanks


Note that to interpolate, the sequences must be inside single quotes:

# replace /ll/ with itself
'hello'.gsub(/ll/, '\0') # returns 'hello'
'hello'.gsub(/ll/, "\0") # returns 'he\000o'
March 12, 2010
3 thanks

Complete Formatting Codes

NOTE: Some of these seem only to work for DateTime (e.g. %L, %N)

%a - The abbreviated weekday name (“Sun”)

%A - The full weekday name (“Sunday”)

%b - The abbreviated month name (“Jan”)

%B - The full month name (“January”)

%c - The preferred local date and time representation

%C - Century (20 in 2009)

%d - Day of the month (01..31)

%D - Date (%m/%d/%y)

%e - Day of the month, blank-padded ( 1..31)

%F - Equivalent to %Y-%m-%d (the ISO 8601 date format)

%h - Equivalent to %b

%H - Hour of the day, 24-hour clock (00..23)

%I - Hour of the day, 12-hour clock (01..12)

%j - Day of the year (001..366)

%k - hour, 24-hour clock, blank-padded ( 0..23)

%l - hour, 12-hour clock, blank-padded ( 0..12)

%L - Millisecond of the second (000..999)

%m - Month of the year (01..12)

%M - Minute of the hour (00..59)

%n - Newline (n)

%N - Fractional seconds digits, default is 9 digits (nanosecond)

  • %3N millisecond (3 digits)

  • %6N microsecond (6 digits)

  • %9N nanosecond (9 digits)

%p - Meridian indicator (“AM” or “PM”)

%P - Meridian indicator (“am” or “pm”)

%r - time, 12-hour (same as %I:%M:%S %p)

%R - time, 24-hour (%H:%M)

%s - Number of seconds since 1970-01-01 00:00:00 UTC.

%S - Second of the minute (00..60)

%t - Tab character (t)

%T - time, 24-hour (%H:%M:%S)

%u - Day of the week as a decimal, Monday being 1. (1..7)

%U - Week number of the current year, starting with the first Sunday as the first day of the first week (00..53)

%v - VMS date (%e-%b-%Y)

%V - Week number of year according to ISO 8601 (01..53)

%W - Week number of the current year, starting with the first Monday as the first day of the first week (00..53)

%w - Day of the week (Sunday is 0, 0..6)

%x - Preferred representation for the date alone, no time

%X - Preferred representation for the time alone, no date

%y - Year without a century (00..99)

%Y - Year with century

%z - Time zone as hour offset from UTC (e.g. +0900)

%Z - Time zone name

%% - Literal “%” character

t = Time.now                        #=> 2007-11-19 08:37:48 -0600
t.strftime("Printed on %m/%d/%Y")   #=> "Printed on 11/19/2007"
t.strftime("at %I:%M%p")            #=> "at 08:37AM"
March 3, 2010
3 thanks

Deprecated in 1.9.x!

Use FileUtils::copy instead. It is also in 1.8.x, FileUtils, so call that one instead.

March 3, 2010 - (>= v1_8_6_287)
4 thanks

makedirs(path) to create file path

mkdir will only create a single directory on an existing path. If you want to create a full path, like the `mkdir -p /full/path` command, use the makedirs method.

1.8: File.makedirs(path) 1.9: FileUtils.makedirs(path)

February 19, 2010
8 thanks


Note that the ActiveSupport library provides the except and except! methods, which return the Hash minus the given keys. So you don’t need to write your own wrapper if you happen to be using Rails or ActiveSupport as a stand-alone library:


February 5, 2010
3 thanks

Rmoving preceding 0's

In most *nix system, adding a - after the % will remove preceding 0s.

So %-d for a single digit day, or %-I for a single digit hour, etc.

January 27, 2010
3 thanks
November 23, 2009
3 thanks

Make directory if not exists

If the directory already exists, mkdir raises exception. To prevent this:

Dir.mkdir(dir) unless File.exists?(dir)
November 18, 2009 - (>= v1_8_6_287)
4 thanks



class Klass
  def set(string)
    var_name = "@#{string}"  # the '@' is required
    self.instance_variable_set(var_name, 'bar')
  def puts_foo
    puts @foo
k = Klass.new
k.puts_foo  # nil
k.puts_foo  # 'bar'
November 5, 2009
6 thanks

define_method with parameters

Just to be clear, you can do this:

define_method(:my_method) do |foo, bar| # or even |*args|
  # do something

This means same as:

def my_method(foo, bar)
  # do something

If you want to define method with parameters that have default values, you need to get a bit more creative and do something like this:

define_method(:my_method) do |foo, bar|
  bar ||= {}
  # do something
October 20, 2009
3 thanks

See Dir#glob

See glob for more usage information and comments.

October 7, 2009
4 thanks


Here’s a small helper for doing the “opposite” of this method:

class Hash
  def without(*keys)
    cpy = self.dup
    keys.each { |key| cpy.delete(key) }

h = { :a => 1, :b => 2, :c => 3 }
h.without(:a)      #=> { :b => 2, :c => 3 }
h.without(:a, :c)  #=> { :b => 2 }
August 20, 2009
3 thanks


@tadman - or simply defining:

class Symbol
  def to_proc
    proc { |obj, *args| obj.send(self, *args) }
July 8, 2009 - (<= v1_8_7_72)
5 thanks

Using block version in Ruby < 1.8.7

The block usage was added in 1.8.7, so to get the same functionality in an earlier version of Ruby, you need to utilize the find method.

Here is a quick example:

match = list.find { |l| l.owner == myself }
match_index = list.index(match)

If you do some gymnastics, you can have it on one line without extra variables:

match_index = list.index(list.find { |l| l.owner == myself })
July 1, 2009
4 thanks


User = Struct.new(:name, :phone)

marc = User.new(“Marc”, “555-5555”)

May 13, 2009
3 thanks

Equivalent to Array#reject!

This method is functionally identical to Array#reject!

May 2, 2009
8 thanks

Create a Hash from two Arrays

Here is my favorite idiom for creating a Hash from an Array of keys and an Array of values:

keys = [:a, :b]
values = [1,2]
h = Hash[*keys.zip(values).flatten]      # => {:b=>2, :a=>1}
May 2, 2009
3 thanks

Test if one array includes the elements of another

You can just use a set difference (aka minus) to see if one array includes all elements of another

not_included = [1,2,3] - (1..9).to_a
not_included      # => []

not_included = [1,2,3,'A'] - (1..9).to_a
not_included      # => ["A"]

Use intersection to test if any of the one are in the other:

shared = [1,2,3,'A'] & (1..9).to_a
shared     # => [1, 2, 3]
April 23, 2009
5 thanks
April 23, 2009
6 thanks

Argument Ordering

Be aware that the order of arguments for this method is the opposite of File.join:

File.expand_path('foo', '/bar')   # => "/bar/foo"
File.join('foo', '/bar')          # => "foo/bar"
April 23, 2009
5 thanks

Handy shorthand for array manipulation

You may write something like this:

>> ['a', 'b', 'c'].collect{|letter| letter.capitalize}
=> ["A", "B", "C"]

But it looks so much nicer this way:

>> ['a', 'b', 'c'].collect(&:capitalize)
=> ["A", "B", "C"]
April 21, 2009
3 thanks

To throw an exception, use Kernel#raise

Other languages use the term throw for raising exceptions, but Ruby has a specific raise call for that.

April 16, 2009
12 thanks

Parameters for Hash#inject

When running inject on a Hash, the hash is first converted to an array before being passed through.

The typical Enumerable#inject approach would be to simply capture the value:

array.inject(...) do |c, v|

In the case of a Hash, v is actually a key/value pair Array. That is the key is v.first and the value is v.last, however using the pair this way is awkward and can lead to confusion.

Better to simply expand the parameters in the block definition:

hash.inject(...) do |c, (k, v)|

Where c is the traditional carry variable and k/v represent key and value respectively.

March 31, 2009
3 thanks

Sorting Hashes with Symbol Keys

To sort a hash with symbol keys, use Enumerable#sort_by:

h = { :a => 20, :b => 30, :c => 10  }
h.sort                       # => NoMethodError: undefined method `<=>' for :a:Symbol
h.sort_by { |k,v| k.to_s }   # => [[:a, 20], [:b, 30], [:c, 10]]
March 27, 2009
4 thanks

Hour with/without preceding zero

One gotcha is the difference between the hour in 12 hour time with and without a preceding zero. In some fonts they look the same.

With preceding zero (capital I)

Time.now.strftime("%I:%M") # => 05:21

Without preceding zero (lowercase L)

Time.now.strftime("%l:%M") # => 5:21
March 18, 2009
4 thanks

Better autopad numbers

There is a much better way than to use diwadn’s method if you want to pad numbers with zeros. Here’s my recommended way to do it:

"Number: %010d" % 12345 #=> "Number: 0000012345"

It’s very easy. First we begin our placeholder with “%”, then we specify a zero (0) to signify padding with zeros. If we omitted this zero, the number would be padded with spaces instead. When we have done that, just specify the target length of the string. At last a single “d” is placed to signify that we are inserting a number.

Please see String#% and Kernel#sprintf for more information about how to do this.

Here’s another example of how to do it:

12345.to_s.rjust(10, "0") #=> "0000012345"

See String#rjust for more information.

Any of these methods are a lot better than the method outlined below.