Что на самом деле происходит при указании "private"/ "protected" в Ruby?

Что происходит, когда private/protected указывается в определении класса Ruby? Они не keywords, поэтому подразумевается, что они должны быть вызовами методов, но я не могу найти, где они определены. Они, похоже, не документированы. Существуют два разных способа объявления методов private/protected (показано ниже) по-разному? (Второй способ - это, очевидно, вызов метода, но это не так очевидно в первом случае.)

class Foo
  private
  def i_am_private; end
  def so_am_i; end
end

class Foo
  def i_am_private; end
  def so_am_i; end
  private :i_am_private, :so_am_i
end

Ответ 1

Оба являются вызовами метода. Цитата из docs:

Каждая функция может использоваться двумя разными способами.

  • Если используется без аргументов, три функции устанавливают контроль доступа по умолчанию для следующих определенных методов.
  • С аргументами функции устанавливают контроль доступа для названных методов и констант.

Смотрите документацию здесь:

Вы искали способ создания Module.private. Вот где это происходит. И вот еще информация об этом. Вам нужно будет прочитать больше, начиная с rb_define_private_method, определенного в class.c.

Надеюсь, что это поможет!

Ответ 2

Я хотел бы добавить что-то о своем ключевом поведении, потому что ответы были больше о том, чем, как: ответ кроется в сложных возможностях метапрограммирования Ruby. Их можно использовать в качестве ключевых слов, используя крюк method_added; крючок в Ruby - это функция, которая вызывается, когда происходит конкретное событие (т.е. имя крючка). Важно то, что крюк method_added получает в качестве аргумента имя метода, который был определен: таким образом, можно изменить его поведение.

Например, вы можете использовать этот хук, чтобы определить поведение, подобное декораторам Python; важная часть состоит в том, что, в отличие от методов private и protected, этот метод, подобный декоратору, должен определять method_added, который не определяет себя:

class Module
  def simple_decorator
    eigenclass = class << self; self; end
    eigenclass.class_eval do
      define_method :method_added do |name|
        eigenclass.class_eval { remove_method :method_added }
        old_name = 'old_' + name.to_s
        alias_method old_name, name
        class_eval %Q{
          def #{name}(*args, &block)
            p 'Do something before call...'
            #{old_name}(*args, &block)
            p '... and something after call.'
          end
        }
      end
    end
  end
end

class UsefulClass
  simple_decorator
  def print_something
    p "I'm a decorated method :)"
  end

  def print_something_else
    p "I'm not decorated :("
  end
end

a = UsefulClass.new
a.print_something
a.print_something_else

simple_decorator выглядит как ключевое слово языка и ведет себя как private; однако, поскольку он удаляет крюк method_added, он применяется только к следующему определению метода.