Flowdock

Notes posted to Ruby

RSS feed
April 16, 2009
0 thanks

Known unknowns

In case it isn’t obvious - this is what you use when you’re fleshing out all the tests that you haven’t written yet. eg if you have a set of twenty tests for a complex piece of functionality, and just want to write out the “should” declarations (or equivalent), so you don’t forget all the corner cases… then fill out the tests themselves. Putting an assert_fail makes sure you notice if you forget to come back and fill in the body of a test.

April 1, 2009
1 thank

Returns the element, not block result

Enumerable#find will always return the element that is found, not the result of the block provided.

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 31, 2009
0 thanks

Input for trigonometric functions must be radians

You must use radians to have the right result. For example to compute the sin of 125 degrees use:

Math.sin(125*Math::PI/180)

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 27, 2009
0 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 26, 2009
0 thanks
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.

March 12, 2009
1 thank

Comparing Date with Numeric in mixed sort

While:

Date#<=>(other) 

can accept a Numeric object as other, the reverse is not true:

Numeric#<=>(other) 

cannot accept a Date object as other.

So if you are sorting a list containing a mix of dates and numbers, you can get different results depending on the starting order!

a = Date.parse("2008-01-01")
b = Date.parse("2009-10-22")
c = Date.parse("2005-01-04")
d = 0

[a,b,c,d].sort #=> [0, Tue, 04 Jan 2005, Tue, 01 Jan 2008, Thu, 22 Oct 2009]

[b,c,d,a].sort #=> ArgumentError: comparison of Fixnum with Date failed
March 12, 2009 - (v1_8_6_287 - v1_8_7_72)
1 thank

Autopad Numbers with Zeros (0s)

Here’s a handy code for padding 0s in a string. This is useful when you need to generate numbers for forms, such as invoices or orders. For example, you want to turn an invoice number 12345 to 0012345:

$ irb

>> s = "0000000"
=> "0000000"

>> num = "12345"
=> "12345"

>> s.insert(-(num.to_s.length + 1), num.to_s)[0, s.length - num.to_s.length] if num.to_s.length <= s.length
=> "0012345"
March 5, 2009
7 thanks

String#match will match single token only

>> s = “{{person}} ate {{thing}}”

> “{{person}} ate {{thing}}”

>> r = /{{(.*?)}}/

> {{}}

>> s.match®.captures

> [“person”]

Using String#scan pulls out all tokens you were searching for:

>> s.scan®.flatten

> [“person”, “thing”]

March 3, 2009
9 thanks

File class documentation

Most of the File class documentation is located in IO class docs. What you see here is what ‘ftools’ gives you.

February 28, 2009
0 thanks

Exceptions while debugging

If the error wasn’t stored in a variable, you can still see it by looking at the global variable $ERROR_INFO.

February 28, 2009
1 thank

rescue

Store exceptions using ‘rescue => var’

begin                              
  x = factorial(-1)             
rescue => ex                       
  puts "#{ex.class}: #{ex.message}"
end                                
February 25, 2009
0 thanks

Always a String

Remember that even if you ask for one field that is a number, a String will be returned:

Time.now.strftime("%j") #=> "055"
February 24, 2009
2 thanks

Test if one array includes the elements of another v2

Maybe a bit more readable way to write the previous snippet would’ve been

puts "yay" if [1, 2, 3].all? { |i| (1..9).include?(i) }
# => "yay"

puts "nope" if [1, 2, 3, 'A'].any? { |i| not (1..9).include?(i) }
# => "nope"
February 24, 2009
0 thanks

Test if one array includes the elements of another

Recently I’ve written this little snippet:

puts "yay" if [1, 2, 3].each {|i| break unless (1..9).to_a.include?(i)}
# => "yay"

puts "nope" unless [1, 2, 3, 'A'].each {|i| break unless (1..9).to_a.include?(i)}
# => "nope"
February 16, 2009
1 thank

See max

See max for comments and more usage examples.

February 16, 2009
2 thanks

Capping values

This method is very useful when you want to cap values:

# minimum ≤ value 
value = [input.to_i, minimum].max

# value ≤ maximum
value = [input.to_i, maximum].min

# minimum ≤ value ≤ maximum
value = [ [input.to_i, minimum].max, maximum ].min

# Practical example: Make sure destination is within container
destination.x = [ [current.x + current.velocity.x, 0].max, container.width  ].min
destination.y = [ [current.y + current.velocity.y, 0].max, container.height ].min
February 16, 2009
5 thanks

Usage example

Some examples:

# Remove even numbers
(1..30).reject { |n| n % 2 == 0 }
# => [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29]

# Remove years dividable with 4 (this is *not* the full leap years rule)
(1950..2000).reject { |y| y % 4 != 0 }
# => [1952, 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000]

# Remove users with karma below arithmetic mean
total = users.inject(0) { |total, user| total += user.karma }
mean = total / users.size
good_users = users.reject { |u| u.karma < mean }
February 12, 2009
4 thanks

Real life use

If you’re wondering what the base64 format is used for, here are some examples:

  • HTTP Basic authentication: encode your username and password as one string, and add it as a header of an HTTP request. When a page requiring basic authentication gets called from a browser it results in a generic Username/Password dialog from that browser. See also http://en.wikipedia.org/wiki/Basic_access_authentication

  • Encode the binary content of images to base64 and embed it in XML documents, for example in web services

  • For more information see http://en.wikipedia.org/wiki/Base64

Just note that the encoded (character) data is about 30% larger than un-encoded (binary) data.

February 12, 2009
4 thanks

Binary files

Another real important flag is b when dealing with binary files. For example to download an mp3 from the internet you need to pass the b flag or the data will be screwed up:

# Downloads a binary file from the internet
require 'open-uri'
url = "http://fubar/song.mp3"
open(url, 'rb') do |mp3|
  File.open("local.mp3", 'wb') do |file|
    file.write(mp3.read)
  end
end

Don’t say you haven’t been warned. :)

February 12, 2009
3 thanks

Other regular-expression modifiers

Likewise you can set Regexp::IGNORECASE directly on the regexp with the literal syntax:

/first/i
# This will match "first", "First" and even "fiRSt"

Even more modifiers

  • o – Perform #{} interpolations only once, the first time the regexp literal is evaluated.

  • x – Ignores whitespace and allows comments in * regular expressions

  • u, e, s, n – Interpret the regexp as Unicode (UTF-8), EUC, SJIS, or ASCII. If none of these modifiers is specified, the regular expression is assumed to use the source encoding.

Literal to the rescue

Like string literals delimited with %Q, Ruby allows you to begin your regular expressions with %r followed by a delimiter of your choice.

This is useful when the pattern you are describing contains a lot of forward slash characters that you don’t want to escape:

%Q(http://)
# This will match "http://"
February 12, 2009
4 thanks

Literal syntax

As you propably know you can create an Array either with the constructor or the literal syntax:

Array.new == []
# => true

But there is also another nice and concise literal syntax for creating Arrays of Strings:

["one", "two", "three"] == %w[one two three]
# => true

You can use any kind of parenthesis you like after the %w, either (), [] or {}. I prefer the square brackets because it looks more like an array.

February 12, 2009
2 thanks

Use this!

You should raise your own ArgumentError in methods to notify users of your class, if you think certain kinds of arguments aren’t acceptable.

def transfer_money(amount)
  unless amount.is_a?(Number)
    raise ArgumentError.new("Only numbers are allowed")
  end
  # ... Do the actual work
end
February 12, 2009
3 thanks

Useful scenario

This can be quite useful, for example when writing a command line script which takes a number of options.

Example

Let’s say you want to make a script that can make the basic CRUD operations. So want to be able to call it like this from the command line:

> my_script create
> my_script delete

The following script allows you to use any abbreviated command as long as it is unambiguous.

# my_script.rb
require 'abbrev'

command = ARGV.first
actions = %w[create read update delete]
mappings = Abbrev::abbrev(actions)
puts mappings[command]

That means you can call it like this:

> my_script cr
> my_script d

And it will print:

create
delete
February 10, 2009
0 thanks

Cheat Sheet

I have written a short introduction and a colorful cheat sheet for Perl Compatible Regular Expressions (PCRE) as used by Ruby’s Regexp class:

http://www.bitcetera.com/en/techblog/2008/04/01/regex-in-a-nutshell/

February 10, 2009
0 thanks

Cheat Sheet

I have written a short introduction and a colorful cheat sheet for Perl Compatible Regular Expressions (PCRE) as used by Ruby’s Regexp class:

http://www.bitcetera.com/en/techblog/2008/04/01/regex-in-a-nutshell/

February 10, 2009
3 thanks

Cheat Sheet

I have written a short introduction and a colorful cheat sheet for Perl Compatible Regular Expressions (PCRE) as used by Ruby’s Regexp class:

http://www.bitcetera.com/en/techblog/2008/04/01/regex-in-a-nutshell/

February 10, 2009
0 thanks

Output format

This outputs date & time in format of yyyy-MM-ddThh-mm-ssZZZ. All values are preceded with 0 if less than 10. Hours are in 0..23 range. Timezone is sticked at the end. Watch out for capital T in the middle :)