情境
bookstore_data 為從書店排行榜爬取下來的資料。中文
、英文
為第一層分類,中文
裡面的中文書
、中文文學
,以及英文
底下的英文書
、英文文學
為第二層分類。
API的行為在這裡為query_by_genre
。當query中文
,回傳中文
對應的value,也就是內容為{'中文書': [...], '中文文學': [...]}
的區塊。
這邊想做的事情為將第二層分類的內容關聯到商品,我們用related_product
模擬類似的行為。實際上我想要做的事情為利用排行榜的資料找出商品資料
使用 yield
目前的需求為改變hash
的value
,這時候想到的概念為Higher-Order function
。如果我可以對每一個value
處理的話,Javascript可以利用傳變數的方式把參數傳進去。Ruby
的也有類似的方式,這種方式稱為block
,我們可以利用block
解決目前的問題。block 的概念為將一段程式碼的控制權暫時拿出來並回傳結果回去,以上方的例子來說,就是把 value
拿出來做 related_product
的處理完再丟回去,最後的結果就會將第二層分類下的value
做關聯商品
的動作。
下例為將上方的例子做簡化:
我們把原本要做的事情簡化。上面的輸出結果為所有的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_one
、plus
一樣都為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>
endarray.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
。
參考資料: