Pergunta

Outro que não seja self.class.send :method, args..., claro.Eu gostaria de disponibilizar um método bastante complexo tanto no nível de classe quanto de instância, sem duplicar o código.


ATUALIZAR:

@Jonathan Branam:essa foi minha suposição, mas eu queria ter certeza de que ninguém mais havia encontrado uma maneira de contornar.A visibilidade em Ruby é muito diferente daquela em Java.Você também está certo nisso private não funciona em métodos de classe, embora declare um método de classe privado:

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

Foo.bar
# => NoMethodError: private method 'bar' called for Foo:Class
Foi útil?

Solução

Aqui está um trecho de código para acompanhar a pergunta.Usar "private" em uma definição de classe não se aplica a métodos de classe.Você precisa usar "private_class_method" como no exemplo a seguir.

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

Não vejo uma maneira de contornar isso.A documentação diz que você não pode especificar o recebimento de um método privado.Além disso, você só pode acessar um método privado da mesma instância.A classe Foo é um objeto diferente de uma determinada instância de Foo.

Não tome minha resposta como final.Certamente não sou um especialista, mas queria fornecer um trecho de código para que outras pessoas que tentarem responder tenham métodos de classe privados adequados.

Outras dicas

Deixe-me contribuir para esta lista de soluções e não soluções mais ou menos estranhas:

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

Se o seu método é apenas um função útil (ou seja, não depende de nenhuma variável de instância), você poderia colocar o método em um módulo e include e extend a classe para que esteja disponível tanto como um método de classe privada quanto como um método de instância privada.

Hoje em dia você não precisa mais dos métodos auxiliares.Você pode simplesmente incorporá-los à definição do seu método.Isso deve parecer muito familiar para o pessoal de 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

E não, você não pode chamar um método de classe privada a partir de um método de instância.No entanto, você poderia implementar o privado método de classe como público método de classe em um privado classe aninhada em vez disso, usando o private_constant método auxiliar.Ver esta postagem do blog para mais detalhes.

Esta é a maneira de brincar com métodos de classe privada "reais".

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"

saúde

Esta é provavelmente a maneira mais "nativa de Ruby 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>

Com alguma metaprogramação Ruby, você poderia até fazer com que parecesse:

class Foo
  def self.foo
    'foo'
  end

  extend PrivateStatic
  private_static :foo
end

A metaprogramação do Ruby é bastante poderosa, então você pode implementar tecnicamente quaisquer regras de escopo que desejar.Dito isto, ainda prefiro a clareza e surpresa mínima da primeira variante.

A menos que eu esteja entendendo mal, você não precisa apenas de algo assim:

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

    public
    def bar
        Foo.bar
    end
end

É claro que você poderia alterar a segunda definição para usar sua abordagem self.class.send se quisesse evitar codificar o nome da classe ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top