Rubyのgemを使う！ | 初めてのプログラミング実践 ②

Rubyのgemを使ってみたいと思います。
gemの解説は次の記事を参考にさせていただきました！

https://techplay.jp/column/529

##パッケージとしてのgem
Rubyのパッケージとは、プログラムの部品で便利な機能をひとまとめにしたものです。同じくプログラミング言語であるPythonではライブラリと呼んだりします。先人が開発した便利な機能を活用させていただくことで、１からコードを書くことなく、便利な機能を使うことができます。

Railsで開発を行う際には多くのgemの力を借りることになると思います。ユーザー認証機能の"devise"や、グラフを作るための"chartkick"なんていうgemもあります。

##パッケージ管理システムとしてのgem "bundler"
bundlerとはgemを管理するためのツールで、bundler自体もgemの一種です。bundlerを使うことで、複数のgemの依存関係を保ちながらgemの管理ができます。

##gemのインストール状態を確認してみる
次のコマンドで確認していきましょう。

まずパッケージ管理システムとしてのbundlerを確認してみます。

```terminal
$ gem list bundler

*** LOCAL GEMS ***

bundler (2.2.14, 2.1.4, 1.17.3, default: 1.17.2)
```

次に全てのgemをみてみます。私はこのようになりました。

```terminal
$ gem list

*** LOCAL GEMS ***

awesome_print (1.8.0)
bigdecimal (default: 1.4.1)
bundler (2.2.14, 2.1.4, 1.17.3, default: 1.17.2)
byebug (11.1.3)
cmath (default: 1.0.0)
csv (default: 3.0.9)
curl (0.0.9)
date (default: 2.0.0)
dbm (default: 1.0.0)
did_you_mean (1.3.0)
e2mmap (default: 0.1.0)
etc (default: 1.0.1)
fcntl (default: 1.0.0)
fiddle (default: 1.0.0)
fileutils (default: 1.1.0)
forwardable (default: 1.2.0)
gdbm (default: 2.0.0)
holiday_japan (1.4.4)
io-console (default: 0.4.7)
ipaddr (default: 1.2.2)
irb (default: 1.0.0)
json (default: 2.1.0)
logger (default: 1.3.0)
matrix (default: 0.1.0)
minitest (5.11.3)
mutex_m (default: 0.1.0)
mysql2 (0.5.2)
net-telnet (0.2.0)
nokogiri (1.11.1 x86_64-darwin)
openssl (default: 2.1.2)
ostruct (default: 0.1.0)
power_assert (1.1.3)
prime (default: 0.1.0)
psych (default: 3.1.0)
racc (1.5.2)
rake (12.3.3)
rdoc (default: 6.1.2)
rexml (default: 3.1.9)
rss (default: 0.2.7)
scanf (default: 1.0.0)
sdbm (default: 1.0.0)
shell (default: 0.7)
stringio (default: 0.0.2)
strscan (default: 1.0.0)
sync (default: 0.5.0)
test-unit (3.2.9)
thwait (default: 0.1.0)
tracer (default: 0.1.0)
unidecoder (1.1.2)
webrick (default: 1.4.2)
xmlrpc (0.3.0)
zlib (default: 1.0.0)

```

##gemのインストール方法
bundlerのインストール方法はこちらを参考にさせていただきました。

https://www.sejuku.net/blog/19426

では早速、今回の目的のgem "holiday_japan"をインストールしていきます。

###日本の祝日判定Rubyプログラム
1948年7月20日以降の日本の国民の祝日、振替休日、および国民の休日を計算して判定してくれるとのこと。

次のようにコマンドを打つとgemのインストールができます。

```terminal
$ gem install holiday_japan
```

gemのインストールは以上ですので簡単ですね！

##Rubyのプログラムを作ってみる

それでは"holiday_japan"を活用して、今年のカレンダーをCSVで出力するプログラムを作ってみます。

###gemを呼び出す
Rubyプログラムの中でインストール済みのgemを呼び出すには次のようにします。

```ruby:Ruby
require 'csv'
require 'date'
require 'holiday_japan'
```

今回は"csv"と"date"というgemも使っています。

###出力するカレンダーの期間を指定する
始まりの日付と終わりの日付をプログラム内で指定してあげるとうまくいきそうです。

```terminal
start_date = Date.parse("20210101")
end_date = Date.parse("20211231")
```

Date.parse(20210101)が初見の方は混乱するかもしれません。
irbで確認してみると次のようになります。

```terminal
irb(main):001:0> require "date"
irb(main):002:0> Date.parse("20210101")
=> #<Date: 2021-01-01 ((2459216j,0s,0n),+0s,2299161j)>
```

つまり、"20210101"のような文字列を、Rubyが日付として認識できるカタチに宜しくしてくれるんですね。

###CSVを出力する

gemの"csv"を使うことでCSVが出力されます。
今回は詳しく説明しませんが、次のようなカタチを基本にしていただけると、使い回しができると思います。

```ruby:Ruby
CSV.open('./calender.csv', 'w', headers: true) do |csv|
  csv << ['年','月','日','曜日','祝日']
  csv << [2021, 1, 1,  "金曜日", "元日"]
end
```

最初に表のヘッダー部分を作成し...

```ruby
csv << ['年','月','日','曜日','祝日']
```

その後に全ての日付と曜日と祝日の名前を、１行ずつ差し込んでいきます。

```ruby
csv << [2021, 1, 1,  "金曜日", "元日"]
```

もちろん、全ての日付を手入力するくらいなら、エクセルで作った方が早い...となってしまうので、ここは「繰り返し処理」を使ってプログラムしていきます。

###holiday_japanの使い方
詳しくはgithubの説明をご覧ください。

https://github.com/masa16/holiday_japan

今回はDateで用意した日付の祝日名を知りたいので、.nameを使います。

```ruby
HolidayJapan.name(Date.parse("20210101"))
=> "元日"
```

###祝日ではない日の取扱
祝日でない日は空の文字列をCSVに書き込んでおきたいと思います。
「条件分岐」を使って、祝日であればその名前を変数（holiday_name）に代入し、祝日でなければからの文字列（""）を変数（holiday_name）に代入します。

```ruby
unless HolidayJapan.name(start_date).nil? then
  holiday_name = HolidayJapan.name(start_date)
else
  holiday_name = ""
end
```

###プログラムの完成！

最終的に作成した結果は次のようになりました！

```ruby:Ruby
require 'csv'
require 'date'
require 'holiday_japan'

dow = ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"]

puts "カレンダーの開始日を入力してください（例：20200101）"
a = gets.to_s

puts "カレンダーの終了日を入力してください（例：20201231）"
b = gets.to_s

start_date = Date.parse(a)
end_date = Date.parse(b)

CSV.open('./calender.csv', 'w', headers: true) do |csv|
  csv << ['年','月','日','曜日','祝日']
  while start_date <= end_date do
    year = start_date.year
    month = start_date.month
    day = start_date.day
    dow_num = start_date.wday
    unless HolidayJapan.name(start_date).nil? then
      holiday_name = HolidayJapan.name(start_date)
    else
      holiday_name = ""
    end
    csv << [year, month, day, dow[dow_num], holiday_name]
    start_date += 1
  end
end
```

##まとめ
私としてはRuby単体プログラムではCSVをよく使います。
今回はCSVを出力するだけでしたが、既存のCSVを読み込んで必要なデータだけ抽出し、成形し直すということも可能です。