🐼
RBSのPrivateの処理を追ってみる
RubyのPrivate
こいつのことです。初学者なので勘違いしていましたがキーワードではなくメソッドらしい……。
class MyClass
def hoge
puts 'test'
end
private <--こいつ
def hogehoge
end
end
公式リファレンス
private() -> nil[permalink][rdoc][edit]
private(name) -> String | Symbol
private(*name) -> Array
private(names) -> Array
メソッドを private に設定します。
引数なしのときは今後このクラスまたはモジュール定義内で新規に定義されるメソッドを関数形式でだけ呼び出せるように(private)設定します。
引数が与えられた時には引数によって指定されたメソッドを private に設定します。
可視性については クラス/メソッドの定義/呼び出し制限 を参照して下さい。
rbs
rbsでも同様関数として定義されています。
def private: () -> nil
| (Symbol method_name) -> Symbol
| (Symbol, Symbol, *Symbol method_name) -> Array[Symbol]
| (string method_name) -> string
| (interned, interned, *interned method_name) -> Array[interned]
| (Array[interned]) -> Array[interned]
RBS内部で関数をprivateにしている箇所
# rbs/prototype/rb.rb
def process(node, decls:, comments:, context:)
case node.type
...
when :public, :private
accessibility = __send__(node.children[0])
if args.empty?
decls << accessibility
else
args.each do |arg|
if arg && (name = literal_to_symbol(arg))
if (i, _ = find_def_index_by_name(decls, name))
current = current_accessibility(decls, i)
if current != accessibility
decls.insert(i + 1, current)
decls.insert(i, accessibility)
end
end
end
end
# For `private def foo` syntax
current = current_accessibility(decls)
decls << accessibility
process_children(node, decls: decls, comments: comments, context: context)
decls << current
end
...
どうやら引数がない場合decls
にそのままアクセシビリティが登録され、引数ある場合は関数を名前で探して登録、def
の前のprivate
がつてるものは別途処理をしているようです。
単純にNodeのタイプがprivate
関数であればdecls
に現在のアクセシビリティが登録される処理を行っていそうです。
current_accessibility
# rbs/prototype/rb.rb
def current_accessibility(decls, index = decls.size)
slice = decls.slice(0, index) or raise
idx = slice.rindex { |decl| decl == private || decl == public }
if idx
_ = decls[idx]
else
public
end
end
現在のアクセシビリティが何なのかをrindex
を使い、private
またはpublic
が最後のどこでできたのかを探索して調べる関数のようです。
process
の中でこれを使いアクセシビリティを更新すべきかどうが判断しているみたいですね。
private
# rbs/prototype/rb.rb
def private
@private ||= AST::Members::Private.new(location: nil)
end
@private
がnilの場合に新しいAST::Member::Private
を@private
に代入する関数のようです。
@private
を保持している理由は使っている場所が見当たらず背景がよくわかりませんでした。(初期化に負荷がかかるから?)
おわり
private
がキーワードではなくメソッドだったのでASTの解析がどうなってるんだろうなと思い実装を追ってみました!
間違っている箇所があればコメントしてくだい!!
Discussion