Quantcast
Channel: hachi8833の記事一覧|TechRacho by BPS株式会社
Viewing all articles
Browse latest Browse all 1759

[Ruby] Kernelのモジュール関数について

$
0
0

こんにちは、hachi8833です。

Rubyスタイルガイドを読む: 文法(8)で取り上げたKernelモジュールとモジュール関数が気になったのでもう少し追ってみました。

条件

  • Ruby: 2.4

Kernelモジュールについて

全てのクラスから参照できるメソッドを定義しているモジュール。 Object クラスはこのモジュールをインクルードしています。
Object クラスのメソッドは実際にはこのモジュールで定義されています。これはトップレベルでのメソッドの再定義に対応するためです。
Rubyリファレンスマニュアル: module Kernelより

RubyのObjectクラスのメソッドのほとんどは、実際にはKernelモジュールをインクルードすることで実現しています。

Kernelのモジュール関数について

Rubyリファレンスマニュアルでは、上述のKernelモジュールのメソッドを「モジュール関数」と呼んでいます。

モジュール関数についてはTechRacho記事「[Ruby] module_functionでモジュールの特異メソッドを簡潔に書く」で解説したように「プライベートメソッドであると同時に モジュールの特異メソッドでもあるようなメソッド」です。

KernelモジュールがObjectクラスにインクルードされることで、(BasicObjectを除くすべてのオブジェクトでKernelのモジュール関数を利用できるようになります。

モジュール関数はKernel.をつけてもつけなくても実行できます。#newは不要です。

Kernelのモジュール関数のリストを見ていて、lambdaevalといった多くの重要な機能がモジュール関数として実装されていることに今さらながら気が付きました。Rubyのいわゆる組み込みメソッドの多くがこの方法で実装されているということですね。

Objectクラスのモジュール関数のリスト

Objectクラスにインクルードされているモジュール関数のリストを見てみたくてあれこれやっていたところ、babaさんが以下のコードで取れると教えてくれました。モジュール関数はprivateなので、#private_methodsで取る必要があったのでした。

Object.private_methods.each{|m| p Object.method(m)}
#<Method: Class#initialize>
#<Method: Class#inherited>
#<Method: Class(Module)#using>
#<Method: Class(Module)#attr>
#<Method: Class(Module)#attr_reader>
#<Method: Class(Module)#attr_writer>
#<Method: Class(Module)#attr_accessor>
#<Method: Class(Module)#remove_const>
#<Method: Class(Module)#remove_method>
#<Method: Class(Module)#method_added>
#<Method: Class(Module)#method_removed>
#<Method: Class(Module)#protected>
#<Method: Class(Module)#method_undefined>
#<Method: Class(Module)#undef_method>
#<Method: Class(Module)#public>
#<Method: Class(Module)#private>
#<Method: Class(Module)#initialize_copy>
#<Method: Class(Module)#initialize_clone>
#<Method: Class(Module)#alias_method>
#<Method: Class(Module)#included>
#<Method: Class(Module)#extended>
#<Method: Class(Module)#prepended>
#<Method: Class(Module)#define_method>
#<Method: Class(Object)#log>
#<Method: Class(Object)#DelegateClass>
#<Method: Class(Object)#Digest>
#<Method: Class(Object)#P>
#<Method: Class(Kernel)#sprintf>
#<Method: Class(Kernel)#format>
#<Method: Class(Kernel)#Integer>
#<Method: Class(Kernel)#Float>
#<Method: Class(Kernel)#String>
#<Method: Class(Kernel)#Array>
#<Method: Class(Kernel)#Hash>
#<Method: Class(Kernel)#fail>
#<Method: Class(Kernel)#iterator?>
#<Method: Class(Kernel)#__method__>
#<Method: Class(Kernel)#catch>
#<Method: Class(Kernel)#__dir__>
#<Method: Class(Kernel)#loop>
#<Method: Class(Kernel)#global_variables>
#<Method: Class(Kernel)#throw>
#<Method: Class(Kernel)#block_given?>
#<Method: Class(Kernel)#raise>
#<Method: Class(Kernel)#__callee__>
#<Method: Class(Kernel)#eval>
#<Method: Class(Kernel)#Rational>
#<Method: Class(Kernel)#Pathname>
#<Method: Class(Kernel)#trace_var>
#<Method: Class(Kernel)#untrace_var>
#<Method: Class(Kernel)#at_exit>
#<Method: Class(Kernel)#Complex>
#<Method: Class(Kernel)#set_trace_func>
#<Method: Class(Kernel)#gem>
#<Method: Class(Kernel)#select>
#<Method: Class(Kernel)#caller>
#<Method: Class(Kernel)#caller_locations>
#<Method: Class(Kernel)#`>
#<Method: Class(Kernel)#test>
#<Method: Class(Kernel)#fork>
#<Method: Class(Kernel)#exit>
#<Method: Class(Kernel)#sleep>
#<Method: Class(Kernel)#respond_to_missing?>
#<Method: Class(Kernel)#gem_original_require(require)>
#<Method: Class(Kernel)#load>
#<Method: Class(Kernel)#pp>
#<Method: Class(Kernel)#exec>
#<Method: Class(Kernel)#exit!>
#<Method: Class(Kernel)#system>
#<Method: Class(Kernel)#spawn>
#<Method: Class(Kernel)#abort>
#<Method: Class(Kernel)#syscall>
#<Method: Class(Kernel)#open>
#<Method: Class(Kernel)#printf>
#<Method: Class(Kernel)#print>
#<Method: Class(Kernel)#putc>
#<Method: Class(Kernel)#puts>
#<Method: Class(Kernel)#gets>
#<Method: Class(Kernel)#readlines>
#<Method: Class(Kernel)#readline>
#<Method: Class(Kernel)#initialize_dup>
#<Method: Class(Kernel)#rand>
#<Method: Class(Kernel)#p>
#<Method: Class(Kernel)#srand>
#<Method: Class(Kernel)#proc>
#<Method: Class(Kernel)#lambda>
#<Method: Class(Kernel)#trap>
#<Method: Class(Kernel)#require>
#<Method: Class(Kernel)#require_relative>
#<Method: Class(Kernel)#binding>
#<Method: Class(Kernel)#local_variables>
#<Method: Class(Kernel)#warn>
#<Method: Class(BasicObject)#method_missing>
#<Method: Class(BasicObject)#singleton_method_added>
#<Method: Class(BasicObject)#singleton_method_removed>
#<Method: Class(BasicObject)#singleton_method_undefined>

モジュールやBasicObjectクラスのメソッドを除くと、Objectクラス自身のメソッドは非常に少ないことがわかりました。

参考: Rubyの「関数」について

Rubyリファレンスマニュアルの片隅にひっそりと関数一覧というものがあります。なぜか目次にエントリがありません。

Rubyのモジュール関数を検索しているとときどきこの関数一覧にたどり着いてしまうので、若干まぎらわしいですね。

いくつか開いてみるとわかるように、これらはRubyの内部で使用されるC言語などの関数です。ALLOCのような大文字の関数はCのマクロでした。

これらはRubyから直接呼ぶことはできません。

関連記事


Viewing all articles
Browse latest Browse all 1759

Trending Articles