Flowdock

Notes posted to Ruby

RSS feed
May 4, 2009 - (v1_8_6_287)
2 thanks

NoMethodError: undefined method `each_char'

For some reason the each_char method on String is not available by default in Ruby 1.8.6 and you will be presented with a NoMethodError.

You can resolve this by requiring the jcode lib:

require 'jcode'
May 4, 2009
1 thank

clarification

Via Kenneth Kalmer:

From the man page: If salt is a character string starting with the characters “$id$” followed by a string terminated by “$”: $id$salt$encrypted then instead of using the DES machine, id identifies the encryption method used and this then determines how the rest of the password string is interpreted.

irb session

=>abNANd1rDfiNc”
irb(main):002:0>secret”.crypt(”abasasa”)
=>abNANd1rDfiNc”
irb(main):003:0>secret”.crypt(”$1$abasasa”)
=>$1$abasasa$2RZY2vd6E2ZEPSDa0eLec0″
irb(main):004:0>secret”.crypt(”$1$abasa”)
=>$1$abasa$ikoKICgwOFdcWgmDl9Asy1″

see http://www.opensourcery.co.za/2009/05/01/quick-nix-shadow-passwords-with-ruby/

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
4 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 30, 2009
1 thank

For specific entries, use Dir.glob

When working with the contents of a directory it’s not uncommon to be interested in a specific subset of the entries present.

Dir.glob can be used to fetch entries by name and File.stat can be used to determine the type of file.

April 24, 2009
0 thanks

test

I need that program :)

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
0 thanks

See Also: IO Class Methods

There are other more specific methods defined in the IO class: IO.open for files, IO.popen for pipes.

April 23, 2009
1 thank

Customize Formatting with a Subclass

Instead of passing in a formatter block, you can always create a subclass that defines the format:

require 'logger'

class MyLogger < Logger
  def format_message(severity, datetime, progname, msg)
    "[%s %s] %s\n" % [ severity, datetime.strtftime("%H:%M"), msg ]
  end
end

This can be easier than always passing the same formatter option.

April 23, 2009
2 thanks

Rails and Ruby 1.8.7 Extensions

Note that the use of Symbol#to_proc requires either Rails or Ruby 1.8.7. Prior versions will show:

['a', 'b', 'c'].collect(&:capitalize)
 #  => TypeError: wrong argument type Symbol (expected Proc)
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
1 thank

Extracting the First Element

To extract the first element from an Array, use shift:

array = [ 1, 2, 3 ]           # => [ 1, 2, 3 ]
array.first                   # => 1
array                         # => [ 1, 2, 3 ]
array.shift                   # => 1
array                         # => [ 2, 3 ]
April 16, 2009
1 thank

Extracting the Last Element

To remove the last element from the Array, use pop:

array = [ 1, 2, 3 ]           # => [ 1, 2, 3 ]
array.last                    # => 3
array                         # => [ 1, 2, 3 ]
array.pop                     # => 3
array                         # => [ 1, 2 ]
April 16, 2009
15 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|
end

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)|
end

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

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
1 thank
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.