Edited at

Rubyのクラスメソッドはインスタンスメソッドと同じようにprivateにならない

More than 5 years have passed since last update.

これも他の言語からRubyにやってきた人は間違えやすいかも。

private以下で定義したクラスメソッドはインスタンスメソッドと同じようにprivateになりそうな気がしますが、実はpublicのままです。

private_class_methodでそのメソッドを指定するか、特異クラスの中で定義する必要があります。

require 'rspec'

describe 'private class method' do
context '1. when use private keyword' do
class PrivateKeyword
def a_public_instance_method; end
def self.a_public_class_method; end
private
def a_private_instance_method; end
def self.a_private_class_method; end
end

let(:instance) { PrivateKeyword.new }
specify { instance.respond_to?(:a_public_instance_method).should be_true }
specify { PrivateKeyword.respond_to?(:a_public_class_method).should be_true }
specify { instance.respond_to?(:a_private_instance_method).should be_false }

#Maybe surprising!!
specify { PrivateKeyword.respond_to?(:a_private_class_method).should be_true }
end

context '2. when use private_class_method' do
class PrivateClassMethod
def self.a_private_class_method; end
private_class_method :a_private_class_method
end

# Should be private
specify { PrivateClassMethod.respond_to?(:a_private_class_method).should be_false }
end

context '3. when use singleton class' do
class InSingletonClass
class << self
def a_public_class_method; end
private
def a_private_class_method; end
end
end

specify { InSingletonClass.respond_to?(:a_public_class_method).should be_true }

# Should be private
specify { InSingletonClass.respond_to?(:a_private_class_method).should be_false }
end
end

$ rspec private_class_method_spec.rb

.......

Finished in 0.00232 seconds
7 examples, 0 failures

ちなみにprivateなクラスメソッドがそれほど多くないなら、2番目のprivate_class_methodを使う方がシンプルでいいと思うんですが、どうでしょうか?

そもそもあまりクラスメソッドが多いと、本当にオブジェクト指向プログラミングできてますか?ということになりそうですし。


参考

Privateメソッドに関連する話として、「JavaやC#の常識が通用しないRubyのprivateメソッド」というタイトルで以前ブログを書きました。

http://junichiito.hateblo.jp/entry/20120315/1331754912