ie-developers / ie-questions

public questions for ie students.
10 stars 0 forks source link

eachメソッドの先にnilがある。 #14

Closed kazuminn closed 9 years ago

kazuminn commented 9 years ago

ruby 2.1.5 mac ox 10.10

https://github.com/kazuminn/twitter_/blob/master/kusoripu.rb (コンセプトはreadme見てください。) こちらのコード16行目の配列でnilが入ってると、その先の n_reply_to_screen_nameメソッドはレシーバーがnilだとエラーが起きちゃうわけです。 compact!メソッドをeachの前に入れても、破壊されたものがNillclassのものなので eachはダメだと怒られちゃいます。

どうすればよいでしょうか。

atton commented 9 years ago

えーっと。ちょっと整理したいのだけれど 配列に nil が入ることがあるので compact したい、ってのはokです。

compact!メソッドをeachの前に入れても、破壊されたものがNillclassのものなので

ってのが良く分からないです。 どういう風に実行した時に何が起きて何がダメかちょっとまとめてみましょう (あと、このコードそのままじゃ動かない気もします……)

atton commented 9 years ago

あとエスパーすると nil な時にまずいのは x.in_reply_to_screen_name な気がする。 こんな感じ?

client = Twitter::REST::Client.new do |config|
  config.consumer_key = "fQDpM4Hf9W3c6n3X5heJwLZ74"
  config.consumer_secret = "wlx82Y2zLx0PvAnW6OTjVNBWa2uJjlwysHgCa70iFq8NG0MSNx"
  config.access_token = "2416079641-KZuLIT277rtE1EoNQoq6HcC65wcyAMGkt7f4QOe"
  config.access_token_secret = "BG4FSx2iXMztvwYQ8GAm9j2qfSBtHQBAfVFcYOl0cfB3V"
end

hash = {}
client.user_timeline("warugaki_kazumi").each do |x|
  screen_name = x.in_reply_to_screen_name
  unless screen_name.nil?
    unless hash.has_key?(screen_name) then
      hash[x.in_reply_to_screen_name] = 1
    else
      hash[x.in_reply_to_screen_name] = 2
    end
  end
end

hash.each do |key,value|
  if value.to_i == 1
    client.update("@warugaki_kazumiは、" + key + "さんにクソリプをしている可能性があります。")
  end
end
atton commented 9 years ago

あと細かいところ

kazuminn commented 9 years ago
hanachin commented 9 years ago

@atton- consumer_secretaccess_token_secretベタ書きで貼るのは不味いのでは

hanachin commented 9 years ago

エスパーすると

client.user_timeline("warugaki_kazumi") # => nil

のときにeachを呼ぶと

client.user_timeline("warugaki_kazumi").each do # nil.eachしてるのでエラー

みたいな感じですか?

kazuminn commented 9 years ago

@atton- さん @hanachin  さん tokenの件は、regenerateしたので大丈夫です。

kazuminn commented 9 years ago

事の発端は、

client.user_timeline("warugaki_kazumi").each do

だと、 x.in_reply_to_screen_nameがxがnilの時エラー

で、nilを消そうとcompact!

client.user_timeline("warugaki_kazumi").compact!.each do

ってすると、compact!によって破壊されたものはNilクラスのインスタンスなので、 eachメソッドを使うとエラーがでるよー。で

破壊しないようにcompact

client.user_timeline("warugaki_kazumi").compact.each do

 だが、

kusoripu.rb:15:in `block in <main>': can't convert Twitter::NullObject to Integer (Twitter::NullObject#to_int gives Twitter::NullObject) (TypeError)

と激おこ。

nil消したはずなのに「あれー?」って感じですね。

kazuminn commented 9 years ago

細かいことを付け足すと

client.user_timeline("warugaki_kazumi").each do # nil.eachしてるのでエラー

ってのは、厳密にはnill.eachしてないので、エラーにならないのでは。

client.user_timeline("warugaki_kazumi").compact!.class #Nillクラス

これ、compact!で破壊されたものはNillクラスのインスタンスなんですね。

hanachin commented 9 years ago

compactcompact!は動作が違いますね。compact!で何も変更がなかった場合nilが返ります

compact は自身から nil を取り除いた配列を生成して返します。 compact! は自身から破壊的に nil を取り除き、変更が 行われた場合は self を、そうでなければ nil を返します。 http://docs.ruby-lang.org/ja/2.2.0/method/Array/i/compact.html

kazuminn commented 9 years ago

@hanachin さん   なるほどです。   compactを使えばいいのですね。

でも

kusoripu.rb:15:in `block in <main>': can't convert Twitter::NullObject to Integer (Twitter::NullObject#to_int gives Twitter::NullObject) (TypeError

と怒られます。

  

atton commented 9 years ago

compact は client.user_timeline("warugaki_kazumi") の中身に nil がある時に消します。

今回 nil なのは client.user_timeline("warugaki_kazumi") の中身の tweet の in_reply_to_screen_name なので、 each に失敗してるんじゃなくて hash への代入に失敗してますね

kazuminn commented 9 years ago

https://gist.github.com/atton-/ea9178765cf4fcdfcc83

https://twitter.com/_atton/status/578177683873349632

hash で返るものには to_int が必要

ってhash methodの戻り値のオブジェクトにはto_intなinstance methodを持っていなければならない って解釈でいいです?

atton commented 9 years ago

ってhash methodの戻り値のオブジェクトにはto_intなinstance methodを持っていなければならない って解釈でいいです?

その解釈であってます。 ちなみにこれが原因でどのようなことが起こってるか説明できます?

kazuminn commented 9 years ago

to_int methodを持っていないから、hashインスタンスのkeyにできない事案が起こっている。

ですかね?

atton commented 9 years ago

だいたいあってます。 key にしようとして to_int が存在していないものは何です?

kazuminn commented 9 years ago

HasHashMethod.new オブジェクトですよね。

atton commented 9 years ago

あーっと。私の gist じゃなくて君のコードの方ね。

kazuminn commented 9 years ago

あ。x.in_reply_to_screen_nameの戻り値。ですかね。

atton commented 9 years ago

そうそう正解。

だから、

kusoripu.rb:15:in `block in

': can't convert Twitter::NullObject to Integer (Twitter::NullObject#to_int gives Twitter::NullObject) (TypeError

のエラーは each とか compact が問題ではなくて、 x.in_reply_to_screen_name の object を hash の key にしてるのが問題、というお話でした

kazuminn commented 9 years ago

あ、なるほどです。

hashではなくて他のものにすれば、動きそうですね。

よくわかりました。ありがとうございました。