My take on Rails environment specific constants Learning Objective-C: a Ruby analogy
Feb 03

What?

In Ruby you have basically two ways of defining private methods:

# 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:

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:

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:

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:

$ ./configure
$ make

And then try running this script:

class Test
  def_p say_hello
    puts "I'm a private method"
  end
end
Test.new.say_hello

You should see the following output:

pvt.rb:10:in `': private method `say_hello' called for # (NoMethodError)

Happy hacking :)

Related Posts

6 Responses to “Hacking Ruby’s Syntax”

  1. herval says:

    you could achieve something similar using an ‘annotation’, without any need to hack the parser itself: http://bens.me.uk/2009/java-style-annotations-in-ruby

    annotations, by the way, are how Python declares static (class) methods.. :-)

  2. Interesting concept. I’ve read about it before - from a different source though.

    I decided to hack into the parser because I believe this specific case should be somewhat part of the core language syntax - as it is in java, for instance.

    Nevertheless, it was an interesting trip to hack through the parser and worth on its own! :P

    Vlw!

  3. Hmmmm, seems like you’ve been reading my mind. Just a few days ago I was thinking how crap it is to have to define method scopes the way they are now.

    But the way I thought of to do it was just to create 3 methods
    priv (private)
    pub (public)
    pro (protected)

    that take blocks which would be the method definitions as they are now.

    So that you could write something like

    pub def my_method .. end

    I haven’t tried to code this up yet but that is the way that I was thinking of doing it. And for me it is more natural to read it like that than def_p. But like they say, there are many ways to crack a nut, and many ways to skin a cat. So whatever works best for the individual I guess

  4. You are right in that

    priv def my_method
    end

    reads better than

    def_p my_method
    end

    I just chose def_p - as in define private - because I was more concerned about making it work.

    Just a naming clarification here: priv | pro | pub cannot be methods in order to allow your syntax. They’d have to be reserved keywords - just like def - and have to be understood by the parser.

    If you look at the patch I wrote, you’ll see it shouldn’t be too hard to implement it.

    Cheers

  5. Kudos for the good initiative :)

    In the end I think “private def my_method” would be simpler and more natural to read, just like Groovy and Scala. Ruby should borrow from them.

  6. tks!

    Totally agree on the readability issue you pointed out. def_p is just a prototype to see how many people also miss this syntax.

    It’s good to know I’m not alone. ;)

Leave a Reply

preload preload preload