LoginSignup
3
0

More than 5 years have passed since last update.

Rubyのinheritedについて調べてそれを活かしたNaniyatsuというgemを作った話

Posted at

Rubyのinherited

https://docs.ruby-lang.org/ja/latest/method/Class/i/inherited.html
Rubyにはinheritedというサブクラスが定義されたときにコールされるクラスメソッドがある.
存在は知っていたが使う機会が一切無かったのでいろいろ実験して調べてみた.

とりあえず使ってみる

hoge.rb
class Hoge
  def self.inherited(subclass)
    puts 'ここでなんかできるよ'
  end
end

class Fuga < Hoge
end
> ruby hoge.rb 
ここでなんかできるよ

という具合でおもむろに定義しておけば継承にフックして勝手に実行される.

サブクラスのサブクラスが定義されたときも呼ばれる

hoge.rb
class Hoge
  def self.inherited(subclass)
    puts 'ここでなんかできるよ'
  end
end

class Fuga < Hoge
end

class Piyo < Fuga
end
> ruby hoge.rb 
ここでなんかできるよ
ここでなんかできるよ

サブクラスでオーバーライドするとサブクラスのinheritedだけ呼ばれる

hoge.rb
class Hoge
  def self.inherited(subclass)
    puts 'ここでなんかできるよ'
  end
end

class Fuga < Hoge
  def self.inherited(subclass)
    puts 'Fugaのinheritedだよ'
  end
end

class Piyo < Fuga
end
> ruby hoge.rb 
ここでなんかできるよ
Fugaのinheritedだよ

引数にはサブクラスのクラスオブジェクトが渡される

hoge.rb
class Hoge
  def self.inherited(subclass)
    puts subclass.to_s
  end
end

class Fuga < Hoge
end

class Piyo < Fuga
end
> ruby hoge.rb 
Fuga
Piyo

inheritedの実行タイミング

hoge.rb
class Hoge
  def self.inherited(subclass)
    puts '呼ばれたよ'
  end
end

puts '1'

class Fuga < Hoge
  puts '2'
end

puts '3'
> ruby hoge.rb 
1
呼ばれたよ
2
3

class Fuga < Hoge この行で呼ばれるらしい.
このことを指して記事冒頭に貼ったドキュメントでは

このメソッドが呼ばれるタイミングは クラス定義文の実行直前です。

と説明している.

inherited内でのself

hoge.rb
class Hoge
  def self.inherited(subclass)
    puts self.to_s
  end
end

class Fuga < Hoge
end

class Piyo < Fuga
end
> ruby hoge.rb 
Hoge
Fuga

まとめ

要するに「継承時に呼ばれる」という点だけが特殊でそれ以外は普通のクラスメソッドと何も変わらないらしい.

Naniyatsuというgemを作った

だいたいわかったのでお遊びでNaniyatsuというgemを作った.
リポジトリ: https://github.com/takuan-oishii/naniyatsu
RubyGems: https://rubygems.org/gems/naniyatsu

require 'naniyatsu'

class Hoge
  extend Naniyatsu
end

class Fuga < Hoge
end

class Piyo < Fuga
end

Hoge.new.hoge? # => true
Fuga.new.hoge? # => true
Piyo.new.hoge? # => true

Hoge.new.fuga? # => false
Fuga.new.fuga? # => true
Piyo.new.fuga? # => true

Hoge.new.piyo? # => false
Fuga.new.piyo? # => false
Piyo.new.piyo? # => true

extendするとclass_name?なメソッドを生やしてくれるmodule.
サブクラスのインスタンスはsuper_class_name?にもtrueを返すので挙動のイメージはkind_of?メソッドである.

本体はこのファイルだけで完結している.
https://github.com/takuan-oishii/naniyatsu/blob/master/lib/naniyatsu.rb

inheritedと似たメソッドのextendedも使っていていい感じに勉強になった.

余談

qiitaの話の流れ上書きやすかったので「勉強したかったから勉強してついでにgem作りました」という順番で書いたが実際は同僚が
「RailsのSTIってclass_name?みたいなメソッド生やしてくれそうで生やしてくれないんだな」
と言うので「じゃあそういうgem作るか」という流れで始まったNaniyatsuのアイデアありきの勉強である.

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0