Search code examples
rubyvisibilityaccess-specifier

Don't the Ruby methods instance_eval() and send() negate the benefits of private visibility?


w = Widget.new # Create a Widget
w.send :utility_method # Invoke private method!
w.instance_eval { utility_method } # Another way to invoke it
w.instance_eval { @x } # Read instance variable of w

Looking at the example above which relates to the Widget class (below), the send and instance_eval methods violate all of the protections provided by private and protected visibility. If so, why bother with private and protected access in Ruby at all since there is no guarantee that your definitions will be honored?

class Widget
  def x # Accessor method for @x
   @x
  end
  protected :x # Make it protected
  def utility_method # Define a method
   nil
  end
  private :utility_method # And make it private
end

Solution

  • If you really want to protect instances of Widget, you can do this (and a bunch of other stuff; the code here is not a complete security solution, merely indicative):

    class Widget
    
      def some_public_method
        ...
      end
    
      private
    
      def utility_method
        ...
      end
    
      def send(method, *args, &block)
        raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
      end
    
      def instance_eval(&block)
        raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
      end
    
      class <<self
        private
        def class_eval(&block)
          raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
        end
      end
    end
    
    Widget.freeze