[Ruby] Block 應用

陳漢庭
7 min readNov 7, 2020

--

範例
結果

情境

bookstore_data 為從書店排行榜爬取下來的資料。中文英文 為第一層分類,中文裡面的中文書中文文學,以及英文底下的英文書英文文學為第二層分類。

API的行為在這裡為query_by_genre。當query中文,回傳中文對應的value,也就是內容為{'中文書': [...], '中文文學': [...]} 的區塊。

這邊想做的事情為將第二層分類的內容關聯到商品,我們用related_product模擬類似的行為。實際上我想要做的事情為利用排行榜的資料找出商品資料

使用 yield

目前的需求為改變hashvalue,這時候想到的概念為Higher-Order function。如果我可以對每一個value 處理的話,Javascript可以利用傳變數的方式把參數傳進去。Ruby的也有類似的方式,這種方式稱為block,我們可以利用block 解決目前的問題。block 的概念為將一段程式碼的控制權暫時拿出來並回傳結果回去,以上方的例子來說,就是把 value 拿出來做 related_product 的處理完再丟回去,最後的結果就會將第二層分類下的value關聯商品的動作。

下例為將上方的例子做簡化:

簡單block應用

我們把原本要做的事情簡化。上面的輸出結果為所有的value都被加了兩個波浪符號。值得一提的是,把動作用decorator 包起來,亦即未來如果資料需要做block處理,可以利用functional的方式處理資料。

{:colour=>"red~~", :size=>"一手掌握~~"}

如果把上述的yield(value) 改成 yield,輸出結果則為

{:colour=>"~~", :size=>"~~"}

yield 其他寫法

上方的寫法1到寫法3,意思都一樣。

使用Proc

如果不用&算符可以用上面的寫法,這種寫法更像是 javascript 的 function 利用變數的方式傳下去。

我們還可以用組合技,讓很多的proc結合在一起,如下方程式碼所示。

輸出結果

什麼是 &

& 可以讓 Proc 變回 block 代入方法中。這樣講有點抽象,實際舉個例子:

上面的&plus_one&plus為將原本的proc轉回block使用

&搭配symbol的組合搭配,上面的寫法為symbol.to_proc的語法糖。

上述的 symbol.to_proc 可以寫為 -> (x) {x.symbol}

這邊 symbol的角色就跟上面的plus_oneplus一樣都為proc。上述的:succ, :to_i, :to_s, :&, :+ 等特殊符號可以轉為proc ,因為這些符號都有to_proc的方法。

上面為附有to_proc方法的symbol ,相關連結可以參考這篇

寫了新的class覆寫原本的方法,可以看到此時的self指的是to_s ,我們也可以利用類似的方式客製化的class

Symbol#to_proc 常見問題

能不能像使用保留字一樣使用symbol.to_proc

array.map { |x| x.<方法1>.<方法2>.<方法3> }

改成下列寫法可以嗎?

array.map(&:<方法1>.<方法2>.<方法3>)

答案是不行,但我們可以自己做

def custom_method(x)
x.<方法1>.<方法2>.<方法3>
end

並使用method(或send

array.map(&method(:custom_method))

或者使用lambda

# 方式1
def custom_method(x)
x.<方法1>.<方法2>.<方法3>
end
array.map(& ->(x) { x.custom_method })
# 方式2
array.map(& ->(x) { x.<方法1>.<方法2>.<方法3> })

# 方式3
custom_method = ->(x) { x.<方法1>.<方法2>.<方法3> }
array.map(&custom_method)

Javascript 對應

印出來的結果為

{ colour: "red~~", size: "一手掌握~~" }

transform_values

關於上述的reformat_hash的寫法一共有4種。如果是單純渲染,最優雅的用法為transform_values

參考資料:

--

--

陳漢庭
陳漢庭

Written by 陳漢庭

由於零散的紀錄過了一段時間之後就看不懂了,於是為了強迫自己用故事的方式記錄學到的東西,就開啟我的發文之路。

No responses yet