R 筆記 - respond_to? / send

R筆記 - respond_to? / send

往常的禮拜一是公司部版的日子,而有時 cucumber 沒過或 sync 多了一些空白是家常便飯,不外乎重新再給他跑一次看看(local 沒問題,retry),或者是哪邊稍微修改等等…,結果這次卻到了快下班前才大致上到一個段落,原因想當然就是跟為標題有關,於是又有了這篇文章的誕生…

respond_to?

先來 Ruby doc 的定義

respond_to?(symbol, include_all=false) → true or falseclick to toggle source
respond_to?(string, include_all=false) → true or false
Returns true if obj responds to the given method. Private and protected methods are included in the search only if the optional second parameter evaluates to true.

我想有看過龍哥的 railsbook 中應該會有看過這段

1
2
3
4
5
6
7
def index
@users = User.all
respond_to do |format|
format.json { render json: @users }
format.html { render :index }
end
end

使用 respond_to 可以針對不同的格式(html 或 json)輸出不同的結果。除了用 respond_to 之外,讓我們接著看看另一種做法。

因此大致上了解了他的用法,不過跟定義有什麼關聯呢?讓我們看下去!

send

ㄧ樣也是先來看 Ruby doc 定義

send(symbol [, args…]) → objclick to toggle source
send(symbol [, args…]) → obj
send(string [, args…]) → obj
send(string [, args…]) → obj
Invokes the method identified by symbol, passing it any arguments specified. You can use send if the name send clashes with an existing method in obj. When the method is identified by a string, the string is converted to a symbol.

1
2
3
4
5
6
7
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"

再次的我想有看過龍哥的 railsbook 中應該有看過 private 方法 這段

1
2
3
kitty = Cat.new
kitty.gossip # => NoMethodError
kitty.send(:gossip) # => 我跟你說,你不要跟別人說喔!

不是說呼叫 private 方法的時候不能有明確的接收者嗎?執行 send 方法把 gossip 當做參數傳給它而已,並沒有明確的 receiver!

來個實例結合兩者吧!

1
2
3
4
obj = Object.new
obj.talk

#=> undefined method 'talk' for #<Object:0x12345678> (NoMethodError)

沒有 talk 這個 method,所以我們可以透過 respond_to? 做檢查,就可以確認是否有這個 method 可以用,避免產生error…

1
2
3
4
5
6
obj = Object.new
if obj.respond_to?("talk")
obj.talk
else
puts "Sorry, object can't talk!"
end

再來換換 send 的方式(前提是要先知道有這個方法)

1
2
obj.talk
obj.send("talk")

但優點在 process 執行時可以動態的呼叫不同 method,什麼意思?

1
2
3
4
5
6
7
8
9
10
puts "Search for: "
request = gets.chomp

if request == "writer"
puts book.writer
elsif request == "price"
puts book.price
elsif request == "date"
puts book.date
end

這時候就可以改成:

1
2
3
4
5
6
7
8
puts "Search for:"
request = gets.chomp

if book.respond_to?(request)
puts book.send(request)
else
puts "Input error"
end

所以我說再回到今天的問題…

原本寫 code 的人的邏輯想透過 respond_to? 來給值,途中會去讀另一個檔案的預設值 [],但卻犯了一個天大的錯誤大家也都沒有發現…

1
2
3
4
5
6
7
8
9
10
#=> xxx.rb
setting.value = respond_to?("default_#{key}".to_sym)

#=> zzz.rb
...
protected

def default_device_license_transfer_black_list
[]
end

而攝影大哥為了處理點新東西,在程式碼中多了三元運算子的判斷

1
setting.value = respond_to?("default_#{key}".to_sym) ? send("default_#{key}") : nil

於是就… 還記得前面的定義中埋點梗嘛?

Private and protected methods are included in the search only if the optional second parameter evaluates to true.

到底為什麼要把這種一點不 protected 的預設值設成 protected 呢?我想這又是另一個故事惹XD

參考資料