ruby - 基本的な文法 - クラス

 
1. クラス名は大文字で始まるのだ
2. コンストラクタ
3. デストラクタはないのだ
4. クラス名・メソッド名・void
5. 継承

1. クラス名は大文字で始まるのだ

 まずこれにびっくり。
#!/usr/bin/env ruby

class myclass           # ← 小文字
  def initialize()
  end

  def sub()
    puts 'sub なのだ'
  end
end

c = myclass.new()
c.sub()

 てなソースを書いて実行したら
/home/hogehoge/lang/ruby/class/class01.rb:3: class/module name must be CONSTANT
 怒られちゃいました。  なかなか制約があるのですなぁ。クラス名の先頭の文字は大文字でないと文法エラーになるんですって。  そういや Eclipse 上で赤いマークが出てたな。  書き直したら
#!/usr/bin/env ruby

class Myclass           # ← 大文字
  def initialize()
  end

  def sub()
    puts 'sub なのだ'
  end
end

c = Myclass.new()
c.sub()

 正常に動作しました。
sub なのだ

2. コンストラクタ

 コンストラクタには initialize というメソッドを定義します。
#!/usr/bin/env ruby

class Myclass
  def initialize()
    puts 'コンストラクタなのだ'
  end

  def sub()
    puts 'sub なのだ'
  end
end

c = Myclass.new()
c.sub()

 上記のソースを実行すると、下記の結果が得られます。
コンストラクタなのだ
sub なのだ

3. デストラクタはないのだ

 ruby には、他の言語でいうところのデストラクタはないそうで・・・。  検索すると「DestructorはないけどFinalizerはあった件 - komamitsu.log」に記事がありましたので、それを参考にさせていただきます。  ObjectSpace.define_finalizer というメソッドを使うとファイナライザーの定義ができるそうな・・・。  上記参考サイトのままでない方法でやってみるとうまくいかなかったので、更に「module function ObjectSpace.#define_finalizer (Ruby 2.5.0)」を参考にして
class Myclass
  def Myclass.callback
    proc {
      puts 'ファイナライザなのだ'
    }
  end

  def initialize()
    puts 'コンストラクタなのだ'

    ObjectSpace.define_finalizer(self, Myclass.callback)
  end

  def sub()
    puts 'sub なのだ'
  end
end

1.upto 2 do | i |
  c = Myclass.new()
  c.sub()
end

 これを実行すると
コンストラクタなのだ
sub なのだ
コンストラクタなのだ
sub なのだ
ファイナライザなのだ
ファイナライザなのだ
 となります。  デストラクタでなくファイナライザなので完全に消滅するときにしか動作しないようです。  処理を proc で囲んでいないとエラーになっちゃいます。
class Myclass
  def Myclass.callback
    puts 'ファイナライザなのだ'  # proc で囲んでいない
  end

  def initialize()
    puts 'コンストラクタなのだ'

    ObjectSpace.define_finalizer(self, Myclass.callback)
  end

  def sub()
    puts 'sub なのだ'
  end
end

1.upto 2 do | i |
  c = Myclass.new()
  c.sub()
end

 実行結果はこうなります。
/home/hogehoge/lang/ruby/class/class05.rb:9:in `define_finalizer': wrong type argument NilClass (should be callable) (ArgumentError)
	from /home/hogehoge/lang/ruby/class/class05.rb:9:in `initialize'
	from /home/hogehoge/lang/ruby/class/class05.rb:18:in `new'
	from /home/hogehoge/lang/ruby/class/class05.rb:18:in `block in <main>'
	from /home/hogehoge/lang/ruby/class/class05.rb:17:in `upto'
	from /home/hogehoge/lang/ruby/class/class05.rb:17:in `<main>'
コンストラクタなのだ
ファイナライザなのだ
 2、4行目は「DestructorはないけどFinalizerはあった件 - komamitsu.log」や「Rubyコーディング規約」にはメソッドの前には、クラス名でなく self と書くように記述してあるんですけど。
class Myclass
  def self.callback
    proc {
      puts 'ファイナライザなのだ'
    }
  end

  def initialize()
    puts 'コンストラクタなのだ'

    ObjectSpace.define_finalizer(self, self.callback)
  end

  def sub()
    puts 'sub なのだ'
  end
end

1.upto 2 do | i |
  c = Myclass.new()
  c.sub()
end

 て書くと結果はこうなっちゃいました。
/home/hogehoge/lang/ruby/class/class06.rb:11:in `initialize': undefined method `callback' for #<Myclass:0x00000008038733a8> (NoMethodError)
	from /home/hogehoge/lang/ruby/class/class06.rb:20:in `new'
	from /home/hogehoge/lang/ruby/class/class06.rb:20:in `block in <main>'
	from /home/hogehoge/lang/ruby/class/class06.rb:19:in `upto'
	from /home/hogehoge/lang/ruby/class/class06.rb:19:in `<main>'
コンストラクタなのだ

4. クラス名・メソッド名・void

 クラス名・メソッド名を取得するにはそれ用のメソッドを定義するらしい。  これに関しては「メソッドの中からクラス名とメソッド名を取得する - Qiita」を参考にさせていただきました。  引数のないメソッド、C言語では void で定義するのですが、ruby では () 自体を省略するようで、これは理にかなっている。
class Myclass

  def initialize()
  end

  def self.class_name
    self.name
  end

  def self.class_method_name
    __method__
  end

  def sub1(param)
    puts("[#{self.class.name}.#{__method__}]なのだ引数は[#{param}]")
  end

  def sub2
    puts("[#{self.class.name}.#{__method__}]なのだ引数はない")
  end
end

c = Myclass.new()
c.sub1('ppp')
c.sub2

 というソースを書いて実行すると下記の結果が得られます。
[Myclass.sub1]なのだ引数は[ppp]
[Myclass.sub2]なのだ引数はない

5. 継承


class 派生先 < 継承元
 と書くことでクラスの継承ができるようです。  「クラスを継承する - クラスの継承 - Ruby入門」を参考にさせていただきました。
class BaseClass
  def initialize
  end

  def self.class_name
    self.name
  end

  def self.class_method_name
    __method__
  end
end

class MyClass < BaseClass

  def initialize
  end

  def sub1(param)
    puts("[#{self.class.name}.#{__method__}]なのだ引数は[#{param}]")
  end

  def sub2
    puts("[#{self.class.name}.#{__method__}]なのだ引数はない")
  end
end

c = MyClass.new
c.sub1('popopo')
c.sub2

 というソースを書いて実行すると下記の結果が得られます。
[MyClass.sub1]なのだ引数は[popopo]
[MyClass.sub2]なのだ引数はない