discordbot(Ruby)でGoogleSpreadSheetの内容を呼び出し

ストックじゃなくていいねください。


# 事前準備
discordのbotを作成してる前提で進めていきます。
[前回](https://qiita.com/fishkiller/items/3e036ad7ef1cb0c716e1)を見ていただけたら簡単に作成できると思います。

# GoogleSpreadSheet
今回は[R6S持ちキャラ](https://docs.google.com/spreadsheets/d/1VHruuvXrQXxvfFxVpLi1mz050BJHHrLpe_itdWOlHys/edit?usp=sharing)というスプシを作成しました。
![ca045e63443d1367e245d344e6ecc26c.png](https://qiita-image-store.s3.amazonaws.com/0/209263/ca3118e2-f210-fc39-c489-cd80d6af6a7a.png)

# GoogleSpreadSheetのAPI
1. [Google Developers Console](https://console.developers.google.com/flows/enableapi?apiid=sheets.googleapis.com)でプロジェクトを作成してください。
2. ページの上部にあるOAuth 同意画面というタブをクリックし、メールアドレスを選択し、サービス名を入力してて保存してください。
3. 認証情報タブをクリックし、認証情報の作成をクリック。OAuthクライアントIDを選択してください。
4. アプリケーションの種類はその他、名前(自分で決めて)入力して作成をクリック。
5. 一番右のダウンロードをクリックし、JSONをダウンロード
![ea308b15ee7978971255c3ba0903c7b7.png](https://qiita-image-store.s3.amazonaws.com/0/209263/6a6462a4-f692-5c1e-f9ce-221e6876c850.png)
6.ダウンロードしたjsonの名前をclient_secret.jsonに変更し、作業ディレクトリに入れてください。

## gem 
```
$ gem install google-api-client
```
## Bundllerでインストール
```
source "https://rubygems.org"
gem "discordrb"
gem "google-api-client"
```
```
$ bundle install --path vendor/bundler
```
# source

```ruby:discord_bot.rb
#::RBNACL_LIBSODIUM_GEM_LIB_PATH = 'libsodium.dll' #windows用
require 'discordrb'
require 'google/apis/sheets_v4'
require 'googleauth'
require 'googleauth/stores/file_token_store'
require 'fileutils'


OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
APPLICATION_NAME = 'Google Sheets API Ruby Quickstart'
CLIENT_SECRETS_PATH = 'client_secret.json'
CREDENTIALS_PATH = File.join(Dir.home, '.credentials',
                             "sheets.googleapis.com-ruby-quickstart.yaml")
SCOPE = Google::Apis::SheetsV4::AUTH_SPREADSHEETS_READONLY
#ENV['SSL_CERT_FILE'] = File.expand_path('./cacert.pem') #windows用


def authorize
  FileUtils.mkdir_p(File.dirname(CREDENTIALS_PATH))

  client_id = Google::Auth::ClientId.from_file(CLIENT_SECRETS_PATH)
  token_store = Google::Auth::Stores::FileTokenStore.new(file: CREDENTIALS_PATH)
  authorizer = Google::Auth::UserAuthorizer.new(
    client_id, SCOPE, token_store)
  user_id = 'default'
  credentials = authorizer.get_credentials(user_id)
  if credentials.nil?
    url = authorizer.get_authorization_url(
      base_url: OOB_URI)
    puts "Open the following URL in the browser and enter the " +
         "resulting code after authorization"
    puts url
    code = gets
    credentials = authorizer.get_and_store_credentials_from_code(
      user_id: user_id, code: code, base_url: OOB_URI)
  end
  credentials
end

# Initialize the API
service = Google::Apis::SheetsV4::SheetsService.new
service.client_options.application_name = APPLICATION_NAME
service.authorization = authorize

spreadsheet_id = '1VHruuvXrQXxvfFxVpLi1mz050BJHHrLpe_itdWOlHys'#←スプシのID
range = '持ちキャラ一覧!A2:O12'
response = service.get_spreadsheet_values(spreadsheet_id, range)

bot = Discordrb::Bot.new token: 'discordのbotトークン'
puts "This bot's invite URL is #discordのサーバー招待URL"
puts 'Click on it to invite it to your server.'

####################################################
# plz User1 atkとdiscordに送信されると実行
bot.message(content: 'plz User1 atk') do |event|
    range = '持ちキャラ一覧!A3:O3'
    response = service.get_spreadsheet_values(spreadsheet_id, range)
    response.values.each do |row|
      event.respond "#{row[0]},#{row[1]}, #{row[2]}, #{row[3]}, #{row[4]}, #{row[5]}, #{row[6]}, #{row[7]}, #{row[9]}, #{row[10]}, #{row[11]}, #{row[12]}, #{row[13]}"
    end
  end

```

## bot実行
```
$ bundle exec ruby discord_bot
```

## Error
### sodiumに関するエラーが出た場合
- Mac OS   
```
$ brew install libsodium
```
- Windows    
1. [ここ](https://download.libsodium.org/libsodium/releases/)から最新版のlibsodium-x.x.x-msvc.zip(x.x.xはバージョン情報)をダウンロードしてください。
2. ダウンロードしたzipファイルから Win32/Release/v120/dynamic/ にあるlibsodium.dllを作業ディレクトリにコピーしてください。
3. 上記のプログラムソースの上位部にある
```
#::RBNACL_LIBSODIUM_GEM_LIB_PATH = 'libsodium.dll'
```
のコメントアウトを外してください。

### SSLに関するエラーが出た場合
- windows　　　
1. [ここ](http://curl.haxx.se/ca/cacert.pem)から証明書を作業ディレクトリに保存。
2. 上記のプログラムソース上位部にある
```
#ENV['SSL_CERT_FILE'] = File.expand_path('./cacert.pem')
```
のコメントアウトを外してください。

# おまけ
discordでコマンドを送信した人の保持キャラをスプシから参照してdiscordにpostします。

```ruby:discord_bot.rb
#atk
randatk = {}
attacker = ''
bot.message(content: 'rand atk') do |event|
 if "#{event.user.name}" == 'ユーザー1' then
   range = '持ちキャラ一覧!A3:O3'
 elsif "#{event.user.name}" == 'ユーザー2' then
   range = '持ちキャラ一覧!A4:O4'
 elsif "#{event.user.name}" == 'ユーザー3' then
   range = '持ちキャラ一覧!A5:O5'
 elsif "#{event.user.name}" == 'ユーザー4' then
   range = '持ちキャラ一覧!A6:O6'
 elsif "#{event.user.name}" == 'ユーザー5' then
   range = '持ちキャラ一覧!A7:O7'
 end
 response = service.get_spreadsheet_values(spreadsheet_id, range)
 response.values.each do |row|
   randatk = ["#{row[1]}", "#{row[2]}", "#{row[3]}", "#{row[4]}", "#{row[5]}", "#{row[6]}", "#{row[7]}", "#{row[9]}","#{row[10]}",
   "#{row[11]}", "#{row[12]}", "#{row[13]}"]
   randatk.delete_if{|v| v == "#{row[14]}"}
   attacker = randatk.sample
   if attacker.length == 0 then
     event.respond "Null"
   end
   event.respond "#{attacker}"
 end
end
#def
randdef = {}
defender = ''
bot.message(content: 'rand def') do |event|
 if "#{event.user.name}" == 'ユーザー1' then
   range = '持ちキャラ一覧!A10:O10'
 elsif "#{event.user.name}" == 'ユーザー2' then
   range = '持ちキャラ一覧!A11:O11'
 elsif "#{event.user.name}" == 'ユーザー3' then
   range = '持ちキャラ一覧!A12:O12'
 elsif "#{event.user.name}" == 'ユーザー4' then
   range = '持ちキャラ一覧!A13:O13'
 elsif "#{event.user.name}" == 'ユーザー5' then
   range = '持ちキャラ一覧!A14:O14'
 end
 response = service.get_spreadsheet_values(spreadsheet_id, range)
 response.values.each do |row|
   randdef = ["#{row[1]}", "#{row[2]}", "#{row[3]}", "#{row[4]}", "#{row[5]}", "#{row[6]}", "#{row[7]}", "#{row[9]}","#{row[10]}",
   "#{row[11]}", "#{row[12]}", "#{row[13]}"]
   randdef.delete_if{|v| v == "#{row[14]}"}
   defender = randdef.sample
   if defender.length == 0 then
     event.respond "Null"
   end
   event.respond "#{defender}"
 end
end
```


#次はスプシの更新時にdiscordにポスト
[次](https://qiita.com/fishkiller/items/369035f70c4ff4c4677b)はスプシの更新時にスプシの内容をdiscordにpostさせます。