ナスカブログ

未来の自分へのドキュメント

Ruby Goldへの道 day4

以下のサイトでruby gold取得に向けて毎日一回Goldチャレンジを行い間違えた問題を簡単にまとめる。 rex.libertyfish.co.jp

4日目 得点 70点/100点中

惜しい。順調に得点を伸ばしてる。

では、今日も間違えた問題を簡単にまとめる。

module M
  def class_m # インスタンスメソッド
    "class_m"
  end
end

class C
  include M
end

p C.methods.include? :class_m #=> false
# Cの特異メソッドを表示
p C.new.methods.include? :class_m #=> true
  • selfはnewされたクラスのオブジェクトになる
class C
  def initialize
    p self.class
    # selfはnewされたオブジェクトになる
  end
end

class C2 < C
end

C2.new #=> C2
  • モジュールを読み込むにはusing モジュールが必要
class C
  def m1
    200
  end
end

module R
  refine C do
    def m1
      100
    end
  end
end

c = C.new
puts c.m1 #=>200
# Rモジュールは読み込めていない
# 読み込むにはusingRが必要
using R
c2 = C.new
puts c2.m1 #=> 100
  • loadは外部ライブラリを読み込む...
    モジュールの使用は include か using
module M
  def foo
    super
    puts "M#foo"
  end
end

class C2
  def foo
    puts "C2#foo"
  end
end

class C < C2
  def foo
    super
    puts "C#foo"
  end
  using M # or include M
  # ※using と include は挙動が違う
  # load M 
  # loadは外部ライブラリを読み込む
end

C.new.foo
  • method_missingはチェーンをたどった末にメソッドが見つからなかったら呼ばれる
module M
  def method_missing(id, *args)
    puts "M#method_missing"
  end
end
class A
  include M
  def method_missing(id, *args)
    puts "A#method_missing"
  end
end
class B < A
  def method_missing(id, *args)
    puts "B#method_missing"
  end
  # このmethod_missingメソッドをコメントアウトすると
  # Aクラスのmethod_missingが呼ばれる
end

obj = B.new
obj.dummy_method #=> B#method_missing
# 継承チェーンをたどった末に見つからなかったらオブジェクト(Bクラス)のmethod_missingが呼ばれる
# method_missingも継承チェーンをたどるのでBに定義しなかったらAのmethod_missingが呼ばれる
  • Objectクラスに*メソッドは定義されていない
p [1,2,3,4].map(&self.method(:*))
#=> undefined method `*' for class `#<Class:#<Object:0x00007ff4e18b9d58>>' (NameError)
# オブジェクトクラスに*メソッドが定義されていないためエラー
  • 定数は静的に探索が行われる
module A
  B = 42

  def f
    21
  end
end

A.module_eval(<<-CODE)
  def self.f
    p B
  end
CODE

B = 15

A.f #=> 42
  • 正規表現の[]は囲まれた文字1つ1つにマッチする
    出た。正規表現。少しずつ覚えていこう..
p "Matz is my tEacher"[/[J-P]\w+[^ ]/] #=> "Matz"
  • クラスメソッドの呼び出しはself.[メソッド]
class C
  class << C # 特異クラス
    def hoge # クラスメソッド
      'Hi'
    end
  end

  def hoge # selfをつけるとクラスメソッドになる
    'Goodbye'
  end
end

p C.hoge #=> "Hi"
# クラスメソッドを呼び出す
p C.new.hoge #=> "Goodbye"
  • Module.nestingはネストの状態を表示する
    浅いところから表示していく
module SuperMod
  module BaseMod
    p Module.nesting
  end
end

#=> [SuperMod::BaseMod, SuperMod]
# ネストの状態を浅いところから全て表示する
  • raiseの例外クラスを省略した場合は、RuntimeErrorを発生させる
begin
  raise "Err!"
  # raise 発生させたい例外クラス, "エラーメッセージ" 
rescue => e
  puts e.class #=> RuntimeError
  # 例外クラスの記述が省略されているので RuntimeError が発生
end
  • superと呼び出した場合は、現在のメソッドと同じ引数が引き継がれる
    super() と引数がないことを明示的に示す必要がある
class S
  def initialize
    puts "S#initialize"
  end
end

class C < S
  def initialize(*args)
    super
    # super()と記述するとエラーはなくなる
    puts "C#initialize"
  end
end

C.new(1,2,3,4,5) #=>  wrong number of arguments (given 5, expected 0) (ArgumentError)
  • モジュールにクラスメソッドを定義するには3つ方法がある
# モジュールにクラスメソッドを定義する方法
# ①
module M
  extend self
  def a
    100
  end
end

p M.a #=> 100

# ②
module M
  def a
    100
  end

  module_function :a
end

p M.a #=> 100

# ③
module M
  class << self
    def a
      100
    end
  end
end

p M.a #=> 100
  • freezeは破壊的な変更を禁止する
    どこにfreezeがあるかを確認する必要がある
array = ["a", "b", "c"].map(&:freeze) #=> 配列の要素に対して破壊的な変更を禁止する
array = array.freeze

array.each do |chr|
  chr.upcase!
end

p array #=> can't modify frozen String: "a" (FrozenError)
p Class.method_defined? :new #=> true
p String.method_defined? :new #=> false
p Class.singleton_class.method_defined? :new #=> true
p String.singleton_class.method_defined? :new #=> true