hacking rubys syntax
What?
In Ruby you have basically two ways of defining private methods:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this is the first way to do it | |
class Test | |
def say_hello | |
puts "I'm a private method" | |
end | |
private :say_hello | |
end | |
# and this is the second way | |
class Test | |
#other methods this class might have | |
private | |
def say_hello | |
puts "I'm a private method" | |
end | |
end |
I see a small problem with both approaches. In the first one, and the most obvious, is that you need to duplicate the method name as well as add an extra method call - private - just to change its visibility.
The second approach avoids this but adds the risk of accidentally putting a method that is intended to be public under the private section of the source file, which can render an annoying debugging session.
Why?
Personally, I like to have a smooth reading flow in my source files. That means that if the public method_a makes use of the private method_b, I want method_b defined right below its caller, which is possible - but verbose - using the private method call:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Test | |
def method_a | |
method_b | |
end | |
def method_b | |
puts "I'm a private method" | |
end | |
private :method_b | |
end |
But can be somewhat harder to accomplish if you decide to split your source file in sections:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Test | |
def method_a | |
method_b | |
end | |
#just another public method. We might have several | |
def method_c | |
method_b | |
end | |
private | |
def method_b | |
puts "I'm a private method" | |
end | |
end |
I wanted to be able to define a private method with a single reserved keyword...
How?
What if I could define a private method using this new syntax:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Test | |
def_p say_hello | |
puts "I'm a private method" | |
end | |
end |
It turns out I can.
Notice the def_p keyword? This is a new keyword I created by changing ruby's parser and that behaves mostly like the def keyword, except that it defines a private method instead.
If you wanna read the code that allows this behavior and try it yourself, download the patch I wrote and apply it to the ruby source code - I patched version 1.9.1-p376.
After applying the patch, just build ruby as usual:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./configure | |
$ make |
And then try running this script:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Test | |
def_p say_hello | |
puts "I'm a private method" | |
end | |
end | |
Test.new.say_hello |
You should see the following output:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pvt.rb:10:in `': private method `say_hello' called for # (NoMethodError) |
Happy hacking :)