Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Private/Protected block in Ruby?

Ruby doesn't seem to have a facility for defining a protected/private block like so:

protected do
  def method
  end
end

This would be nice compared to

protected 

def method 
end 

public

where you might forget to "public" after the protected methods.

It seems possible to implement this using metaprogramming. Any ideas how?

like image 671
gsmendoza Avatar asked Jun 15 '09 01:06

gsmendoza


People also ask

What is private and protected in Ruby?

protected methods can be called by any instance of the defining class or its subclasses. private methods can be called only from within the calling object. You cannot access another instance's private methods directly.

What is protected method in Ruby?

Protected methods In Ruby, a protected method (or protected message handler) can only respond to a message with an implicit/explicit receiver (object) of the same family. It also cannot respond to a message sent from outside of the protected message handler context.

Does Ruby have private methods?

A Ruby method can be:By default ALL your methods are public . Anyone can use them! But you can change this, by making a method private or protected .

What does private do in Ruby on Rails?

Private: – When a method is declared private in Ruby, it means this method can never be called with an explicit receiver. Any time we're able to call a private method with an implicit receiver.


2 Answers

Since you want to group by functionality you can declare all your methods, and then declare which ones are protected and private by using protected followed by the symbols of the methods you want to be protected, and the same for private.

The following class shows what I mean. In this class all methods are public except bar_protected and bar_private which are declared protected and private at the end.

class Foo

  def bar_public
    print "This is public"
  end

  def bar_protected
    print "This is protected"
  end

  def bar_private
    print "This is private"
  end

  def call_protected
    bar_protected
  end

  def call_private
    bar_private
  end

  protected :bar_protected

  private :bar_private

end
like image 194
Brandon Bodnar Avatar answered Oct 12 '22 21:10

Brandon Bodnar


I actually endorse bodnarbm's solution and do not recommend doing this, but since I can't pass up a metaprogramming challenge, here's a hack that will accomplish this:

class Module
  def with_protected
    alias_if_needed = lambda do |first, second|
      alias_method first, second if instance_methods.include? second
    end
    metaclass = class<<self; self end
    metaclass.module_eval {|m| alias_if_needed[:__with_protected_old__, :method_added]}
    def self.method_added(method)
      protected method
      send :__with_protected_old__ if respond_to? :__with_protected_old__
    end
    yield
    metaclass.module_eval do |m|
      remove_method :method_added
      alias_if_needed[:method_added, :__with_protected_old__]
    end
  end
end
like image 34
Chuck Avatar answered Oct 12 '22 20:10

Chuck