Ruby勉強

インターネットの企画職な人がプログラミングを勉強するブログ

Ruby define_methodとclass_eval

# クラスを動的に定義
A = Class.new

# #1
# Aクラスのコンテクストで
# private_methodであるdefine_methodを使用
A.class_eval{
  define_method(:hoge){|a|
    puts a
  }
}
A.new.hoge("hoge") #=> "hoge"

# #2
# Aクラスのコンテクストで
# private_methodであるdefine_methodを使用
A.__send__(:define_method,:fuga) {|a|
  puts a
}
A.new.fuga("fuga") #=> "fuga"

# #3
# 動的に、クラスを定義し、メソッドを定義する方法例
# procは、Kernel#procを使用。受けたブロックをprocに変換して
# __send__に送り、それを__send__はそのままdefine_methodへ送っている
# わかりやすさという点でこうした方が良いか
#  def definer(class_name,method_name,&k)
#   class_name=Object.const_set(class_name.capitalize,Class.new)
#   class_name.__send__(:define_method,method_name,k)
module A
  def definer(class_name,method_name)
    class_name=Object.const_set(class_name.capitalize,Class.new)
    class_name.__send__(:define_method,method_name,proc)
  end
end
class B
  extend A
end

B.definer("C",:hoge) {|a|
  puts a
}
C.new.hoge(1)

こういった臨機応変にクラスやメソッドを動的定義、追加することは、リフレクションプログラミングという。 見通しは悪くなるが柔軟。

Ruby 定数の参照順位 - Silver/Gold試験対策

定数は外側を参照し、その次に継承関係を探索する

class C
  CONST = "c"
end
class A
  CONST = "a"
  class B < C
    p CONST
  end
end #=> "a"

このように明示的に、定数を参照することもできる

class C
  CONST = "c"
end
class A
  CONST = "a"
  class B < C
    p C::CONST
  end
end #=> "c"
CONST = "d"
class A
  p CONST
end #=> "d"

トップレベルは参照順位が低い

CONST = "d"

class A
  CONST = "e"
end

class B < A
  p CONST
end #=> "e"

参照先をトップにすると

CONST = "d"

class A
  CONST = "e"
end

class B < A
  p ::CONST
end #=> "d"

Ruby Fiber - Silver/Gold試験対策

概要

  • Fiberは、ノンプリエンプティブ(nonpreemptive)なタスクスケジューリング方式。
  • Threadはプリエンプティブ(preemptive)。プリエンプティブとは先制、先取の意味がある。
  • プリエンプティブである、Threadだと、例外が発生したりすると、勝手にスレッドが切り替わる。
  • このThreadの挙動はこれは適切で、無限ループをわかっていながら実行し続けたりせずというOSなどもっとRawなコントロールにスケジュールを任せようということだと思う。 一方、Fiberは明示的にタスクを受け渡し宣言をすることでアプリケーションレベルでタスクスケジュールを管理できるようだ。

詳細

  • resumeとはFiberのあるブロックの実行を続行(文字通りresume)する
  • yieldとはFiberのブロックから、resumeした親にコンテクストを預けるというか、処理をsuspendするイメージ
f = Fiber.new do
  p "hoge"
  Fiber.yield
  p "fuga"
end
f.resume #=> "hoge"
f.resume #=> "fuga"
  • yieldは引数と共に、コンテクストをresumeに預ける。Fiber#resumeの返り値はその引数
f = Fiber.new do
  n = 3
  loop do
    Fiber.yield(n)
    n += 1
  end
end
p f.resume #=> 3。
p f.resume #=> 4。一度めのyieldの後ろを実行し、loopして、2度めのyieldで引数と共にコンテクストを返してもらう

親に例外が伝播する

f = Fiber.new do
  raise StandardError, "StandardError in Fiber"
end
begin
  f.resume
rescue => ex
  p ex.message #=>"StandardError in Fiber"
end

実行するFiberがない場合はFiberErrorに。

 f = Fiber.new do
   "fiber"
 end
p f.resume #=> "fiber"
p f.resume #=> FiberError

Ruby rdoc - Silver/Gold試験対策

#= "#="で見出し1
#== "#=="見出し2
#=== "#==="さようなら
#- "#-"箇条書き1
#- "#-"箇条書き1
#* "#*"箇条書き別の方法
#* "#*"箇条書き別の方法
#1. "#1."箇条書き数字
#2. "#2."
#a. "#a."箇条書きアルファベット小文字
#b. "#b."
#A. "#A."箇条書きアルファベット大文字
#B. "#B."
#C. "#C."
#[cat] \[cat\]でラベル付き
#dog:: \dog::でもラベル付き
#*birds*:: \*birds\*で太字
#_italic_:: \_italic\_
#[罫線]
#\-\-\-で罫線
#---
class A
  include M
  def hoge
    :hoge
  end
  def self.fuga
  end
end

プレビュー f:id:peakp:20161108090145p:plain

Ruby Object Class - Silver/Gold試験対策

  • 全てのクラスのスーパークラス。 オブジェクトの一般的な振舞いを定義する
  • このクラスのメソッドは上書きしたり未定義にしない限り、すべてのオブジェクトで使用することができことができる
def hoge
 puts 1
end

上は以下と等価である

class Object
  private
   def hoge
    puts 1
   end
end

トップレベルでの、メソッド定義は、Objectクラスで、privateの可視性で定義されている。

def hoge
    puts 1
end

Object.new.hoge #=> private method `hoge` called .... (NoMethodError)

なので、こうなる

Ruby 定数の参照順番 - Silver/Gold試験対策

定数は自クラスを参照し、その後、外側のクラスを参照する

class C1
  MSG = "msg1"
  MSG2 = "msg2"
  class C2
    MSG = "C2:msg1"
    puts MSG  #=> C2:msg1
    puts MSG2 #=> msg2
  end
  puts MSG #=> msg1
  puts MSG2 #=> msg2
end
MSG3=1
class A
  puts MSG3 #=> 1
end

Ruby DATA __END__ - Silver/Gold試験対策

DATAとEND。全て大文字

while DATA.gets
  puts $_ if $_ =~ /Ruby/
end #=> Ruby the prgoramming language
__END__
Java the prgoramming language
Ruby the prgoramming language
Python the prgoramming language

下記とほぼ同じ

DATA.each do |str|
  puts str if str =~ /Ruby/
end
__END__
Java the prgoramming language
Ruby the prgoramming language
Python the prgoramming language

String#=~とRegexp#=~があるので、 selfが文字列、otherが正規表現の場合だけでなくその逆でもマッチが検査できる

self =~ other

instance method String#=~ (Ruby 2.1.0)