The second day of Ruby picks up the pace a bit, mostly focussing on the nice bits of sugar that Ruby provides and the excercises give you a chance to play with them a bit.
fileio.rb
Find out how to access files with and without blocks.
#!/usr/bin/ruby -w
# without block
counter = 1
file = File.new("eg_file.txt", "r")
while (line = file.gets)
puts "#{counter}: #{line}"
counter = counter + 1
end
file.close
# with block
counter = 1
File.open("eg_file.txt", "r") do |infile|
while (line = infile.gets)
puts "#{counter}: #{line}"
counter = counter + 1
end
end
# with Exception Handling
counter = 1
begin
file = File.new("eg_file.txt", "r")
while (line = file.gets)
puts "#{counter}: #{line}"
counter = counter + 1
end
file.close
rescue => err
puts "Exception: #{err}"
err
end
# using each block
counter = 1
f = File.open("eg_file.txt","r")
f.each do |line|
puts "#{counter}: #{line}"
counter = counter + 1
end
f.close
h_to_a.rb
How would you translate a hash to an array? Can you translate arrays to hashes
Wow this was a bit of a killer. There is a function called in ruby 1.9 that does what I would do to convert a hash into an array — unrolling it. But Debian Squeeze's ruby is still at 1.8. So I had to make a flatten.
#!/usr/bin/ruby
# in 1.9 you can just
# h.flatten # => [1, "one", 2, [2, "two"], 3, "three"]
# Here I have to roll my own.
class Hash
def flatten()
arr = []
self.map { |k,v| arr.push(k); v.class=="Hash" ? arr.push(v.flatten) : arr.push(v); }
arr
end
end
h = {1=> "one", 2 => [2,"two"], 3 => "three"}
a = h.flatten
puts a.join(', ');
sixteen_four.rb
Print the contents of an array of sixteen numbers, four numbers at a time using just each. Now do the same with each slice in Enumerable.
I wasn’t sure that this was the most compelling bit of syntax to illustrate the Poppins-like magic of Ruby, but had a crack anyway.
#!/usr/bin/ruby
# print array of 16 numbers, 4 at a time
a = []
16.times {|i| a[i]=i}
# using only each
[0,4,8,12].each{|i| puts a[i..i+3].join(', ')}
# same thing using each_slice
a.each_slice(4){|x| puts x.join(", ") }
Tree.rb
The Tree class was interesting, but it did not allow you to specify a new tree with a clean user interface. Let the initializer accept a nested structure with hashes and arrays. You should be able to specify a tree like this
I spent a while regretting that I wasn’t doing this excercise in Perl, mostly due to the rustiness of my Ruby skills.
#!/usr/bin/ruby
class Tree
attr_accessor :children, :node_name
def initialize (h={})
@node_name = h.keys.first
@children = []
h[@node_name].each {|node,value| @children.push Tree.new({node=>value}) }
end
def visit_all(&block)
visit &block
@children.each{|n| n.visit_all &block}
end
def visit(&block)
block.call self
end
end # class
t=Tree.new( { 'Ruby' => {'sub1' => {}, 'sub2' => {} } } )
puts "Tree first node visit"
t.visit {|node| puts node.node_name}
puts
puts "Tree visit all nodes"
t.visit_all {|node| puts node.node_name}
Write a simple grep that will print the lines of a file having any occurences of a phrase anywhere in that line. … If you want include line numbers.
After faffing to make the Tree code in the previous excercise run as expected, this excercise seemed rather straightforward.
#!/usr/bin/ruby
#
# prints lines of file which match a regexp given as an argument
unless ARGV.length == 2
puts "Two arguments required"
exit 1
end
f = File.open(ARGV[1],"r")
counter = 1
f.each do |line|
puts "#{ARGV[1]} #{counter}: #{line}" if (line =~ /#{ARGV[0]}/)
counter = counter + 1
end
f.close