Сведения о вопросе

Oleksandrop

04:20, 27th August, 2020

Теги

Есть ли способ вызвать закрытый метод класса из экземпляра в Ruby?

Просмотров: 574   Ответов: 7

Кроме self.class.send :method, args..., конечно. Я хотел бы сделать довольно сложный метод доступным как на уровне класса, так и на уровне экземпляра, не дублируя код.


UPDATE :

Бранам: это было мое предположение, но я хотел убедиться, что никто другой не нашел обходного пути. Видимость в Ruby сильно отличается от таковой в Java. Вы также совершенно правы, что private не работает с методами класса, хотя это объявит частный метод класса:

class Foo
  class <<self
    private
    def bar
      puts 'bar'
    end
  end
end

Foo.bar
# => NoMethodError: private method 'bar' called for Foo:Class



  Сведения об ответе

PAGE

18:20, 28th August, 2020

Вот фрагмент кода, который будет сопровождать этот вопрос. Использование "private" в определении класса не относится к методам класса. Вы должны использовать "private_class_method", как в следующем примере.

class Foo
  def self.private_bar
    # Complex logic goes here
    puts "hi"
  end
  private_class_method :private_bar
  class <<self
    private
    def another_private_bar
      puts "bar"
    end
  end
  public
  def instance_bar
    self.class.private_bar
  end
  def instance_bar2
    self.class.another_private_bar
  end
end

f=Foo.new
f=instance_bar # NoMethodError: private method `private_bar' called for Foo:Class
f=instance_bar2 # NoMethodError: private method `another_private_bar' called for Foo:Class

Я не вижу способа обойти это. В документации говорится, что вы не можете указать получение частного метода. Кроме того, вы можете получить доступ только к закрытому методу из того же экземпляра. Класс Foo является другим объектом, чем данный экземпляр Foo.

Не считайте мой ответ окончательным. Я, конечно, не эксперт, но я хотел бы предоставить фрагмент кода, чтобы другие, кто пытается ответить, имели правильно закрытые методы класса.


  Сведения об ответе

VERSUION

11:03, 9th August, 2020

Позвольте мне внести свой вклад в этот список более или менее странных решений и не-решений:

puts RUBY_VERSION # => 2.1.2

class C
  class << self
    private def foo
      'Je suis foo'
    end
  end

  private define_method :foo, &method(:foo)

  def bar
    foo
  end
end

puts C.new.bar # => Je suis foo
puts C.new.foo # => NoMethodError


  Сведения об ответе

nYU

14:42, 6th August, 2020

Если ваш метод является просто служебной функцией (то есть он не зависит ни от каких переменных экземпляра), вы можете поместить этот метод в модуль и include и extend класс, чтобы он был доступен как частный метод класса, так и частный метод экземпляра.


  Сведения об ответе

DINO

10:10, 5th August, 2020

Именно так можно играть с "real" методами частного класса.

class Foo
  def self.private_bar
    # Complex logic goes here
    puts "hi"
  end
  private_class_method :private_bar
  class <<self
    private
    def another_private_bar
      puts "bar"
    end
  end
  public
  def instance_bar
    self.class.private_bar
  end
  def instance_bar2
    self.class.another_private_bar
  end
  def calling_private_method
    Foo.send :another_private_bar
    self.class.send :private_bar
  end
end
f=Foo.new
f.send :calling_private_method 
 # "bar"
 # "hi"
Foo.send :another_private_bar
# "bar"

овации


  Сведения об ответе

COOL

17:43, 12th August, 2020

В настоящее время вам больше не нужны вспомогательные методы. Вы можете просто встроить их в определение вашего метода. Это должно быть очень знакомо для людей Java:

class MyClass

  private_class_method def self.my_private_method
    puts "private class method"
  end

  private def my_private_method
    puts "private instance method"
  end

end

И нет, вы не можете вызвать частный метод класса из метода экземпляра. Однако вместо этого можно реализовать метод закрытого класса как метод открытого класса в частном вложенном классе, используя вспомогательный метод private_constant . Смотрите этот блог для получения более подробной информации.


  Сведения об ответе

VCe znayu

14:08, 18th August, 2020

Это, пожалуй, самый "native vanilla Ruby" способ:

class Foo
  module PrivateStatic # like Java
    private def foo
      'foo'
    end
  end
  extend PrivateStatic
  include PrivateStatic

  def self.static_public_call
    "static public #{foo}"
  end

  def public_call
    "instance public #{foo}"
  end
end

Foo.static_public_call # 'static public foo'
Foo.new.public_call # 'instance public foo'
Foo.foo # NoMethodError: private method `foo' called for Foo:Class
Foo.new.foo # NoMethodError: private method `foo' called for #<Foo:0x00007fa154d13f10>

С некоторым метапрограммированием Ruby вы даже можете сделать его похожим:

class Foo
  def self.foo
    'foo'
  end

  extend PrivateStatic
  private_static :foo
end

Метапрограммирование Ruby довольно мощное, поэтому вы можете технически реализовать любые правила определения области действия, которые вам могут понадобиться. Тем не менее, я все же предпочел бы ясность и минимальную неожиданность первого варианта.


  Сведения об ответе

P_S_S

18:41, 5th August, 2020

Если я не ошибаюсь, разве тебе просто не нужно что-то вроде этого:

class Foo
    private
    def Foo.bar
        # Complex logic goes here
        puts "hi"
    end

    public
    def bar
        Foo.bar
    end
end

Конечно, вы можете изменить второе определение, чтобы использовать свой подход self.class.send, если вы хотите избежать жесткого кодирования имени класса...


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться