気軽に楽しくプログラムと遊ぶ

自分が興味があってためになるかもって思う情報を提供しています。

Ruby Gold取得に向けてメタプログラミング読んだ後に知識の抜け漏れを確認する

メタプログラミングを読み終えたので、これから知識の抜け漏れを補って行きます。

下記のブログで試している事を確認して行きます。
やったーRuby技術者認定Gold受かったよー\(^o^)/ - 【旧】PerlerのRuby日記->はてなブログに移行しました
Ruby技術者認定試験(Gold)合格経験

試験後に確認している内容が含まれているので、試験に活きる知識が身につくはず。

メソッドの継承

module MyModule
  def class_method; puts "OK"; end
end

module MyModule2
  def inst_method; puts "instance method OK"; end
end

class MyClass
  # クラスメソッド定義(特異クラスにインスタンスメソッドを定義)
  extend MyModule
  
  # インスタンスメソッド定義
  include MyModule2
end

class MyClass2 < MyClass
end

MyClass.class_method # => OK
MyClass2.class_method # => OK 
mc2 = MyClass2
mc2.inst_method # => instance method OK 

superはincludeされたクラスで呼び出せるか

module M
  def method; puts "module M"; super; end
end

class ParentClass
  def method; puts "class ParentClass"; end
end

class ChildClass < ParentClass
  include M
  def method; puts "class ChildClass"; super; end
end

ChildClass.new.method 
# => class ChildClass
# => module M
# => class ParentClass  呼び出せた!

ParentClass > M > ChildClass という継承関係
includeを行うとinclude呼び出しクラスの一つ上にスーパークラスが作られる
superclassメソッドでは参照できない

privateメソッドの呼び出し

class ParentClass
  private
    def m; puts "OK"; end
end

class ChildClass < ParentClass
  def m
    super 
  end

  def m2
    m
  end
end

childclass = ChildClass.new
childclass.m # => OK
childclass.m2 # => OK

インスタンス変数のスコープ

class C
  @v = 1
  def m
    @v = 2
  end
  class << C
    @v = 3
    # Cクラスのクラスメソッドを定義
    def m
      # Cクラスのクラスインスタンス変数を参照
      @v
    end
  end
end

# クラスインスタンス変数
クラスインスタンス変数はクラスメソッドから参照可能
C.m
# => 1

# 生成オブジェクトのインスタンス変数
C.new.m
# => 2

# Cクラスの特異クラス内のインスタンス変数
class << C
  @v
end
# => 3

# Cクラスの生成オブジェクトにおける特異クラス内のインスタンス変数(ややこしいw)
c = C.new
class << c
  puts @v
end
# => nil
# 生成オブジェクト内でインスタンス変数未定義のため。当たり前か。

子クラスでinitialize未定義の場合、親クラスのinitializeが呼び出される

class C1
  def initialize(value)
    puts value
  end
end

class C2 < C1
end

C2.new("OK")
# => OK

superとsuper()

class C1
  def m(arg = 1)
    puts arg
  end
end

class C2 < C1
  def m(arg)
    # 親クラスのmメソッドを引数指定ありで呼ぶ
    super(2)
    # 親クラスのmメソッドを引数指定あり(super(arg)の省略記法)で呼ぶ
    super
    # 親クラスのmメソッドを引数指定なしで呼ぶ
    super()
  end
end
C2.new.m 2

# => 2
# => 2
# => 1

インスタンス変数

Cクラスの生成オブジェクトのインスタンス変数とクラスインスタンス変数

class C
  # クラスインスタンス変数
  @v = 1
    def m
      # Cクラスの生成オブジェクトのインスタンス変数。クラスインスタンス変数とは別物
      @v
  end
end

# 生成オブジェクトのインスタンス変数にアクセス
C.new.m
# => nil

クラスインスタンス変数へアクセスする
変数が格納されている適切なオブジェクトにアクセスすることで参照可能

class C
  @v = 1
  
  # selfはCオブジェクト。selfを付けない場合はCクラスの生成オブジェクトを参照
  def self.m
    puts @v
  end
end
# => 1

モジュールから引き継ぐもの

module M
  CONST = 1
  @@v = 2

  def instance_method
    puts "Module M instance_method"
  end

  def self.class_method
    puts "Module M class_method"
  end
end

class C
  include M
  # クラス変数は引き継がれる
  puts @@v += 1
  # 定数も引き継がれる
  puts CONST
end

# => 3
# => 1

# モジュール内のインスタンスメソッドも引き継がれる
C.new.instance_method
# => Module M instance_method

# クラスメソッドは引き継がれない
C.class_method
NoMethodError: undefined method `class_method' for C:Class

superclassとclass

クラスの継承リスト: Class < Module < Object < Kernel < BasicObject
KernelはObjectにインクルードされており、全クラスより参照可能なメソッドを提供

# 各オブジェクトのスーパークラス
class C
end

C.superclass
# => Object

Class.superclass
# => Module
Module.superclass
# => Object
Object.superclass
# => BasicObject
Basicbject.superclass
# => nil

# 各オブジェクトのクラス
C.class
# => Class
Object.class
# => Class
Basicobject.class
# => Class

Class.class
# => Class
Module.class
# => Class
Kernel.class
# => Module