TwitterGemを使うときは困ったらとりあえずto_hするべし

# tl;dr
TwitterGemを使うときの返り値のクラスは、基本的に`Enumerable`をincludeしているので雑に`to_h`しちゃって取るのが楽そうです。
# この記事のスコープ
TwitterGemを介してTwitterAPIを叩き、ツイートの取得を行うところまで。個人的に詰まったポイントがあったのでそこも併せて共有できたらなと思って書きました。
# TwitterGemとは
RubyでTwitterAPIを操作できるようになるgemです。[リポジトリはここから](https://github.com/sferik/twitter)
APIを叩くためにはTwitter社に対して申請をする必要がありますが、その具体的な方法については本記事では割愛します。
英語で利用目的などを書かないといけないためウッとなりますが、Google翻訳を駆使しながら書いた~~ガバガバ~~英語でもapproveされたので、構える必要はないと思ってます。
# インストール
普通に

```ruby
gem install twitter
```
するか、Gemfileに書いて

```ruby
bundle
```

しましょう。
READMEにはサポートされているRubyバージョンとして、2.3 ~ 2.5 が挙げられていますが、筆者の環境では2.6.3でも問題なく動作しています。きっと。
# 準備
まずはrequireしましょう

```ruby
require 'twitter'
```

次にAPIを叩く用のclientを生成します

```ruby
class Twitter
  def initialize
    @client = Twitter::REST::Client.new |config|
       config.consumer_key = "consumer_key"
       config.consumer_secret = "consumer_secret"
       config.access_token = "access_token"
       config.access_token_secret = "access_token_secret"
    end
  end
end
```

それぞれキーを突っ込んであげてください。
これで準備完了です。簡単ですね。

# 使い方
[Rubyで簡単なTwitter クライアントをつくる](https://qiita.com/shimisunet/items/c3a0b93fb13fa82ed8be) をぜひ参照しましょう。私もお世話になりました。リンク先の記事では

- タイムラインの取得
- リプライの取得
- 特定のリストのタイムラインを取得
- ツイート

を紹介しています。

本記事では

- ユーザの詳細情報の取得
- ツイートごとの詳細情報の取得

これらを紹介するとともにハマったポイントについてご紹介できればと思っています。
# Twitterユーザの詳細情報を取得
## リストを指定しユーザを取得する
`list_members`というメソッドに、ユーザ名とリスト名を与えてあげることで取得することができます。この結果は、`TwitterClient::Cursor`クラスのインスタンスとして返ってきます。こいつは`Enumerable`をincludeしているのでArrayやHashと同様に`each`を使ってごにょごにょできます。便利です。

```irb
[1] pry(#<TwitterClient>)> @client.list_members('twitterのユーザ名', 'リスト名').class
=> Twitter::Cursor
[2] pry(#<TwitterClient>)> @client.list_members('twitterのユーザ名', 'リスト名').class.include?(Enumerable)
=> true
```


コード例

```ruby
class Twitter
  def initialize
    ...
  end

  # リストに属しているユーザをArrayとして取得する
  def fetch_list_users
    list_members('twitterのユーザ名', 'リスト名').each_with_object([]) do |user, arr|
      arr << member
    end
  end
end
```

## Twitter::User
サンプルとして
https://twitter.com/hurugisuko ( 私の好きなネットの古着屋さん ) を使いました。

```irb
[1] pry(#<TwitterClient>)> user = list_members('twitterのユーザ名', 'リスト名').first
=> #<Twitter::User id=1111913399225450496>
# ユーザの名前を取ってくる
[2] pry(#<TwitterClient>)> user.name
=> "古着屋 Hurugisuko"
# プロフURL
[3] pry(#<TwitterClient>)> user.url
=> #<Addressable::URI:0x3fd4935192c4 URI:https://twitter.com/hurugisuko>
# AddressableからURLへ変換
[4] pry(#<TwitterClient>)> user.url.to_s
=> "https://twitter.com/hurugisuko"
# プロフィール画像を取ってくる
[5] pry(#<TwitterClient>)> user.profile_image_url_https
=> #<Addressable::URI:0x3fd491727798 URI:https://pbs.twimg.com/profile_images/1113260900587147264/xVaQa0Lc_normal.jpg>
# URLだけ抽出
[6] pry(#<TwitterClient>)> user.profile_image_url_https.to_s
=> "https://pbs.twimg.com/profile_images/1113260900587147264/xVaQa0Lc_normal.jpg"
# 自己紹介情報を取ってくる
[7] pry(#<TwitterClient>)> user.description
=> "若い世代に向け、「お金をかけないオシャレ」「唯一無二のスタイル」をコンセプトに幅広く古着を販売しています。 Hurugisukoは2人の人間で管理・運営を行っています。「生活に小さな彩りを添える」がコンセプトのハンドメイド作品たちはこちらから→@hurugisukohh"
```

色々取れますね。
### ハマったところ
<img width="580" alt="古着屋 Hurugisuko（@hurugisuko）さん : Twitter 2019-11-22 09-21-57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236813/40ab4a9b-1904-7c0a-1b05-52af9eda1e8c.png">
この赤枠部分のURLどうやって取るんだろうってところ。
`user.url`はtwitterのURLに飛んでしまうし。。
### 解決方法
```
user.to_h[:url]
=> "https://t.co/fiupN9eIDi"
```
URLを叩くとメルカリの画面へ遷移できているかと思います。
`Twitter::User`クラスに対して、to_hでhash化してキーを与えることで取得しています。
メソッドとして定義されているものと、to_hとキーで取ってくる2つのパターンがある、ということが大事なポイントです。
# ツイートごとの詳細な情報
## 特定のユーザのツイートを取ってくる
`user_timeline`というメソッドに、`user_id(Twitter::User#id)`を与えてあげることでそのユーザのツイート(デフォルトで20件)取得することができます。

```.irb
[1] pry(#<TwitterClient>)> @client.user_timeline(twitter_user_id)
=> [#<Twitter::Tweet id=1198931529931427840>,
    ...
   ]
```

コード例

```ruby
class Twitter
  def initialize
    ...
  end

  # 特定のユーザのツイートを取ってくる
  def tweets(account)
    @client.user_timeline(account, opt)
    end
  end

  def opt
    { count: 10 }
  end
end
```

このメソッドにはオプションを渡すことができて、例えば`@client.user_timeline(twitter_user_id, count: 10)`とすれば、10件のツイートを取ってきてくれます。
他のオプションについては[rubydoc](https://www.rubydoc.info/gems/twitter/4.0.0/Twitter%2FAPI:user_timeline)が参考になるかと思います。 
## Twitter::Tweet
```.irb
[1] pry(#<TwitterClient>)> t = @client.user_timeline(account, count: 10).first
=> #<Twitter::Tweet id=1200744305482031107>
# ツイート内容の取得
[2] pry(#<TwitterClient>)> t.text
=> "coming soon...\n\n☑︎12/1（日） 23時発売開始‼︎\nhttps://t.co/aVf7vUNRIT https://t.co/b77r7AvC0i"
# メディアの取得
[3] pry(#<TwitterClient>)> t.media
=> [#<Twitter::Media::Photo id=1200744297571602434>,
    #<Twitter::Media::Photo id=1200744297567375362>,
    #<Twitter::Media::Photo id=1200744297693237250>,
    #<Twitter::Media::Photo id=1200744297575804928>]
# 画像のURLを取得
[4] pry(#<TwitterClient>)> t.media.first.media_url_https
=> #<Addressable::URI:0x3fe8da8c19d4 URI:https://pbs.twimg.com/media/EKnmk6rU0AIbZuV.jpg>
[5] pry(#<TwitterClient>)> t.media.first.media_url_https.to_s
=> "https://pbs.twimg.com/media/EKnmk6rU0AIbZuV.jpg"
```
こちらも同様に色々できます。
### 困ったところ
たまに`Twitter:Tweet#text`で全文を取得できないケースがあります。(`...`として省略されている)
調べると、twitterAPIの仕様変更があって、長いつぶやきは省略されてしまうそう。ref: [アップデートの情報](https://developer.twitter.com/en/docs/tweets/tweet-updates) 
~~とりあえず雑に~~`to_h`すると、`:truncated`というキーがあり、textが省略されているツイートは、ここがtrueになっていました。
さらに調べると、`truncated` がtrueになっているツイートでは、前述した`Twitter:Tweet#media`で画像情報も取得することができませんでした。これは困った。

```.irb
[1] pry(#<TwitterClient>)> tweet.text
=> "【 yutori online store new arrival 】\n☑︎12/1（日）23時新商品入荷‼︎\n\nいよいよ12月に突入です☃️‼️\n\n12月最初の入荷は使いやすいブルゾンからセーター&amp;スウェットを多めにピックアップ… https://t.co/waU8pfXuo1"
[2] pry(#<TwitterClient>)> tweet.to_h[:truncated]
=> true 
[3] pry(#<TwitterClient>)> tweet.media
=> []
[4] pry(#<TwitterClient>)> tweet.id
=> 1200755654043918336
```

### 解決方法
`user_timeline` へのオプションとして、`{ tweet_mode: 'extended' }` を渡すことで、長いツイートでも全文および画像の取得ができました。ただし、ツイートの全文取得はインターフェースが変わるので注意が必要です。

```.irb
# { tweet_mode: 'extended' } を指定してuser_timelineを叩く
# tweet.idは上記の[4]と同じ
[1] pry(#<TwitterClient>)> tweet.id
=> 1200755654043918336
[2] pry(#<TwitterClient>)> tweet.to_h[:truncated]
=> false
# Twitter#Tweet#full_text は定義されていないのでto_h経由で取得する
[3] pry(#<TwitterClient>)> t.to_h[:full_text]
=> "【 yutori online store new arrival 】\n☑︎12/1（日）23時新商品入荷‼︎\n\nいよいよ12月に突入です☃️‼️\n\n12月最初の入荷は使いやすいブルゾンからセーター&amp;スウェットを多めにピックアップ🔥\n\nお気に入りのアウターに合わせる1着を是非見つけて下さい💕\n\n良ければリツイート宜しくお願い致します🙇‍♂️✨ https://t.co/8LKvQ35PJu"
[4] pry(#<TwitterClient>)> t.media
=> [#<Twitter::Media::Photo id=1200755645940502531>,
    #<Twitter::Media::Photo id=1200755645936357377>,
    #<Twitter::Media::Photo id=1200755645944696832>,
    #<Twitter::Media::Photo id=1200755646204760064>]
```
# 結論 (再掲)
TwitterGemを使うときの返り値のクラスは、基本的に`Enumerable`をincludeしているので雑に`to_h`しちゃって取るのが楽そうです。