しょんぼり技術メモ

まいにちがしょんぼり

イベントハンドラみたいなのをRubyで書きたい

C#で言うところのEventHandlerみたいな奴がRubyで欲しくなったので勉強してみた。

#!/usr/bin/ruby -Ku
# -*- coding: utf-8 -*-

# 呼ばれる側 その1
class Class1
  def class1_print
    puts "    called:Class1.class1_print()"
  end

  def class1_print_with_arg(arg)
    puts "    called:Class1.class1_print_with_arg() arg is: #{arg}"
  end
end

# 呼ばれる側 その2
class Class2
  def class2_print
    puts "    called:Class2.class1_print()"
  end

  def class2_print_with_arg(arg)
    puts "    called:Class2.class2_print_with_arg() arg is: #{arg}"
  end
end

# EventHandlerみたいなモノ
class Caller
  # Methodオブジェクトを格納する配列
  @methods = nil

  # コンストラクタ
  def initialize
    @methods = Array.new
  end

  # Methodオブジェクト配列に関数を登録
  def register_func(method)
    @methods << method
  end

  # caller += hoge と書けるように演算子オーバーロード
  def +(method)
    register_func(method)
    return self
  end

  # 登録した関数を削除
  def unregister_func(method)
    @methods.delete(method)
  end

  # caller -= hoge と書けるように演算子オーバーロード
  def -(method)
    unregister_func(method)
    return self
  end

  # 現在登録されている関数を全て呼び出す
  def call_them_all
    @methods.each do |method|
      method.call
    end
  end

  # 引数を渡して全て呼び出す
  def call_them_all_with_arg(arg)
    @methods.each{|method| method.call(arg)}
  end
end

class1 = Class1.new
class2 = Class2.new
caller = Caller.new

puts "・何も登録していない状態でのCaller呼び出し"
caller.call_them_all
puts "→何も呼ばれない"
puts

puts "・class1_printを登録"
caller += class1.method(:class1_print) # caller.register_func( class1.method(:class1_print) ) と同じ
puts "Caller呼び出し"
caller.call_them_all
puts "→class1_printが呼ばれる"
puts

puts "・class2_printを登録"
caller += class2.method(:class2_print)
puts "Caller呼び出し"
caller.call_them_all
puts "→class1_print、class2_printが呼ばれる"
puts

puts "・class1_printを削除"
caller -= class1.method(:class1_print)
puts "Caller呼び出し"
caller.call_them_all
puts "→class2_printが呼ばれる"
puts


puts "・Callerを初期化"
caller = Caller.new
puts

puts "・class1_print_with_arg class2_print_with_argを登録"
caller += class1.method(:class1_print_with_arg)
caller += class2.method(:class2_print_with_arg)
caller.call_them_all_with_arg("Argument string.")
puts "→class1_print_with_arg、class2_print_with_argが呼ばれる"

実行結果:

・何も登録していない状態でのCaller呼び出し
→何も呼ばれない

・class1_printを登録
Caller呼び出し
    called:Class1.class1_print()
→class1_printが呼ばれる

・class2_printを登録
Caller呼び出し
    called:Class1.class1_print()
    called:Class2.class1_print()
→class1_print、class2_printが呼ばれる

・class1_printを削除
Caller呼び出し
    called:Class2.class1_print()
→class2_printが呼ばれる

・Callerを初期化

・class1_print_with_arg class2_print_with_argを登録
    called:Class1.class1_print_with_arg() arg is: Argument string.
    called:Class2.class2_print_with_arg() arg is: Argument string.
→class1_print_with_arg、class2_print_with_argが呼ばれる

とりあえずそれっぽく動いた。関数っていう呼び方が正しくないのはご愛敬。
クラスメソッドを取得するのに、some_instance.method(:method_name)という形式を取るのがちょっとモニョるけど、RubyらしいといえばRubyらしい…かな?

# っていうか誰か作ってるんじゃないかなこういうの…