Previous Next Table of contents

7. Builtin libraries

7.1 What is the return value of instance_methods(nil)?

The method instance_methods returns an array of the methods of an object, whereas instance_methods(nil) returns the methods which are defined in the class of the object, excluding the methods inherited from superclasses.

7.2 Why does rand generate the same random number sequence?

rand generates the same sequence every time the script runs. You need to give a different seed by srand to generate different random numbers every time. srand called without an argument makes the seed as the time being, and generates different random numbers.

7.3 How can I choose 5 different numbers between 0 and 51 randomly?

Next method returns an array containing m randomly chosen numbers between 0 and n.
def sample(n, m)
  if m.zero?
    []
  else
    s = sample(n-1, m-1)
    t = rand(n+1)
    s.concat s.include?(t) ? n : t
  end
end
To write it in non-recursive iterated form,
def sample(n, m)
  s = []
  ((n-m)...n).each do |j|
    t = rand(j+2)
    s.concat s.include?(t) ? j+1 : t
  end
  s
end

7.4 As Fixnum, true, nil, and false are implemented as immediate values, what is the difference between an immediate value and a reference?

Singleton methods cannot be defined for such objects implemented as immediate values. Two Fixnums of the same value are always the same instance, so when instance variables are defined, they point the same objects.

7.5 What is the difference between nil and false?

The difference of the methods nil and false is shown by executing nil.methods - false.methods and false.methods - nil.methods.

In a Hash, nil cannot be a value, but false can.

It is recommened that a method returns true or false if it is a predicate, and a value or nil otherwise.

A method with suffix ? is usually a predicate, but some built-in functions are not.

7.6 I read a file and changed the content, but the file does not change.

open("example", "r+").readlines.each_with_index{|l, i|
  l[0,0] = (i+1).to_s + ": "}
This script does not add line numbers to the file "example". It is because this script does not write to the file but only change the strings received from readlines. You must write back the result to the file.
io = open("example", "r+")
ary = io.readlines
ary.each_with_index{|l, i| l[0,0] = (i+1).to_s + ": "}
io.rewind
io.print ary
io.close

7.7 How can I read a file and replace it with new one?

Using command-line option -i, or built-in variable $-i, you can read a file and replace it.

The preceding quiz can be written as follows.
$ ruby -i -ne 'print "#$.: #$_"' example
If you want to reserve the original file, use -i.bak or whatever you like.

7.8 I wrote a file and copied the file, but the tail of the copied file is truncated.

open('file', 'w').print "This is a file.\n"
system 'cp file copy'
When copying the file in this script, the content is not yet flushed. You should close the file before copying.
f = open('file', 'w')
f.print "This is a file.\n"
f.close
system "cp file copy"

7.9 How can I use less to display strings?

f = open '|less', 'w'
f.print "abc\n"
This script ends immediately, and you cannot see less displaying. Use close to wait until less ends.
f = open '|less', 'w'
f.print "abc\n"
f.close
The first line can be written as f = IO.popen 'less', 'w'.

7.10 What occurs to a File object which has no reference?

A File object, which is not referred as in open("file").read, will be garbage collected in next GC, when it is closed.

7.11 I feel uneasy if I don't close a file.

If you want to close a file explicitly, choose one of following three syntax.
(1)
a = open "file"
begin
  a.each {|l| print l}
ensure
  a.close
end
(2)
IO.foreach("file") {|l| print l}
(3)
IO.readlines("file").each {|l| print l}

7.12 How can I sort files by their modified time?

Dir.glob("*").filter{|f| [File.mtime(f), f]}.
  sort{|a,b| b[0]<=>a[0]}.filter{|e| e[1]}
This script returns an array with the filenames sorted by the access time in reverse order. If you want to sort in straight order, you can omit the block of sort.
Dir.glob("*").sort{|a,b| File.mtime(b)<=>File.mtime(a)}
will give the same answer, but this script takes longer time because it accesses files each time it compares the modified time.

7.13 How can I count word frequency in a file?

Following script displays word frequency, designating Hash default value as 0.
freq = Hash.new(0)
open("file").read.scan(/\w+/){|w| freq[w] += 1}
freq.keys.sort.each {|k| print k, "--", freq[k], "\n"}

7.14 Null string ("") returns true in a condition expression.

In Ruby, only nil or false returns false condition. You can use empty? or compare the string to "" or compare length to 0 to find out if a string is empty.

7.15 How can I sort strings in alphabetical order?

The tip is to compare strings first using downcase and if equal then using original strings.

7.16 What does "abcd"[0] return?

It returns the character code for a, 97(Fixnum). Compare with ?a if you want to check it equal to the character a.

7.17 How can I expand tabs to spaces?

Suppose your string to be expanded in a, do either of following.
1 while a.sub!(/(^[^\t]*)\t(\t*)/){$1+' '*(8-$1.size%8+8*$2.size)}
1 while a.sub!(/\t(\t*)/){' '*(8-$~.begin(0)%8+8*$1.size)}
a.gsub!(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")}

7.18 How can I escape a backslash?

Regexp.quote('\\') escapes a backslash.

In gsub, if you write gsub(/\\/, '\\\\'), the second argument is analyzed as '\\' in syntax analysis and when the substitution occurs it is again analyzed as '\' which means to substitute one backslash to one backslash. You need to write gsub(/\\/, '\\\\\\'). Using the fact that \& expresses the match, you can write gsub(/\\/, '\&\&').

If you use the block form of gsub, i.e. gsub(/\\/){'\\\\'}, the string for substitution is analyzed only once and the result is what you intended.

7.19 What is the difference between sub and sub!?

In sub, a copy of the receiver is generated, substituted and returned.

In sub!, the receiver is altered and returned if any match was found. Otherwise, nil is returned.

Methods like sub! are called destructive methods which alter the attribute of the receiver. If there are two similar methods and one is destructive, the destructive one has a suffix ! to denote the destructiveness.
def foo(str)
    str = str.sub(/foo/, "baz")
end

obj = "foo"
foo(obj)
print obj
# -> "foo"

def foo(str)
    str = str.sub!(/foo/, "baz")
end

foo(obj)
print obj
# -> "baz"
Destructive methods like sub! sometimes return an unexpected result. Be careful.

7.20 Where does \Z match?

\Z matches just before the last \n if the string ends with a \n, otherwise it matches at the end of a string.

7.21 What is the difference between Range constructors .. and ...?

.. includes the right hand side in the range, ... does not.

7.22 Is there a function pointer?

A Proc object generated by Proc.new, proc, or lambda serves as a function pointer.

7.23 What is the difference between thread and fork?

Thread and fork have following characteristics. It is not recommended to mix fork and thread.

thread in Ruby is implemented by time sharing, dividing to threads does not gain the speed of execution.

7.24 How can I use Marshal?

Marshal is used to store an object in a file or a string, and later utilize it again. Storing is done this way.
Marshal.dump obj, io, lev
io is a writable IO object, lev designate the level to which referred objects are dereferred and stored. If lev levels of dereferring are done and still object referrences exist, then the dump of the object is only the referrence. It cannot be reconstructed when loaded.

Loading is done this way.
obj = Marshal.load io
or,
obj = Marshal.load str
io is a readable IO object, str is the dumped string.

7.25 Is there an exception handling?

Ruby supports an exception handling like other fore-running languages.
begin
  statements which may raise exceptions.
rescue [exception class name]
  statements when an exception occurred.
ensure
  statements to be done in the end.
end
If an exception occurs in the begin clause, rescue clause is executed. The ensure clause is executed whether an exception occurred or not. rescue and ensure claused can be omitted. If no exception class is designated for rescue clause, StandardError exception is implied, and exceptions which are in a is_a? relation to StandardError are captured.

This expression returns the value of the begin clause.

The latest exception is accessed by the global variable $!. The kind of exception is checked by $!.type.

7.26 How can I use trap?

trap("PIPE") {raise "SIGPIPE"}

Previous Next Table of contents