Plough => Ruby Journey through ruby

Inconsistent hashes

To clarify, hashes here does not mean the Hash class. Object’s in ruby have a hash method that returns a hash code for an object. The hash is also used in the background by the eql? method. So, it’s safe to say that two objects are equal if their hash methods return the same value.

Now, carry out a simple exercise and see what happens. Fire up an IRB session and run the following code, one by one:

    "test".hash
    1.hash
    [].hash

And note the output after every command run. Now, exit out of IRB and start a fresh session and run the same piece of code again. This time you will see the hash values have changed completely. This might be a bit surprising but it has been implemented in Ruby 1.9 for security reasons as it avoids one from guessing hash values. I picked this up from Ruby-core ML discussion and hope you find it useful.

An Interesting Ruby Method

In this post, I will talk about a ruby method that I had no idea existed which might come handy in debugging your code.

The method I am talking about is set_trace_func. It’s part of the Kernel class and it does what it says. Allows one to set the method tracing on a method. The following snippet explains it further. Here, we have a class, TestingSetProcFunc:

    class TestingSetProcFunc
      def traceThisMethod
        source = 1
        target = 2
      end
    end

To inject set_trace_func in, it needs to be called before the method is invoked, like this:

    
    puts "Event    File:Line                Id          Binding        Classname"
    set_trace_func proc { |event, file, line, id, binding, classname|
      printf "%8s %s:%-2d %20s %12s %8s\n", event, file, line, id, binding, classname
    }

It takes a proc with upto 6 arguments. These are the events with their brief descriptions:

  • c-call (call a C-language routine)
  • c-return (return from a C-language routine)
  • call (call a Ruby method)
  • class (start a class or module definition)
  • end (finish a class or module definition)
  • line (execute code on a new line)
  • raise (raise an exception)
  • return (return from a Ruby method).

Now, to run this we just need to call the method and look at the output:

    tracer = TestingSetProcFunc.new
    tracer.traceThisMethod

This is what the output will look like when you run it on the command line:

    
Event    File:Line                Id          Binding        Classname
c-return test.rb:11       set_trace_func #<Binding:0x0b53c4>   Kernel
    line test.rb:13                      #<Binding:0x0b52fc>         
  c-call test.rb:13                  new #<Binding:0x0b525c>    Class
  c-call test.rb:13           initialize #<Binding:0x0b5144> BasicObject
c-return test.rb:13           initialize #<Binding:0x0b5090> BasicObject
c-return test.rb:13                  new #<Binding:0x0b4ff0>    Class
    line test.rb:14                      #<Binding:0x0b4f50>         
    call test.rb:2       traceThisMethod #<Binding:0x0b4eb0> TestingSetProcFunc
    line test.rb:3       traceThisMethod #<Binding:0x0b4dfc> TestingSetProcFunc
    line test.rb:4       traceThisMethod #<Binding:0x0b4d5c> TestingSetProcFunc
  return test.rb:5       traceThisMethod #<Binding:0x0b4cbc> TestingSetProcFunc    

This output gives one a good idea about the work that is happening in the background. The weird looking Binding instance is the context at that particular place in the code. I have just scratched the surface and I am sure there’s a lot one can do with this method. Have a look at the ruby’s test for set_trace_func for more useful ways of employing it.

Ruby Hacking Guide - Chapter 1

I have completed proof-reading and testing the code from old Ruby Hacking Guide and re-releases in the wild again. It still needs some styling work but I will hopefully find time to sort that out this week.

In the meantime, have a read through and see if you spot any mistakes.

Ruby File append mode

There are different file modes available to the developer when creating and opening new files in Ruby. One that I didn’t know about was “a” which basically means append to the end of the file rather than starting a new one. What could it be useful for? One example would be as a log file of some sort where one wants to preserve the old data and add new data to the end of the file. Very trivial but helpful if you know about these things. Just makes you a better developer.

A simple code example would be:

    file = File.new("datamapper.log", "a")