Ruby class with static method calling a private method?

yamori picture yamori · Apr 20, 2015 · Viewed 15.5k times · Source

I have a class with a number of static methods. Each one has to call a common method, but I'm trying not to expose this latter method. Making it private would only allow access from an own instance of the class? Protected does not seem like it would solve the problem here either.

How do I hide do_calc from being called externally in a static context? (Leaving it available to be called from the first two static methods.)

class Foo
  def self.bar
    do_calc()
  end
  def self.baz
    do_calc()
  end
  def self.do_calc
  end
end

Answer

tompave picture tompave · Apr 20, 2015

First off, static is not really part of the Ruby jargon.

Let's take a simple example:

class Bar
  def self.foo
  end
end

It defines the method foo on an explicit object, self, which in that scope returns the containing class Bar. Yes, it can be defined a class method, but static does not really make sense in Ruby.

Then private would not work, because defining a method on an explicit object (e.g. def self.foo) bypasses the access qualifiers and makes the method public.

What you can do, is to use the class << self syntax to open the metaclass of the containing class, and define the methods there as instance methods:

class Foo
  class << self

    def bar
      do_calc
    end

    def baz
      do_calc
    end

    private

    def do_calc
      puts "calculating..."
    end
  end
end

This will give you what you need:

Foo.bar
calculating...

Foo.baz
calculating...

Foo.do_calc
NoMethodError: private method `do_calc' called for Foo:Class