- クラスとメソッドの関係性(メソッド編でも記載)
- クラス
- 参考文献
クラスとメソッドの関係性(メソッド編でも記載)
クラスやメソッド、オブジェクトは以下のように定義されることが多い。
クラス:設計図
オブジェクト:実体
メソッド:振る舞い
イメージとしては
クラス(設計図)内にメソッド(振る舞い)があって、

オブジェクト(実体)はクラス(設計図)を元に作られたもの

または、別の例えだと、クラスを生物の種族と捉えるというのもよくある。
クラス(猫)は、なく、寝るなどの基本的な行動(振る舞い)があり、
または猫はそれぞれ個体がある。

クラス
クラスとは、オブジェクトの所属を表すもの。
クラスに属するオブジェクトは、そのクラスのインスタンスであるとも表現されるが、そのクラスに属しているなどの意味を強調したいときに使われる。
オブジェクトは所属するクラスのメソッドを使用することができる。
どのクラスに属するかはclassメソッドで調べることができる。
"abc".class => String 1.class => Integer [1,2,3].class => Array {id: 1}.class => Hash
クラスを作る
クラスを作るには、以下のような形式で記載する。
class クラス名 ~ end
class ~ endの中にメソッドなどを記載していく。
クラス名は先頭が大文字で、その後ろは小文字になるのが慣習。
また、2単語語以上を組み合わせる際はキャメルケースで記載する。
命名規則の表現とは?
sample imageという語句があった時、
キャメルケースではsampleImageと表現され、
スネークケースではsample_imageと表現される。
そのほかケバブケース(sample-image)もある。
クラスを定義するとクラス名は定数として設定される。
オブジェクトの作り方
自作のクラスのオブジェクトはクラスメソッドnewを使用する。
その他StringやArrayなどのクラスのオブジェクトは、以下のように作成できる。
class Sample def dish puts "お皿" end end Sample.new # => #<Sample:0x00007fd89a06f138> # ArrayやStringなどのオブジェクト a = "string" # => "string" b = [1,2,3] # => [1, 2, 3] String.new # => "" Array.new # => []
ちなみにIntegerのように、newメソッドが存在しないクラスもある。
Integer.new # => NoMethodError (undefined method `new' for Integer:Class)
classメソッド
classメソッドを使用するとオブジェクトのクラスを調べることができる。
# irb Sample.new.class # => Sample Sample.new.class.class # => Class
実行結果からSample.newはsampleクラスのオブジェクトを指し、そのオブジェクトのクラスはSample、
SampleクラスのクラスはClassだということがわかる。
また以下の結果から、クラスもオブジェクトの一種とわかる。
Sample.class # => Class
クラスにメソッドを定義
クラス内にメソッドを書くことをメソッドを定義する、という。
メソッドを定義することで、そのクラスに属する全てのオブジェクトを呼び出せる。
冒頭で猫を使って解説したものでいうならば、
Catクラスに属するミケたちは「食べる」などの振る舞いを使える、ということ。
class Cat def eat "もぐもぐ" end end # 変数mikeに生成したCatクラスのオブジェクトを代入 mike = Cat.new # => #<Cat:0x00007fd89684df98> # Catクラスに定義されたeatを呼び出し p mike.eat # => "もぐもぐ"
レシーバ
メソッドを呼び出すオブジェクトのことをレシーバという。 Cat.newのCat、mike.eatのmikeがレシーバ部分にあたる。
methodsメソッド
methodsメソッドは、レシーバであるオブジェクトが呼び出せるメソッドを表示するメソッド。
class Cat def eat "もぐもぐ" end def purr "ぐるぐる.." end end mike = Cat.new mike.methods => [:purr, :eat, #<-定義したメソッド :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_get, :instance_variable_set, :protected_methods, :instance_variables, :private_methods, :method, :public_method, :public_send, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?, :freeze, :inspect, :object_id, :send, :to_s, :display, :class, :nil?, :hash, :dup, :singleton_class, :clone, :then, :itself, :yield_self, :untaint, :taint, :tainted?, :trust, :untrust, :untrusted?, :singleton_methods, :frozen?, :methods, :public_methods, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__] # sortメソッドを使ってabc順に並べ替え mike.methods.sort => [:!, :!=, :!~, :<=>, :==, :===, :=~, :__id__, :__send__, :class, :clone, :define_singleton_method, :display, :dup, :eat, :enum_for, :eql?, :equal?, :extend, :freeze, :frozen?, :hash, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_variable_defined?, :instance_variable_get, :instance_variable_set, :instance_variables, :is_a?, :itself, :kind_of?, :method, :methods, :nil?, :object_id, :private_methods, :protected_methods, :public_method, :public_methods, :public_send, :purr, :remove_instance_variable, :respond_to?, :send, :singleton_class, :singleton_method, :singleton_methods, :taint, :tainted?, :tap, :then, :to_enum, :to_s, :trust, :untaint, :untrust, :untrusted?, :yield_self]
引数のあるメソッドの定義
クラス内のメソッドにも引数でオブジェクトを渡すことができる。
class Cat def eat(food) "#{food}をもぐもぐ" end def purr(sound) "#{sound}" end end mike = Cat.new p mike.eat('魚') # => "魚をもぐもぐ" p mike.purr('にゃー') # => "にゃー"
クラス内で同じクラスのメソッドの呼び出し
同じクラス内のメソッドの呼び出しは、メソッド名を書くことで実行できる。
メソッドのレシーバは省略すると実行中のメソッド(eat)のレシーバ(mike)が呼び出される。
class Cat def eat(food) "#{food}を" + eat_sound end def eat_sound "もぐもぐ" end end mike = Cat.new p mike.eat('魚') # => "魚をもぐもぐ"
self
selfは擬似変数で、現在のメソッドの実行主体 (オブジェクトまたはクラス)が入る。 以下の例ではeat_soundメソッドのレシーバを調べるため、eatメソッド内でselfを使用している。
class Cat def eat(food) p self "#{food}を" + eat_sound end def eat_sound "もぐもぐ" end end mike = Cat.new p mike # => #<Cat:0x00007fa9450a9628> -> mikeオブジェクト識別番号 p mike.eat('魚') # => #<Cat:0x00007fa9450a9628> -> eat_soundのレシーバのオブジェクト識別番号 # => "魚をもぐもぐ"
0x~は識別番号で、0x以下は実行するたびに変更される。
この番号が同じであれば同じオブジェクトであるので、同じレシーバといえる。
そのため、eatメソッドで記載しているeat_soundの呼び出しをselfを省略せず、self.eat_soundともかくことができる。
例の処理の流れを書くと以下の通りになる。
インスタンス変数
@変数と表現される変数で、設定されたオブジェクトで使用することができ、そのクラスまたはサブクラスのメソッドを参照することができる。
class Cat def eat(food) p "#{food}を食べている" food = food end def refill p "#{food}をまだ食べたそうにしている" end end mike = Cat.new mike.eat('魚') # => "魚を食べている" mike.refill # => NameError (undefined local variable or method `food' for #<Cat:0x00007fa941968858>)
「foodは定義されていない変数または変数である」といったエラーが出ている。
これはローカル変数のスコープの領域を超えたのでfoodという変数のデータが消失したのが原因。
そのためオブジェクトで保持できるインスタンス変数にして改めて実行すると、
class Cat def eat(food) p "#{food}を食べている" @food = food end def refill p "#{@food}をまだ食べたそうにしている" end end mike = Cat.new mike.eat('魚') mike.refill "魚を食べている" "魚をまだ食べたそうにしている"
流れは以下のような流れになる。
newメソッドで作られたオブジェクトがインスタンス変数の持ち主になるため、この時はmikeオブジェクトだけが@food = '魚'の情報を保持している。
mike = Cat.new tama = Cat.new mike.eat('魚') # => "魚を食べている" tama.eat('ちゅ〜る') # => "ちゅ〜るを食べている" mike.refill # => "魚をまだ食べたそうにしている" tama.refill # => "ちゅ〜るをまだ食べたそうにしている"
インスタンス変数を取得(getter)
オブジェクトの外でインスタンス変数を取得するには、取得用のメソッドを作成する必要がある。
また、取得するためのメソッドはゲッターと表現される。
ゲッターなしで呼び出そうとする以下のように構文エラーが出る。
class Cat def eat(food) p "#{food}を食べている" @food = food end end mike = Cat.new mike.eat('魚') # => "魚を食べている" p mike.@food # => SyntaxError (sample.rb:10: syntax error, unexpected tIVAR) p mike.@food
ゲッターであるメソッドを追加すると以下のようになる。
ゲッターで@foodの情報をfoodメソッドで展開できるように設定。
class Cat def eat(food) p "#{food}を食べている" @food = food end def food #<- ゲッター @food end end mike = Cat.new mike.eat('魚') # => "魚を食べている" p mike.food # => "魚"
このゲッターをattr_readerというメソッドで1行で記載することもできるが、また別の投稿で記載する。
インスタンス変数へ代入(setter)
インスタンス変数へ代入するためのメソッドは=()を使用する。 代入するためのメソッドはセッターと表現される。
class Cat def food=(name) @food = name end def food @food end end mike = Cat.new mike.food = "魚" puts mike.food # => 魚 mike.food = "ちゅ〜る" puts mike.food # => ちゅ〜る
()=メソッドはインスタンス変数から@をとり、末尾に=をつけたものを使用する慣習がある。
オブジェクトのもつインスタンス変数を表示
instance_variablesメソッドを使用すると、オブジェクトのインスタンス変数名をシンボルの配列として返す。
class Cat def eat(food) p "#{food}を食べている" @food = food end def food @food end end mike = Cat.new mike.food = "魚" p mike.instance_variables # => [:@food]
mike.foodで@foodに@food = "魚"が定義されるので、mikeオブジェクトには@foodが定義されるようになる。 そのためp mike.instance_variablesで[:@food]が返される。
オブジェクトの初期化
initializeメソッドはオブジェクト初期化メソッドであり、Objectクラスのprivateメソッドに分類される。
このメソッドはnewインスタンスで作成されたオブジェクトの初期化のため使用される。
newメソッドから自動で呼び出される。
class Cat def initialize puts "initializeメソッド" end end Cat.new # => initializeメソッド
インスタンス変数の初期値を設定
initializeメソッドを使用することで、インスタンス変数の初期値を設定することができる。
class Cat def initialize @color = "ぶち" end def color @color end end mike = Cat.new puts mike.color # => ぶち
引数を渡す場合
class Cat def initialize(color) @color = color end def color @color end end mike = Cat.new("しろ") puts mike.color # => しろ
インスタンスメソッドとクラスメソッド
インスタンスメソッド:インスタンス(オブジェクト)をレシーバにするメソッド(mike.colorなど)
クラスメソッド:クラスをレシーバにするメソッド(Cat.newなど)
クラスメソッドの定義
selfを使った方法
メソッド名の前にself.という記載を入れるとクラスメソッドに定義される。
これは前述の通りselfが擬似変数であり、実行主体の情報が入っているため。
クラス名.クラスメソッドという形でも定義できるが、クラス名が変更になった場合保守性が低くなるためあまり使用しない。
class Cat def self.eat_sound "もぐもぐ" end end puts Cat.eat_sound # => もぐもぐ
<<
複数のクラスメソッドをまとめて書くときに有効。
class Cat class << self def eat_sound "もぐもぐ" end end end puts Cat.eat_sound # => もぐもぐ
#記法と.記法
インスタンスメソッドは「クラス名#メソッド名」、
クラスメソッドは「クラス名.メソッド名」または「クラス名::メソッド名」
を使って表される。
クラス内のクラスメソッドの呼び出し
インスタンスメソッド同様メソッド名だけでも呼べるが、省略されているクラス名またはselfでも呼べる。
class Cat def self.eat_sound "もぐもぐ" end def self.eat_sound_continue eat_sound + "ぱくぱく" # 省略形 # self.eat_sound + "ぱくぱく" # Cat.eat_sound + "ぱくぱく" end end puts Cat.eat_sound_continue # => もぐもぐぱくぱく
インスタンスメソッドはクラスメソッドを呼ぶことできるが、逆はできない。
なぜならクラスからオブジェクトのレシーバを判別することはできないため。
継承について
子クラスで、子クラス < 親クラスのような記載をすると継承が定義される。
継承が定義された子クラス(サブクラス)では、親クラス(スーパークラス)のメソッドが使用できる。
class Animal def name @name end def name=(text) @name = text end end class Cat < Animal def size @size end def size=(text) @size = text end end mike = Cat.new mike.name = "みけ" mike.size = "小さい" puts "#{mike.name}は#{mike.size}"
ここではnameメソッドのない子クラスのCatが、親クラスAnimalのnameメソッドを使っている。
継承関係を確認する
ancestorsメソッドは親クラスとincludeしているモジュールを順番に配列に格納して返す。
p Cat.ancestors # => [Cat, Animal, Object, Kernel, BasicObject]
オーバーライド
親クラスと子クラスで同じ名前のメソッドがある時、子クラスのメソッドが呼ばれる。 これをオーバーライドという。
class Animal def name @name end def name=(text) @name = text end def medical_chart @name end end class Cat < Animal def size @size end def size=(text) @size = text end def medical_chart "名前:#{@name} 大きさ:#{@size}" end end mike = Cat.new mike.name = "ミケ" mike.size = "ちいさい" puts mike.medical_chart # => 名前:ミケ 大きさ:ちいさい
親クラスメソッドの使用
class Animal def name @name end def name=(text) @name = text end def medical_chart puts "猫" end end class Cat < Animal def size @size end def size=(text) @size = text end def medical_chart super puts "名前:#{@name} 大きさ:#{@size}" end end mike = Cat.new mike.name = "ミケ" mike.size = "ちいさい" mike.medical_chart # 結果 猫 名前:ミケ 大きさ:ちいさい
上記の例では、superで親クラスのメソッドが呼ばれ、その次に子クラスへ処理が戻ってきている。
また、#{}の中にもsuperは入れることができる。
メソッドの制限
privateを設定すると、private以下のメソッドについて、クラス外での呼び出しについて変数でしか呼び出せなくなるようにできる。
class Cat def eat food end private def food "魚" end end mike = Cat.new p mike.eat # => "魚" p mike.food # => NoMethodError (private method `food' called for #<Cat:0x00007fa47d046158>)
privateの他にpublic(アクセス制限なし)やprotected(アクセス制限あり)もある。
一度privateの記載をするとそれ以降はprivate設定になるので、もしその下にpublicなメソッドを書きたい場合、privateと同じようにpublicを入力するとそれ以降publicな状態のメソッドになる。
privateの書き方はもう一つあり、以下のようにも記載できる。
class Cat def eat food end private def food "魚" end end mike = Cat.new p mike.eat # => "魚" p mike.food # => NoMethodError (private method `food' called for #<Cat:0x00007fa47d131158>)
クラスメソッドの制限
private_class_methodをdefの前に記載するとクラスメソッドを制限できる。
class Cat private_class_method def self.eat puts "もぐもぐ" end end Cat.eat # => NoMethodError (private method `eat' called for Cat:Class)
class << selfの場合はprivateが使用できる。
class Cat class << self private def eat_sound "もぐもぐ" end end end puts Cat.eat_sound # => NoMethodError (private method `eat_sound' called for Cat:Class)
参考文献
変数と定数 (Ruby 3.0.0 リファレンスマニュアル)
Rubyの「attr_accessor」ってなんぞや、という人へ | とむじそブログ
Module#private (Ruby 3.0.0 リファレンスマニュアル)
ゼロからわかる Ruby 超入門 (かんたんIT基礎講座) | 五十嵐 邦明, 松岡 浩平 |本 | 通販 | Amazon