Ruby, Day 3
Last day on Ruby!
Retrospectively, I didn’t knew Ruby before (and I still don’t know much about it, admittedly), but it’s been fun.
I’m not a big fan after what I saw. I still find it a bit messy, but that’s maybe because I’m not used to it enough. The “you can rewrite anything and change basic behavior” is very nice, but I seriously wonder how many times it has bitten back developers. If someone rewrites one of the basic methods in a big codebase, I can only imagine the consequences, if you are luck enough to see them right away…
However, I enjoyed scripting with Ruby very much, and it was a good brainteaser to try to find the effective way of doing those things in a language I completely ignored so far.
Anyway, here is my last homework!
Do
So, the goal here is to modify a class that reads CSV files and add an each method that will perform a block on a CsvRow object, object that is to be written. This object should have its method_missing overwritten so that you can access columns as if they were methods:
module ActsAsCsv def self.included(base) base.extend ClassMethods end module ClassMethods def acts_as_csv include InstanceMethods end end module InstanceMethods def read @csv_contents = [] filename = self.class.to_s.downcase + '.csv' file = File.new(filename) @headers = file.gets.chomp.split(', ') file.each do |row| @csv_contents << row.chomp.split(', ') end end attr_accessor :headers, :csv_contents def initialize read end def each(&block) @csv_contents.each { |line| block.call CsvRow.new(@headers, line) } end end end class RubyCsv # no inheritance! You can mix it in include ActsAsCsv acts_as_csv end class CsvRow attr_accessor :headings, :values def initialize(headings, values) @headings = headings @values = Hash[headings.zip(values).map { |e| [e[0], e[1]] }] end def method_missing(name, *args) col = name.to_s @values[col] end end csv = RubyCsv.new csv.each { |row| puts row.two }
Ruby, Day 2
Find
#File IO without block #f = File.new("testfile", "r") #f.close #File IO with block, implicit call to f.close #File.open("testfile", "r") do |aFile| end #Hash to array h = { 1 => 2, "cat" => "tom" } a = h.to_a #Array to hash a = (1..10).to_a h = Hash[a.map { |i| [i, i * 2] } ] #Iterate through a hash h.each { |i| puts "#{i[0]} : #{i[1]}" } #Use array as stack a.push 19 a.pop #Arrays can be used as: stacks, sets, queues, dequeues, and fifos
Do
Print the content of an array of sixteen numbers, four numbers at a time, using just each. Now, do the same with each_slice in Enumerable:
#Using each (interesting fact: there is a closure on a here) a.each { |i| if i % 4 == 0 then puts "#{a[i-4..i-1]}" end } #Using each_slice a.each_slice(4) { |s| puts "#{s}" }
Rewrite the Tree class so it can be initialized with a nested structure with hashes and arrays:
#Initial code from the book class Tree attr_accessor :children, :node_name def initialize(name, children=[]) @children = children @node_name = name end def visit_all(&block) visit &block @children.each { |c| c.visit_all &block } end def visit(&block) block.call self end end t = Tree.new("Ruby", [Tree.new("Gem")]) t.visit_all { |t| puts "#{t.node_name}" }
Starting from that, this is what we want to be able to write:
Tree.new({ 'grandpa' => { 'dad' => { 'child 1' => {}, 'child 2' => {} }, 'uncle' => { 'child 3' => {}, 'child 4' => {} } } })
And here is my solution to it:
class Tree attr_accessor :children, :node_name def initialize(structure) structure.each do |key, value| @node_name = key @children = value.to_a.map { |e| Tree.new({ e[0] => e[1] }) } end end def visit_all(&block) visit &block @children.each { |c| c.visit_all &block } end def visit(&block) block.call self end end t = Tree.new({ 'grandpa' => { 'dad' => { 'child 1' => {}, 'child 2' => {} }, 'uncle' => { 'child 3' => {}, 'child 4' => {} } } }) t.visit_all { |t| puts "#{t.node_name}" }
Write a simple grep that will print the lines of a file having any occurrences of a phrase anywhere in that line. Use Regular Expressions and include line numbers:
regex = Regexp.new('sit amet') ln = 0 IO.foreach("TestGrep.txt") do |line| ln = ln + 1 puts "#{ln}: #{line}" if regex.match(line) end
Ruby, Day 1
It’s funny because I never learned Ruby, I never wanted to because dynamic languages don’t move me much, but so far it’s been quite fun.
First, a link to http://ruby-doc.org/docs/ProgrammingRuby/ that is the main reference to every question on that language.
I’m not going to run through all the exercises, but I will put solutions of those I found interesting to solve.
Print “This is sentence number 1” where the number 1 changes from 1 to 10:
(1..10).each { |i| puts "This is sentence number #{i}" }
Bonus problem: write a program that picks a random number (I will do between 1 and 1024, how geeky!). Let the player guess a number, telling the player whether the guess is too low or too high:
max = 1024 guess = -1 number = rand(max) + 1 puts "Guess a number from 1 to #{max}" until guess == number guess = gets.to_i puts "Number is greater than #{guess}" if number > guess puts "Number is lesser than #{guess}" if number < guess end puts "Well done!"
Seven Languages in Seven Weeks
A recently bought the book titles “Seven Languages in Seven Weeks”. The book has excellent reviews, and I have to say that in the list of languages it covers, I only have vague notions for some of them (Prolog, Clojure, Haskell), but absolutely no experience with any of them.
So, what I’m going to do is write my answers to the exercises on this blog, day by day (the book is divided by “days”) to keep track of my progress and findings. I started out by writing all of this in a text file for private use, but I figured that, after all, why not make it public?
This will probably look boring if you know any of these languages, but mind you that I have no experience whatsoever with nearly all of them.
So, let’s start with the very trendy Ruby!
Google Mail Ads
Just a fun thing that happened today: I was sending a mail in GMail, and noticed that the customized ads displayed something that could be considered “offensive” to me, in a fun way:
Mr. Google is lying. C# rocks!
