why attr_accessor

I keep bump into this problem, where I pick up some basic long ago, after a while, get too used to it and forgot the reason why something is done in a particular way.

If I have written about it, then I have a better understanding and longer memory. Like the collection_select method which I drawn a illustration and post about it sometimes ago, it stuck in my memory till now.

This idea is not really new, you learn by teaching, or at least write or blog about it. All that help to clarify your thought.

And so, to help me internalized the reason behind attr_accessor, I quickly googled and read thru this from stackoverflow, yet, am gonna write about it as a process of internalization. Ha.

You keep writing attr_accessor, one day you totally forgot why we did attr_accessor at the first place. Why attr_accessor?

class Human
  def name=(str)
    @name = str
  end
 
  def name
    @name
  end
end

You do that to assign variable to a value, then call the value. This is common repetitive task. Programming is all about eliminating repetitive tasks. So you can do this in ruby

class Human
  attr_reader :name
  attr_writer :name
end

where attr_reader replace name method part, and attr_writer replace the name=(str) method. Still, often attr_writer and attr_reader often come in pair, why not just do it in one step.

class Human
  attr_accessor :name
end

I created a diagram hopefully could better illustrate this in one glance.

Evolution of attr_accessor

Evolution of attr_accessor

That is it. Already felt that now this tie deeper into my memory.

require file from same directory in ruby

Requiring a file sitting in the same directory wouldn’t work with this

require 'something'

Seems like Ruby 1.9 remove current directory from load path as I read from Stackoverflow

To make it work you could

require './something'

or use require_relative,

require_relative 'something'

The thing is,

load 'something.rb'

still work. So does that mean load and require have different load path?

Regex hammer time

When you have a hammer, you see everything as nails.
A very true message from Dive into Python 3,

Regular expressions are extremely powerful, but they are not the correct solution for every problem. You should learn enough about them to know when they are appropriate, when they will solve your problems, and when they will cause more problems than they solve.

But it is easy to fall into the trap of using regex for everything.
I need to find the last string from a path, where

path = "d:/some/directory-with dash-and space"

So here is how I try to get the last string in a path, with regex

path.match(/\w*$/)

trying to capture any word characters at the end of the string with \w*$, but only captured the last word “space”, not good.

path.match(/(\s|\w)*$/)[0]

to match either whitespace (\s) or word characters (\w) at the end of the string, the result is “and space”, dashed is not captured, not good.

path.match(/[^\/]*$/)

[^\/] to take in everything except “/”, result is “directory-with dash-and space”, it works!

Only later I found out there is a really simple way to do this

File.basename(path)

will actually give you “directory-with dash-and space”. Plus, it will ignore ending slash if there is any.
Duh!

bubble sort

Understanding sorting algorithm by just reading text or still illustration takes a lot of mind gymnastic. Apparently, there are lot of videos online, trying to explain the concept. But not all explain it as good though, some with really boring animation, some with crappy background music, and some even both . Here are two that I find did a great job in explaining bubble sort,

This one from codegearguru. Instead of creating graphic, or cutting out paper to represent data in the sorting process, just use the poker cards! That seems obvious now, but I didn’t think about it when I try to illustrate sorting to myself initially. Ha. Think there is a series of video created for different type of sorting algorithm as well, so definitely a great tool to understand sorting algorithm. Bonus near the end of the video, another technique called shaker sort or cocktail sort is also explained, which is basically a bidirectional bubble sort which should speed up the sorting speed.

Another one from Miles Hauskaz, just plain simple and succinct explanation and a video nicely done as well.

Sorting Algorithms – Bubble Sort from Miles Hauskaz on Vimeo.

So, this is my implementation of bubble sort, admittedly not the best that you can find, but that will do for me now, until I have time to come back and do some refactoring.

arr = %w{g a c b j e e}
i = arr.length - 1
count = 0
n = arr.length - 1
def swap(m,n) 
  arr = []
  if m > n
    arr << n
	arr << m
  else
    arr << m
	arr << n   end end while n > 0
  while count < i
    puts "comparing #{arr[count]} to #{arr[count+1]}"
    a = swap(arr[count],arr[count+1])
    arr[count..count+1] = a
    count += 1
  end
  n -= 1
  i -= 1
  count = 0
end
p arr

map and each

It is a bit difficult for me to understand the difference between map and each, until I found out this in irb accidentally,

irb(main):001:0> name = %w{guido knuth adrian dhh pg}
=> ["guido", "knuth", "adrian", "dhh", "pg"]
irb(main):002:0> name.each {|n| n.upcase}
=> ["guido", "knuth", "adrian", "dhh", "pg"]
irb(main):003:0> name.map {|n| n.upcase}
=> ["GUIDO", "KNUTH", "ADRIAN", "DHH", "PG"]

map and each are suppose to do almost the same thing, but why each didn’t return the correct result in uppercase like what map did?

The different is each yield each element in the collection to the code block, in this case perform the upcase method, but return the receiver, which is the original array, hence an array of lower case names.

Whereas, map return a new array, consists of elements already went through the code block, hence an array of upper case names.

irb(main):007:0> name.each {|n| p n.upcase}
"GUIDO"
"KNUTH"
"ADRIAN"
"DHH"
"PG"
=> ["guido", "knuth", "adrian", "dhh", "pg"]
irb(main):006:0> name.map {|n| p n.upcase}
"GUIDO"
"KNUTH"
"ADRIAN"
"DHH"
"PG"
=> [nil, nil, nil, nil, nil]

So here you can see with p, both map and each output the uppercase names, but look more carefully, the return value of each, as expected, is the original array. map however, return an array of nils!

Why is that?

A much better sort

Okay, much better only in a relative term, comparing to my earlier sorting which didn’t take care of duplicate elements.
Two major changes here.

1. I do away with the temporary variable for holding on the smallest number result from each round of the comparison, instead elements are now passed over directly to the sorted array.

2. Those elements that get passed to the sorted array, will be deleted from the original array, but one items at one round of comparison, which mean if there are duplicated elements, only one of the instance will be removed.

 hackers.delete_at(hackers.index(sorted[count]))

It look a lot more wordy than a shorter

hackers.delete(sorted[count])

but this is deleting ONLY the first element that match the value, compare to the shorter version where it will remove all elements. So it preserve the other element for next round of comparison, and eventually make it to the sorted array.
Complete code as below,

hackers = %w{ gosling matz dhh adrian guido matz knuth dhh adrian guido }
i = hackers.length
count = 0
sorted = []
 
while count < i
  sorted[count] = hackers.inject{ |a,b| a < b ? a : b }
  p sorted[count]
  hackers.delete_at(hackers.index(sorted[count]))
  count += 1
end
p sorted

And the result….

["adrian", "adrian", "dhh", "dhh", "gosling", "guido", "guido", "knuth", "matz", "matz"]

A slightly better sort

Finally have the time to come back to the sorting exercise, here is a slightly better version of sort.
It still doesn’t take care of duplicate elements, but compare to the first sorting version, this one is shorter, as the whole finding smallest element left in the array is now done by inject and a ternary operator, a whole 7 lines of code cut to just 1. And now it no longer sort animals, it sort a list of hackers

hackers = %w{matz ddh adrian guido gosling knuth linus}
i = hackers.length 
sorted = []
while i > 0
  small = hackers.inject{ |a,b| a < b ? a : b}
  sorted.push small 
  hackers.delete small
  i -= 1
end
p sorted

And the result of the sort is

["adrian", "ddh", "gosling", "guido", "knuth", "linus", "matz"]

So the next iteration will be to take care of duplicated elements…stay tuned.

optional parameters in 1.8.7 and 1.9

Apparently you can have optional parameter listed in the middle for your method in Ruby version 1.9

C:\>pik switch 191
 
C:\>irb
irb(main):001:0> def talk(a,*b,c)
irb(main):002:1>   p a,b,c
irb(main):003:1> end
=> nil
irb(main):004:0> talk 'a','b','c'
"a"
["b"]
"c"
=> ["a", ["b"], "c"]

but not Ruby version 1.8.7

C:\>pik switch 187
C:\>irb
irb(main):001:0> def talk(a,*b,c)
irb(main):002:1>   p a,b,c
irb(main):003:1> end
SyntaxError: compile error
(irb):1: syntax error, unexpected tIDENTIFIER, expecting tAMPER or '&'
def talk(a,*b,c)
               ^
        from (irb):1
irb(main):004:0> quit