7

Let's say I have a class ABC with two methods.

class ABC
  def test
     "test"
  end

  def display_test
    puts test
  end
end

I only want to be able to call ABC.new.display_test from my console (IRB) (returning me 'test') and not be able to call ABC.new.test or ABC.new.send(:test) for that matter. Is this possible? If so, how?

Biketire
  • 2,019
  • 1
  • 23
  • 41

4 Answers4

7

The most thorough way to do so would be to have test private and override the send method to specifically block the call to test:

class ABC
  def test
     "test"
  end

  private :test

  def display_test
    puts test
  end

  def send(id)
    if id == :test
      raise NoMethodError.new("error")
    else
      super(id)
    end
  end

  alias_method :__send__, :send
end

Please note that this send override is not a proper one, as it only accepts a single parameter.

If done the right way, it would become possible to do something like this:

ABC.new.send(:send, :test)
SirDarius
  • 41,440
  • 8
  • 86
  • 100
2

Make your method private.

One way to do this is:

class Foo
  private
  def bar
    # …
  end
end

Another way is:

class Foo
  def bar
    # …
  end
  private :bar
end

Note that this won't entirely prevent the method from getting called: it'll only stop "normal" calls. Indeed, there are many ways to call a private method from outside of a class in Ruby. To list a few off the top of my head:

Foo.new.send :bar
Foo.new.__send__ :bar
Foo.new.instance_eval { bar }

You could try to enumerate every possible way to send a message to a method, but your efforts will likely be fruitless in the end: Ruby is far too open for you to be able to seal the gates. So stick to making it private.

Denis de Bernardy
  • 75,850
  • 13
  • 131
  • 154
1

This is partly possible. You can remove it from being called directly, but not through send. This is the way that Ruby's private methods work.

To prevent it from being called directly, make it private.

private :test

class TestClass
  def display_test
    puts test
  end

  private
    def test
      "test"
    end
end

This is a full example:

puts TestClass.new.display_test
puts TestClass.new.send(:test)

begin
  puts TestClass.new.test
rescue
  puts "Error!"
end

Ruby Private Methods

Community
  • 1
  • 1
Dan Grahn
  • 9,044
  • 4
  • 37
  • 74
0

You can use undef method to do disable any methods, but in this case, you can't call it anywhere.


class ABC
  def test
     "test"
  end

  def display_test
    puts test
  end

  undef :display_test
end

Vlad Hilko
  • 1,104
  • 12
  • 17