数値クラスに自前のクラスを追加するにあたり、参考のため他のクラスが何のメソッドを継承・再定義などしているか、リファレンスマニュアルの表より細かく知りたかったため作成した。
一覧表
Fixnum
と Bignum
があるRuby 2.3で作成したものを載せる。
ruby 2.3.1p112 (2016-04-26 revision 54768) [x64-mingw32]
Legend
o: overriding
d: newly defined
-: inherited or mixed in
x: undefined
: never defined
#: (error)
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
% | d - o o o - x
& | d d
* | d d d d d
** | d d d d d
+ | d d d d d
+@ | d - - - - - -
- | d d d d d
-@ | d - o o o - o
/ | d d d d d
< | - - o o o - x
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
<< | d d
<= | - - o o o - x
<=> | o - o o o o x
== | - - o o o o o
=== | - - o o o - -
> | - - o o o - x
>= | - - o o o - x
>> | d d
[] | d d
^ | d d
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
abs | d - o o o - o
abs2 | d - - - - - o
angle | d - - - o - o
arg | d - - - o - o
between? | - - - - - - x
bit_length | d d
ceil | d o - - o o x
chr | d - -
coerce | d - - o o o o
conj | d - - - - - o
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
conjugate | d - - - - - o
denominator | d o - - o o o
div | d - o o - - x
divmod | d - o o o - x
downto | d - -
eql? | o - - o o - o
even? | d o o
fdiv | d - o o o o o
finite? | d
floor | d o - - o o x
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
gcd | d - -
gcdlcm | d - -
hash | - - - o o o o
i | d - - - - - x
imag | d - - - - - o
imaginary | d - - - - - o
infinite? | d
inspect | - - o o o o o
integer? | d o - - - - -
lcm | d - -
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
magnitude | d - o o o - o
modulo | d - o o o - x
nan? | d
negative? | d - - - o - x
next | d - -
next_float | d
nonzero? | d - - - - - -
numerator | d o - - o o o
odd? | d o o
ord | d - -
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
phase | d - - - o - o
polar | d - - - - - o
positive? | d - - - o - x
pred | d - -
prev_float | d
quo | d - - - o o o
rationalize | d - - d d d
real | d - - - - - o
real? | d - - - - - o
rect | d - - - - - o
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
rectangular | d - - - - - o
remainder | d - - o - - x
round | d o - - o o x
singleton_method_added | d - - - - - -
size | d d
step | d - - - - - x
succ | d o -
times | d - -
to_c | d - - - - - o
to_f | d d d d d
| Numeric Integer Fixnum Bignum Float Rational Complex
-----------------------+----------------------------------------------------------------
to_i | d - - d d d
to_int | d o - - o - -
to_r | d - - d d d
to_s | - - o o o o o
truncate | d o - - o o x
upto | d - -
zero? | d - o - o - -
| | d d
~ | d d
コード
numeric_method_table.rb
class Module
def public_method_types
modules = ancestors - [self]
inheritable_list = modules.flat_map(&:public_instance_methods).uniq
callable_list = public_instance_methods
defined_list = public_instance_methods(false)
Hash.new(0).tap do |types|
inheritable_list.each { |mtd| types[mtd] += 0x01 }
callable_list.each { |mtd| types[mtd] += 0x02 }
defined_list.each { |mtd| types[mtd] += 0x04 }
end
end
end
###--- main ---###
if RUBY_VERSION < "2.4"
class_list = [Numeric, Integer, Fixnum, Bignum, Float, Rational, Complex]
else
class_list = [Numeric, Integer, Float, Rational, Complex]
end
types_list = class_list.map(&:public_method_types)
method_list = []
types_list.each do |types|
types.each do |mtd,type|
method_list << mtd if [1, 6, 7, 2, 4, 5].include?(type)
end
end
method_list = method_list.uniq.sort
class_names = class_list.map(&:to_s)
len_mtd = method_list.map(&:length).max
len_class = class_names.map(&:length).max + 1
header = " " * len_mtd + " | " + class_names.map { |c| c.center(len_class) }.join
hline = "-" * len_mtd + "-+-" + "-" * (class_names.size * len_class)
marks = " x#-##do".each_char.map { |m| m.center(len_class) }
#- output -#
puts RUBY_DESCRIPTION
puts
puts <<EOS
Legend
o: overriding
d: newly defined
-: inherited or mixed in
x: undefined
: never defined
#: (error)
EOS
puts
method_list.each_slice(10) do |part|
puts header
puts hline
part.each do |mtd|
print mtd.to_s.rjust(len_mtd)
print " | "
types_list.each do |types|
print marks[types[mtd]]
end
print "\n"
end
puts
end
補足
文字数的に目立っているメソッド singleton_method_added
はフックのひとつで、インスタンスに特異メソッドが追加されたときに呼び出される。Numeric
では追加を阻止して例外を出すように再定義されている。
元々は BasicObject#singleton_method_added
としてprivateで定義されているが、Numeric
ではpublicになっているため(なぜ?)、一覧表では新規定義の扱いになっている。
[1] pry(main)> show-source Numeric#singleton_method_added
From: numeric.c (C Method):
Owner: Numeric
Visibility: public
Number of lines: 13
static VALUE
num_sadded(VALUE x, VALUE name)
{
ID mid = rb_to_id(name);
/* ruby_frame = ruby_frame->prev; */ /* pop frame for "singleton_method_added" */
rb_remove_method_id(rb_singleton_class(x), mid);
rb_raise(rb_eTypeError,
"can't define singleton method \"%"PRIsVALUE"\" for %"PRIsVALUE,
rb_id2str(mid),
rb_obj_class(x));
UNREACHABLE;
}
[2] pry(main)> class << Complex::I; def test; end; end
TypeError: can't define singleton method "test" for Complex
from (pry):1:in `singleton_method_added'
メソッド定義状況の分類
自クラスと親クラス(+Mix-inモジュール)のそれぞれでpublicインスタンスメソッド一覧を調べることで、以下の表のように分類できる。
親クラスが 知っている |
親クラスが 知らない |
||
---|---|---|---|
自クラスで 定義される |
自クラスが 知っている |
再定義 | 新規定義 |
自クラスで 定義される |
自クラスが 知らない |
(矛盾) | (矛盾) |
自クラスで 定義されない |
自クラスが 知っている |
継承 | (矛盾) |
自クラスで 定義されない |
自クラスが 知らない |
未定義化 | 未定義 |
メソッドの一覧は Module#public_instance_methods
で入手できる。特に引数を false
とすれば、そのクラス/モジュール自身で定義されている一覧となる。