Don't the Ruby Methods Instance_Eval() and Send() Negate the Benefits of Private Visibility

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

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

Why can I access private/protected methods using Object#send in Ruby?

Technically: Because send doesn't do anything to check method visibility. (It would be more work to do so.)

Philosophically: Ruby is a very permissive language. You can already just open up a class and make any method you want public. The language designers implemented send in a way that allows it to override the restrictions normally imposed by private. Ruby 1.9 was originally going to have two variants, a private-respecting send and an unsafe variant called send!, but this was apparently dropped for backwards compatibility.

As for what private, protected and public mean:

  • public methods can be called by any sender
  • protected methods cannot be called outside of an instance of the method's class or an instance of a subclass
  • private methods cannot be called with an explicit receiver (with a couple of exceptions, such as setter methods, which always have to have an explicit receiver, and so can be called within the class that way)

Is this a simple way to violate the encapsulation in ruby?

What do you expect from a language that lets you write

String = Array
puts String.new.inspect
#=> []

or

class Fixnum
def +(b)
self-b
end
end

puts 1+2
#=> -1

?

On a more serious note, almost nothing is forbidden in Ruby : it makes it easier to experiment and to learn Ruby inner workings. In some cases, it makes it possible to write more concise code or get "magical" behaviors that would be harder or impossible to reproduce with a stricter language.

In your example, it's possible to call a private method, but you cannot use the usual syntax.

Where is the methods and operators defined that allow to do class self; def foo; end; end inside class definition?

This syntax is used in ruby to access an object's metaclass, or singleton class. The metaclass is used to store methods for an individual object.

obj = # whatever...
class <<obj
# here, self is defined as obj's metaclass
# so foo will be an instance method of obj's metaclass
# meaning that we can call obj.foo
def foo
# ...
end
end
# this is equivalent to the above
def obj.foo
# ...
end

This is a core part of the language, and isn't defined in any library.

Preferred Ruby-ist way of declaring access controls

The only place I've ever seen the second method used is in Ruby books, and only as a "You can also do this" example.

And you very rarely see the use of "public" like in the first method, as it's the default and people just define all their public methods before any protected/private declarations.



Related Topics



Leave a reply



Submit