Saturday, March 15, 2008

When private is not private

In Java if we have a class with a private class method like so...

public class MyJavaClass {
private static void privateMethod() {
System.out.println("I am private method");
}
}

Trying to call the 'privateMethod' class method is futile.

public class Testing {
public static void main(String args[]){
MyJavaClass.privateMethod(); //This will not work!
}
}

Matter of fact you can not even compile the above class!

Testing.java:3: privateMethod() has private access in MyJavaClas
MyJavaClass.privateMethod();

If we have a similar Ruby class and call the private method there is no problem.

class MyRubyClass
private
def self.private_method
puts "I am a private method"
end
end

>> MyRubyClass.private_method
I am a private method
=> nil

What gives?!

As it turns out you can not simply create a class method in a private section and have it actually be private. Reading through the Ruby API I came across the solution to achieve the desired behavior. There is a method in Module called 'private_class_method' with the following signature.

mod.private_class_method(symbol, ...) => mod

Now if we slightly modify our MyRubyClass we get the results we would expect.

class MyRubyClass
private
def self.private_method
puts "I am a private method"
end
private_class_method :private_method
end

>> MyRubyClass.private_method
NoMethodError: private method 'private_method' called for MyRubyClass:Class
from (irb):26


*Note: Private instance methods behave as expected without any modifications.

Monday, March 10, 2008

Quick Tip - to_proc

We all know that & (ampersand) is used to denote a block variable but what you may not know is that Rails ActiveSupport (and soon to be in ruby 1.9) has a nice extension on Symbol that can make use of this convention by adding a to_proc method.

For example instead of:

["This", "blog", "is", "great"].map {|w| w.upcase}
=> ["THIS", "BLOG", "IS", "GREAT"]


We could simplify it by:

["This", "blog", "is", "great"].map(&:upcase)
=> ["THIS", "BLOG", "IS", "GREAT"]


What ruby ends up do is calling the to_proc method on that symbol and it coerces into a block!

Here is a link to the documentation and for those who are lazy I have posted the source below.

# File lib/extensions/symbol.rb, line 23
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end