ruby&active support for expert 3

15
Ruby & ActiveSupport for expert 藤岡岳之(xibbar) Vol.3

Upload: xibbar

Post on 19-Jan-2015

703 views

Category:

Technology


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Ruby&Active Support for expert 3

Ruby & ActiveSupportfor expert藤岡岳之(xibbar)

Vol.3

Page 2: Ruby&Active Support for expert 3

このセッションって

xibbarこと藤岡が自分の勉強がてら気づいたことを発表するマニアックなセッションですrubyを詳しくというよりは、Railsのソースを読んでびっくりしたことから派生して、rubyとrailsの仕組みを調べた結果ですhttp://xibbar.net/rails_tohoku/ にPDFを置いておきました。

Page 3: Ruby&Active Support for expert 3

今日の内容

ブロック、クロージャ、イテレータlambda、procSymbol#to_procの仕組み

Page 4: Ruby&Active Support for expert 3

ブロックとは{ puts "Hello, world" puts "Hello, world" puts "Hello, world"}

do puts "Hello, world" puts "Hello, world" puts "Hello, world"end

コードの塊

Page 5: Ruby&Active Support for expert 3

イテレータとは?

本来は繰り返しのためのものRubyは繰り返し以外にも使えるそのため、ブロック付きメソッド呼び出しというようになってきて、段々とイテレータとは呼ばなくなって来ているっぽい

[1,2,3].each{¦n¦ puts n}

open("/tmp/sample.txt","w"){¦f¦ f.write("Hello world\n")}

イテレータ !イテレータ

Page 6: Ruby&Active Support for expert 3

ブロックをオブジェクト化hello1 = Proc.new do puts "Hello, world" puts "Hello, world" puts "Hello, world"end

hello2 = proc do puts "Hello, world" puts "Hello, world" puts "Hello, world"end

hello3 = lambda do puts "Hello, world" puts "Hello, world" puts "Hello, world"end

hello1.callhello2.callhello3.call

% ruby sample2.rbHello, worldHello, worldHello, worldHello, worldHello, worldHello, worldHello, worldHello, worldHello, world

解説ポイント•Proc.newとprocと

lambdaの違い•callで呼び出される

Page 7: Ruby&Active Support for expert 3

ブロックを関数のように

sum = lambda {¦x,y¦ x + y}

puts sum.call(2,3)

% ruby sample3.rb5

解説ポイント•できることはわかったけど、どういう時に便利かなぁ。

Page 8: Ruby&Active Support for expert 3

ブロック付メソッド呼出

class Foo def three(&arg) arg.call yield yield endend

foo=Foo.newfoo.three{ puts "Hello world"}

% ruby sample4.rb Hello worldHello worldHello world

解説ポイント•単に3回ブロックの中を繰り返すだけのメソッド

•yieldでメソッドの中からブロックが呼び出されるのがキモ

Page 9: Ruby&Active Support for expert 3

ブロックに引数を渡す

class Foo def my_logger(filepath,&arg) file=open(filepath,"w") arg.call(file) file.close endend

foo=Foo.newfoo.my_logger("log.txt"){¦file¦ puts "Hello world" file.write "Hello world logging.\n"}

% ruby sample5.rb Hello world

% cat log.txt Hello world logging.

解説ポイント•ブロックの中で使えるロガーもどき•繰り返しだけがブロックではないという気合い

Page 10: Ruby&Active Support for expert 3

Procをメソッドに渡すclass Foo def my_logger(filepath) file=open(filepath,"w") yield(file) file.close endend

foo=Foo.newscript=proc{¦file¦ puts "Hello world" file.write "Hello world logging.\n"}foo.my_logger("log.txt",&script)

% ruby sample6.rb Hello world

% cat log.txt Hello world logging.

解説ポイント•ブロックの代わりにブロックオブジェクトを渡せる。

•&をつける必要あり。

class Foo def my_logger(filepath) file=open(filepath,"w") yield(file) file.close endend

foo=Foo.newfoo.my_logger("log.txt"){¦file¦ puts "Hello world" file.write "Hello world logging.\n"}

Page 11: Ruby&Active Support for expert 3

クロージャrubyのブロックはクロージャ

def counter_closure count = 0 lambda {¦n¦ count += n }end

count = 10counter = counter_closureputs counter.call(1)puts counter.call(2)puts counter.call(3)puts counter.call(4)counter = counter_closureputs counter.call(5)puts counter.call(6)

% ruby sample8.rb13610511

解説ポイント•ブロックの中は変数を保持し続けている。•callされた時に初期化されたりしない。•作りなおされると、そこで最初からになる•他の言語を知らないから、あんまり突っ込まないで^^;

•Cだったら関数ポインタで実現するしかないよなぁ。。。

クロージャとは引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決する関数のこと。やっぱりよくわからんが。。。他の言語の不便さを体感しないと無理かなぁ。コード中に別環境のコードを書く機能があるかどうかだと思うんだけど。。。自信なし。でも便利。

Page 12: Ruby&Active Support for expert 3

Symbol#to_proc# The same as people.collect { ¦p¦ p.name }people.collect(&:name)

# The same as people.select { ¦p¦ p.manager? }.collect { ¦p¦ p.salary }people.select(&:manager?).collect(&:salary)

マニュアルより

class Symbol def to_proc Proc.new { ¦*args¦ args.shift.__send__(self, *args) } endend

ソースはたったの1行

とっても便利で、冗長だった部分がDRYで嬉しいんだけど、なんでこうなるの???

Page 13: Ruby&Active Support for expert 3

to_procってそもそも?マニュアルより

class Foo def to_proc Proc.new {¦v¦ p v} endend

[1,2,3].each(&Foo.new)

=> 1 2 3

つまりブロックに渡すとto_procの中身をブロックの代わりに実行する。

to_proc メソッドを持つオブジェクトならば、`&' 修飾した引数として渡すことができます(デフォルトで Proc、Method オブジェクトは共に to_proc メソッドを持ちます)。to_proc

はメソッド呼び出し時に実行され、Proc オブジェクトを返すことが期待されます。

Page 14: Ruby&Active Support for expert 3

Symbol#to_procは

よーく見ると、args[0]をsendしている。selfは呼出し元なので、下の場合は:emailになる。User.find(:all).map{|user|user.email}とUser.find(:all).map(&:email)が等価になる。なんでシンボルを与えて、メソッドが返って来るかがわかる。send(:email)ってな具合に評価されるよ!ってのを覚えておくといいと思います。modelに独自メソッドを定義した時も呼び出せます。

class Symbol def to_proc Proc.new { ¦*args¦ args.shift.__send__(self, *args) } endend==>> user.__send__(:email) の繰り返しになる

Page 15: Ruby&Active Support for expert 3

おしまい

おしまい次回以降予定継続method_missingfind_by_email_and_nameってどういう仕組み?erb、bindings