Search code examples
rubymethodsfriend

How can I simulate class/method friendship in Ruby?


I remember (barely) in C++ that you could create friend classes or methods, capable of accessing your private members. Frankly, I never found that feature particularly useful.

Now I am using Ruby for a game development framework. I'm making a simple node system (a node can contain other children nodes, and have a parent node).

My Node class has #add_child(child). The thing is, when A node gets a child B node, I need to set B's @parent reference to point to A. So inside #add_child(child) I have this call:

child.set_parent(self)

Now B's @parent variable points to A. And this works just fine.

But, #set_parent(parent) is only meant to be used for this specific scenario. It must only be called when #add_child(child) is called. If I used #set_parent(parent) out of context, the node system may break.

Now I do find the class/method friendship thing useful. If I could make #set_parent(parent) only usable by #add_child(child), my system wouldn't break if some random programmer decided to call #set_parent(parent) by themselves.

From a few searches it doesn't seem like Ruby has this feature explicitly.

Does Ruby offer class/method friendship features like C++ does? If not, how else can I work around the described problem?


Solution

  • This should work:

    class Node
      def add_child(child)
        @children << child # or whatever
        child.instance_exec(self) { |parent| set_parent(parent) }
      end
    end
    

    Inside instance_exec you're as if inside the other object, so you can invoke private methods, or even directly set instance variables. child.instance_exec(self) { |parent| @parent = parent } would work as well. You could also do child.send(:set_parent, self) or child.instance_variable_set(:parent, self), but I think instance_exec makes it a bit clearer what you're doing. YMMV. :)

    Ruby only nominally protects the insides of its classes, enough that you don't shoot yourself in the foot by accident. But its introspection capabilities are powerful enough that you can access anything from anywhere if you want to.