Notes posted to Ruby
RSS feedNoMethodError: 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'
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/
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]
Find symlink target path
To find the target of a symlink, use File.readlink
For the filename use File.basename
File.basename provides what File.dirname omits.
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"
See Also: IO Class Methods
There are other more specific methods defined in the IO class: IO.open for files, IO.popen for pipes.
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.
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)
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"]
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.
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 ]
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 ]
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.
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.
Returns the element, not block result
Enumerable#find will always return the element that is found, not the result of the block provided.
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]]
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)
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
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
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.
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
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"
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”]
File class documentation
Most of the File class documentation is located in IO class docs. What you see here is what ‘ftools’ gives you.
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.