ruby&active support for expert 3

Post on 19-Jan-2015

703 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

Ruby & ActiveSupportfor expert藤岡岳之(xibbar)

Vol.3

このセッションって

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

今日の内容

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

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

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

コードの塊

イテレータとは?

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

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

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

イテレータ !イテレータ

ブロックをオブジェクト化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で呼び出される

ブロックを関数のように

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

puts sum.call(2,3)

% ruby sample3.rb5

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

ブロック付メソッド呼出

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でメソッドの中からブロックが呼び出されるのがキモ

ブロックに引数を渡す

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.

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

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"}

クロージャ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だったら関数ポインタで実現するしかないよなぁ。。。

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

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で嬉しいんだけど、なんでこうなるの???

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 オブジェクトを返すことが期待されます。

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) の繰り返しになる

おしまい

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

top related