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
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