Docker環境で開発したReactアプリをGithubPagesにデプロイする方法

はじめに

こんにちは!Akira(彰)です!
今回はReactアプリのGithubPagesへのデプロイ手順を解説していきます。
今回の前提環境としては以下となります。

前提環境

  • React: ver18.2.0
  • Docker
FROM node:lts
WORKDIR /usr/src/app
version: "3.9"
services:
  app:
    container_name: react-app
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
    - type: bind
      source: ./
      target: /usr/src/app
    command: sh -c "cd react-app && yarn start"
    ports:
      - 3000:3000
    stdin_open: true
docker-compose run --rm app sh -c 'npx create-react-app react-app'

以上の環境で構築しているものと考え、解説の方を行っていきます!

問題点

以上の環境で構築した場合、ディレクトリ構成は以下のようになっていると思います。

git_dir/
 ├ react-app/
 │  ├ node_module/
 │  ├ public/
 │  ├ src/
 │  ├ .gitignore
 │  ├ package-lock.json
 │  ├ package.json
 │  └ README.md
 ├ Dockerfile
 └ docker-compose.yml

実はこのディレクトリ構成の問題として、ビルドしたファイルが下記のように作成されるためGithubPagesにデプロイした際、ビルドしたファイルを拾ってくれないという状態になります。

git_dir/
 ├ ○ docs/ <= 本来ここにあってほしい
 ├ react-app/
 │  ├ x docs/ <= 実際にビルドされるファイル
 │  ├ node_module/
 │  ├ public/
 │  ├ src/
 │  ├ .gitignore
 │  ├ package-lock.json
 │  ├ package.json
 │  └ README.md
 ├ Dockerfile
 └ docker-compose.yml

この問題を解決するには git_dir 直下にビルドされたファイルを置く必要があります。

この問題と解決方針を前提に次に進みます。

ローカル側での設定

それでは実際にファイルに記述を追加してGithubPagesへデプロイできるようにしていきます。
まずは package.json を下記のように編集してください。

{
+ "homepage": "https://<GitHubアカウント名>.github.io/<リポジトリ名>/",
  "name": "react-app",
  "version": "0.1.0",
  "private": true,
   // 中略

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
+   "rm": "rm -rf ../docs",
+   "mv": "mv build ../docs",
+   "deploy": "npm run rm && npm run build && npm run mv"
  },
  // 後略
}

この記述でビルドしたファイルを docs にリネーム後、git_dir 直下に移動させることができます。
この記述が完了後、下記コマンドを実行しアプリをビルドすると方針通り下記のようなディレクトリ構成になると思います。

docker-compose run --rm app sh -c 'cd react-app && npm run deploy'
git_root_dir/
 ├ docs/
 ├ react-app/
 │  ├ node_module/
 │  ├ public/
 │  ├ src/
 │  ├ .gitignore
 │  ├ package-lock.json
 │  ├ package.json
 │  └ README.md
 ├ Dockerfile
 └ docker-compose.yml

この状態で変更をコミットし、プッシュすることでローカル側の手順は完了です。

Githubでの設定

次はGithubPagesの設定を行っていきます。
プッシュしたGithubリポジトリに移動後、Settings > Pages に移動し下記画像を参考にし設定します。

上記画像の Branch からビルドの変更が含まれるブランチを選択し、フォルダが /root となっているところを /docs に変更し Save をクリックします。

すると該当ブランチでデプロイが走り、完了後Pagesにデプロイ後のページにアクセスできるURLが表示されるので確認してください。(1~5分ぐらい待ちます)

以上の手順でデプロイ先URLで正しく動作確認できれば完了となります!お疲れ様でした!

おわりに

Docker環境でreactをセットアップした際のディレクトリ構成は少し面倒なので今回のような手順を踏む必要があります。
gh-pagesを使うなどの手段もあるとは思いますがDockerで扱う場合、コンテナ内でのGit連携が必要だったので今回のようにすることにしました。
長くなりましたが、ここまで読んでいただきありがとうございました!

JavaScript Primer - 迷わないための入門書 を読んだ感想!

はじめに

こんにちは!Akira(彰)です! 今回は JavaScript Primer - 迷わないための入門書 を読んだ感想を

  • 良かったところ
  • 学んだこと
  • 難しかったこと

に分けて書いていきたいと思います!

良かったところ

ECMAScriptを意識した学習ができる

ECMAScriptを意識して学ぶことで、どの実行環境でも対応できる基本的な知識を学べます。

初歩的な文法も一緒に学べる

本書は「すでに何かしらのプログラミング言語を触ったことがある人向けに書かれています。」とありますが、読んでみると初歩的な文法も"丁寧"に解説されているため1言語、Progateを終えた程度の知識でも理解できる範囲なのかなと感じました。

実際にアプリケーションを作る流れを学べる

本書の後半では前半で学んだことを元に、Ajax通信を扱うアプリ、CLIアプリ、Todoアプリ、を実際に作って学んだことが実際にどういった場面で役立つのかを体験することができます。

学んだこと

基礎文法

他のプログラミング言語で共通するような部分(スコープや演算子)から、JavaScript独自の書き方(Arrow Function等)を網羅的に学びました。

非同期処理

次の処理が完了するまで次の処理ができないという同期的処理の問題を解決するための技術非同期処理について、 PromiseからAsync Function、Promise & Async Functionを合わせた記述方について学びました。
また、非同期処理時の例外処理法についても併せて学ぶことで安全性の高いコードを書く重要性について学ぶことができました。

this

関数定義の方法や状況によって this の参照先が違うということ、this 使用時の問題(thisを含むメソッドを変数に代入、コールバック関数内でのthis)について何故その問題が起こるのか、どう対処するのがいいのかという対処法について学びました。

情報をモデル化して管理する

直接DOMを更新して管理するコードは情報の状態がDOM上にしか存在しないためHTML要素に情報を全て埋め込む必要があり、操作に対する処理が複雑化しがちです。
この問題に対処するために物の状態や操作方法をクラスとしてモデル化し、管理することで複雑さを一定に保つことができ、管理しやすいということを学びました。

モジュール化することでのリファクタリング

作成したTodoアプリケーションをリファクタリングすることでモジュール化していくとコードの管理や機能追加に強い形にできるということを実際に体験し学びました。

難しかったこと

コールバック関数

コールバックが連続するようなコードはまだ慣れなく処理を追っていくのにに時間がかかります...。
反面、実装を進めるには早めに理解して慣れていきたい部分でもあると感じました。

非同期処理

非同期処理単体ではそこまで苦労しなかったのですが、例外を処理する流れへの理解が浅く(コールバックへの理解が浅いため)苦労しました。

リファクタリング

Todoアプリケーションを実際にリファクタリングしてみてまだ機能切り出しの判断が身についていないと考えています。
しかし、これは数をこなして身に着けていくことでもあると思うのでアウトプットを繰り返し慣れていきたいと思います。

おわりに

学習していたRubyと共通する部分への理解は早かったのですが新しく学ぶことについての理解が難しいなぁと感じました。
しかし、動きを制御できるという楽しさも同時に実感したのでアウトプットを重ねて慣れていきたいと思います。
以上が JavaScript Primer - 迷わないための入門書 を読んだ感想でした!ここまで読んでいただきありがとうございました!

Everyday Rails - RSpecによるRailsテスト入門 を読んだ感想!

はじめに

こんにちは!Akira(彰)です! 今回は Everyday Rails - RSpecによるRailsテスト入門 を読んだ感想を

  • 良かったところ
  • 学んだこと
  • 難しかったこと

に分けて書いていきたいと思います!

良かったところ

既にアプリケーションが用意されておりハンズオンで学べる

本書にはテストを実行するためのアプリケーションが用意されており、Github上からcloneできるため自身でアプリケーションを作成する必要がなく、スムーズにハンズオンで学ぶ環境を整えることができました。

テスト独自の書き方のお作法を知れる

通常のDRY原則に拘らずにテストならではのリファクタリング方法や可読性を重視した書き方を知れました。

テスト駆動開発の流れを知れる

テスト駆動開発を用いて実際に開発する流れとテスト駆動開発で得られるメリットを学べました。

演習問題がある

演習問題を用い自分でコードを考えることで理解をさらに深めることができました。

学んだこと

モデルに対するテスト

モデルに対するテストから入り、RSpecの基本的な文法やお作法について学ぶことができました。

テストデータ

FactroyBotを用いたテストデータの作成や重複データをリファクタリングする際のノウハウ等を学べました。

コントローラーテスト

意識するレベルは低いものの、コントローラテストの方法やJSONでのレスポンスを扱うテスト方法について学びました。

システム(総合)テスト

モデルとコントローラーが一緒に正しく動作することをテストする方法として capybaraselenium-webdriver を用いたUIテストについて学びました。

リクエスト(API)テスト

APIテストの書き方や、現在はコントローラをテストするよりもシステム&リクエストを主にテストするほうが良いということについて学びました。

DRY原則について

書いたテストをDRY原則を用いてリファクタリングする方法、その際ある程度DRY原則を外してでも可読性を重視する場合があるというパターンについて学びました。

テストのスピード向上

テストスピードを向上させる為のgemやタグを使ったテクニックについて学びました。

他機能のテスト

ActiveStorageやMailerのテストをどこまで担当するべきかの考え方について学びました。

テスト駆動開発

テスト駆動開発を実際に体験しながらテストベースでの開発におけるメリットを学ぶことができました。

難しかったこと

文法

テストにおける記述法が英文ベースなため、可読性の高いテストを書くためにはある程度自然な英文を習得する必要があると感じました。

リファクタリング

リファクタリングできる要素が多そうなのと可読性を上げるためにある程度セオリーから外れる場合がある等、少し慣れるのに時間のかかりそうな物が多そうだと感じます。

おわりに

本書を読み、個人的にはテスト駆動開発のメリットが目から鱗でした。
特にリファクタリングをする際にテストを意識すると考え方が変わりそうなのと、要件定義の漏れが少なくなりそうという面で自分での開発にもなるべく取り入れるようにしていきたいと思います!
以上が Everyday Rails - RSpecによるRailsテスト入門 を読んだ感想でした!読んできただきありがとうございました!

現場で使える Ruby on Rails 5速習実践ガイド を読んだ感想!

はじめに

こんにちは!Akira(彰)です!
本日は 現場で使える Ruby on Rails 5速習実践ガイド を読んだ感想を、

  • 良かったこと
  • 学んだこと
  • 難しかったこと

に分けて書いていきたいと思います。

良かったこと

Railsの基本原則に沿った開発を意識できる

この本では実際に実装のコードを書いた後に必ず基本原則に沿うようにリファクタリングを行うので、実際にどのように考えてリファクタリングをするか、という流れが明確でした。

Railsアプリケーション作成の全体像を知れる

実際にハンズオンでタスクアプリの土台を作り、そこから機能を追加していく流れを知った上でRailsで使われている技術の概要を細かく知ることで全体像の把握が比較的楽でした。

便利なgemと使い方を知れる

上記でも触れたとおり、この本ではタスクアプリを実際に作ってみながらRailsを学習するのですが、その際に有用なgemの使い方も同時に紹介されているので実際別アプリを作る際に参考になると思います。

チーム開発におけるgit rebaseの使い方や注意点を知れる

個人的に驚いたのですが、複数人での開発する際に注意することやgit操作で起こりうるであろうトラブルを事前に回避するための対策などにも触れており、実際にチーム開発を経験したことがない人でも起こりうるトラブルの想像、回避するための手段をイメージできて助かりました。

学んだこと

MVCについて

これはこの後のリファクタリングにも関連する話ですが、どこまでのコードをモデルに持たせるのかコントローラに持たせるか等が例付きで解説されており、自身で開発する際には気を付けようと思いました。

Slimテンプレートでの書き方

今まで僕が学習に使っていた教材でのテンプレートエンジンはERBだったのでこの本で初めてSlimというものに触れて凄く簡単に記述できるということが理解でき感動しました。

RSpecでのテスト記述

RSpecを使ったテストの記述方や、FactoryBotを使いテストに使うデータの作成法、テストが失敗した時の原因特定の仕方について学びました。

Railsが行っているセキュリティ対策

Railsの代表的なセキュリティ対策として挙げられる3つ、Strong Parameters CSRF対策 インジェクション対策 について詳しく学べました。

アセットパイプライン

実行処理を改善するためのパイプライン処理、パイプライン処理に必要なマニフェストファイルの記述方、アセットに関する設定方について学びました。

非同期処理や定期実行(Active Job)

Sidekiqを使用した非同期のJobの作成と実行の仕方について学びました。
また、実行日時を指定してJobを実行する方法についても知ることができました。

ページの再読み込みを使わずにページの状態を更新するJavaScriptのプログラミング手法 Ajax とそのAjaxを使いリンククリックでのページ遷移を高速化する手法、Turbolinksについて学びました。

チーム開発の流れ

gitを使ったチーム開発の流れ、特に git rebase を使用する際の注意点等に関しては何処かで詳しく勉強しないといけないと感じていたので非常に助かりました。

上手なリファクタリングをするための考え方

MVCについて でも説明した通り、リファクタリングについての考え方をSQLでいう正規化のような流れで解説しており大変分かりやすいと感じると同時に、まだ自身で考えたコードをリファクタリングした経験はないので難しいとも感じています。

難しかったこと

MVC

大体のMVCの関係は理解できましたが実際開発に取り掛かると適切な箇所に適切にコードを記述するというのが難しいだろうなという風に感じました。

リファクタリング

リファクタリングに必要な考え方や工程は理解できましたが、先述の通り自身で考えたコードをリファクタリングした経験はまだないのでこの先アウトプットを通して鍛えていきたいと思っています。

おわりに

最後に本を読み終えての全体的な感想を書いて終わろうと思います。
まずは内容が非常に濃いということ、正直まだ実際に開発等でアウトプットできていないのでちゃんと定着できているかは怪しい感じがします。
逆に言うとアウトプットを通じでこの本で学んだことを身に着けることができたのであれば、Railsに関する知識しっかりとを得ることができるのではないかなと思います。
一番の懸念点はこの本で扱うRailsのバージョンが5系ということで古いこともあり、Rails7との違いがどれぐらいのものなのかまだわからないという点です。
しかし、根幹にあるデータの流れや考え方については変わらないものが多いと思うので読んでよかったと感じています。
以上が 現場で使える Ruby on Rails 5速習実践ガイド を読んだ感想となります。ここまで読んでいただきありがとうございました!

達人に学ぶDB設計 徹底指南書 を読んだ感想!

はじめに

こんにちは!Akira(彰)です!
本日は達人に学ぶDB設計 徹底指南書 を読んだ感想を、

  1. 良かったこと
  2. 学んだこと
  3. 難しかったこと

に分けて書いていきたいと思います。

良かったこと

DBの基礎を学んだ後に知っておくべき知識を学べる

僕は1つ前の記事で感想を書いた本を読んでから今回の本を読んだのですが基礎を学んだ後、自分で設計する際に不安だった要素を補えるような内容となっていて助かりました。

筆者の伝えたいことがわかりやすい

この本は筆者の体験談を交えて書かれており説得力があるのと、繰り返し筆者の伝えたいことを述べてくれるため頭に入りやすいです。

設計におけるアンチパターンを学べる

基本的に「こうしましょう」と解説することはあっても「これはして欲しくないです」と言ってもらえる機会は中々少ないと思います。
この本では論理設計におけるアンチパターンを「何故好ましくないか」という所まで掘り下げて解説しているので本質的な部分での理解が可能でした。

学んだこと

トレードオフ

DB設計におけるトレードオフの関係を適切に理解し目標に合わせ何を諦めるのかを判断することが大事。

ハードウェアのサイジング

RAIDを使ったシステムの構築とRAIDの選定基準とバックアップの種類(フルバックアップ 差分バックアップ 増分バックアップ) そしてバックアップにおけるトレードオフはバックアップコストとリカバリコスト(復元手順の複雑さ)ということを学びました。

第4正規形と第5正規形

第4正規形はキーと集合である多値従属性をテーブルを分割して対応した形で、関連エンティティを作る際に含まれる関連は1つだけにすることで自然と第4正規形になる。
第5正規形は関連と関連エンティティを1対1で対応させると第5正規形となる。
正規化におけるトレードオフSQLのパフォーマンスと正規化したことにより得られるメリット(テーブルの持つ意味が明確となる、更新時の不整合の防止)であるということ。
このトレードオフを考慮して通常時は第3正規形までで良いとされる。

IDEF1XでのER図の書き方

IE表記法での書き方と違い、もっと細かく情報を示したものがIDEF1Xとなる(米空軍がメーカに仕様を伝えるために作ったものなので)

インデックスを正しく用いたパフォーマンスの改善

B-treeインデックスの長所短所と効果の高い使用方法や逆に効果の薄い使用方法。
B-treeインデックス以外の ビットマップインデックスハッシュインデックス の長所短所。

論理設計におけるアンチパターン

第1正規形未満という形から始まり、設計においてやってはいけないことを作者の経験を交えてわかりやすく学びました。

論理設計のグレーノウハウ

グレーノウハウトレードオフにおける最終手段のように扱うアンチパターンとは言わずとも濫用は控えるべき技術を注意点含め学ぶことができました。

木構造を取り扱うには

リレーショナルデータベースの苦手分野である木構造の取り扱いをどうするか、というのを 隣接リストモデル から始まり 入れ子集合モデル, 入れ子区間モデル, 経路列挙モデル について学びました。
そして、入れ子区間モデルが今後木構造の取り扱いを担う大きな手段であることを知ることができました。

難しかったこと

ハードウェアのサイジング

本の内容にもある通り、精度高くサイジングすることは難しそうだなぁ...と感じています。
経験が物をいう分野だと思うので当たり前な話ではありますが...

インデックスの実使用における改善効果

インデックスを用いることでのパフォーマンス改善効果を実感できているわけではないので改善効果がイメージし辛いと感じている部分ではあります。

おわりに

最後に本を読み終えての全体的な感想を書きたいと思います。
良かったことにも書いた通り、この本はSQLの基礎をある程度理解した上で読むと自信に足りていない点を補充できる内容だと感じました。
特に、論理設計や正規化に対して不安や苦手意識を感じている部分が多かった僕はこの本を読んで苦手意識が減ったと思います!
以上が、達人に学ぶDB設計 徹底指南書を読んだ感想になります!ここまで読んでいただきありがとうございました!

スッキリわかるSQL入門 第3版 を読んだ感想!

はじめに

こんにちは!Akira(彰)です!
本日はスッキリわかるSQL入門 第3版 ドリル256問付き! (スッキリわかる入門シリーズ) を読んだ感想を、

  1. 良かったこと
  2. 学んだこと
  3. 難しかったこと

に分けて書いていきたいと思います。

良かったことろ

SQLの基礎をイラスト付きで分かりやすく学べる

この本の題名にもなっている「入門」という名の通り、SQLの基礎をしっかり学ぶことができます。
また、イラスト付きなため視覚的にもわかりやすく躓きにくかったです。

各章毎に問題が用意されている

各章毎に復習のような形で問題が用意されているため復習しながらしっかりと知識を身に着けることができます。
そしてこの本には「特訓ドリル」という問題集も付いているので自身の苦手だと感じている部分をしっかり克服しながら読むことができました。

実使用時のイメージを掴みやすい

本の最後の方になっていくと当然内容も難しくなっていくのですが、登場人物が対話しながら実際に機能を実装してくという流れが分かるので学んだことを「どう使う」というのがイメージし易かったです。

ブラウザ上で操作できるDBを実際に使って学習できる

実際に問題で使われているテーブル等をブラウザ上から操作できるサイトが付属されているため学習のために環境構築する必要がなく、非常に低いハードルで学習を開始できます。

学んだこと

SQLの基本文法

SELECT UPDATE INSERT DELETE の基本4大命令から各命令で使える修飾語を学びました。

集合演算子の使用法

和集合(UNION) 差集合(EXCPT, MINUS) 積集合(INTERSECT) を使って複数のSELECT文の結果を集合演算する方法。

各関数の使い方

集計関数の SUM関数LENGTH関数 等の関数の使い方や実践的な使い道について学びました。

テーブルの結合

主キー外部キー を用いて JOIN句 で各テーブルを結合する方法。
そして結合する際に指定できる結合法(左外部結合, 右外部結合, 完全外部結合)

テーブルの作成方法

テーブル作成の基本文法と人為的ミスによって想定外のデータが格納されないようにするための 制約 の記述方法

トランザクションについて

複数のSQL文を1つの不可分なかたまりとして実行できる。
トランザクション原始性分離レベル を正しく理解することで不可分性を制御できより正しくデータを制御できる。

テーブル設計の基本と正規化

要件をもとに 属性 を含んだ エンティティ とその関係を ER図 に書き起こす 概念設計
概念設計をもとにDBが扱いやすいようにテーブルを意識してエンティティを変形する 論理設計
通常第3正規形までを使って適切にテーブルを分割していく 正規化

第1正規形はセルの結合や繰り返しの列を排除した形

第2正規形は主キーの1部に対して従属する 部分関数従属 を排除した形

第3正規形はテーブル内で 〇〇→△△→✕✕ のように従属性が推移する 推移的関数従属 を排除した形

ここまでで作成した設計を利用して、実際にテーブルを作成する 物理設計
このように、テーブル設計の全体的な流れについて学ぶことができました。

難しかったこと

テーブル設計

章の終わりの方でテーブル設計の方法について学べるのですがそこで出てきた 論理設計 正規化 について難しいと感じました。
特に第2正規形や第3正規形における 完全関数従属推移関数従属 を解消する考え方についてが難しいと感じました。

おわりに

最後に本を読んでの全体的な感想を書きたいと思います。
本の読み始める段階ではProgateのSQLを触った程度の知識で修飾語の順番や命令ごとに使える修飾語が違うことについて難しいと感じていました。
ですがこの本では立場や4大命令というのに分けて解説されているので非常にわかりやすく、混乱することなく理解することができました。
また、問題集も付属しているので本を読んで得た知識をしっかりと復習し身に着けることができるので入門としてはこの1冊で完結していると思います。
以上が、スッキリわかるSQL入門 第3版 ドリル256問付き! (スッキリわかる入門シリーズ)を読んだ感想となります!ここまで読んでいただきありがとうございました!

勉強中!Rubyのoptparseライブラリについて!

はじめに

こんにちは!Akira(彰)です!
今日はRubyのoptparseライブラリについて基本的な使い方をまとめていきたいと思います!
本記事ではlibrary optparse 公式リファレンスを元に

  1. optparseで何ができるのか
  2. optparseの大まかな書き方
  3. parseメソッドの取り扱い
  4. 実際にどのように使うのか

に分けて書いていこうと思います。

optparseで何ができる?

optparseを使うとコマンドラインでオプションを使い値を受け取ることができます。 例えばrbファイルを実行する際に ruby ファイル名.rb -a xx と書いた場合、-a の部分がオプション名、 xx の部分がオプションに対する値です。
このようにoptparseを使うとオプションの内容によって振る舞いを変えるというコードが書けます。

optparseの大まかな書き方

何ができるのかが分かったところで、どのように書いてコード内でどのように値を取り出すのかについて書いていきます。
下記のコードはオプション -a を作成し、オプションを使って入力された値をARGVに格納するといったコードになります。

require 'optparse'

opt = OptionParser.new

opt.on('-a') { |v| p v }

opt.parse!(ARGV)

p ARGV

実際にオプション付きで実行してみると

ruby ファイル名.rb -a b
true  # コマンドラインにオプション(-a)が付いているとtrueが返る
["b"] # オプション(-a)で入力した b が出力されている

上のようになると思います。 この時、気を付けなければならないのはOptionParser#onメソッドが呼ばれた時点ではブロックはまだ実行されていないということです。
ではどのタイミングでブロックが実行されているのかというと、OptionParser#parseメソッドが呼ばれたタイミングです。
下記のようなコードを実行するとそのことが確認できると思います。

require 'optparse'

opt = OptionParser.new

opt.on('-a') { p ARGV }

opt.parse!(ARGV)

このコードはOptionParser#onメソッドのブロックに ARGV を表示するように記述しています。
onメソッドが呼び出されたタイミングでブロックが実行されているのであれば、ARGVの中身は空のはずなので表示は空の配列が返るはずです。
ですが、実行すると下記のような結果になります。

ruby ファイル名.rb -a b
["b"]

このことからonメソッドのタイミングではブロックは呼び出されておらず、parseメソッドの呼び出し時にブロックが実行されているということがわかると思います。

parseメソッドの取り扱い

上記で扱ったコードではOptionParser#parse!メソッドを使っています。その理由は ! の付いていないparseメソッドはARGVにオプション自身も含まれる & ARGVを破壊的に変更しないためです。

メソッド名 振る舞い
parse ARGVにはオプションと値の両方が解析され、ARGV自体は変更されない
parse! ARGVからオプションが取り除かれ、ARGV自体が変更される(破壊的)

OptionParser自体はどのオプションが指定されたのかを記憶していないため、オプションによる条件分岐を実装する際にはハッシュなどに情報を持たせておく必要があります。

require 'optparse'

opt = OptionParser.new

# ここで定義したハッシュに情報を持たせる
opt_params = {}

opt.on('-a') { |v| opt_params[:a] = v }
opt.on('-b') { |v| opt_params[:b] = v }

opt.parse!(ARGV)

p ARGV
p opt_params

このコードをオプション付きで実行すると以下のように出力されます。

ruby ファイル名.rb -a xx -b yy
["xx", "yy"]
{:a=>true, :b=>true} # ハッシュに持たせた情報が出力される

このようにハッシュに情報を持たせるとその情報を用いて分岐処理などを書くことができます。
ですがオプションが多数ある場合、何度もonメソッドにハッシュに値を持たせる処理を記述しなければなりません。
これを簡略化するにはparseメソッドに :into を付けることで自動的にハッシュに値を格納できます。
ハッシュのキーはロングオプション( "--" )で定義されていればロングオプションの値を、ショートオプションのみの場合はショートオプションの値から( "-" )を取り除いた値が使用されます。

require 'optparse'

opt = OptionParser.new

opt_params = {}

opt.on('-a') { |v| v }
opt.on('--bbb') { |v| v }

opt.parse!(ARGV, into: opt_params)

p ARGV
p opt_params

これがparseメソッドに:intoを付けたバージョンです。出力例は↓です。

ruby ファイル名.rb -a xx -b yy
["xx", "yy"]
{:a=>true, :bbb=>true} # ":a"がショートオプションのキー、":bbb"がロングオプションのキー

このように、parseメソッドに :into を記述することで書くonメソッドに処理を書かなくても自動で値を格納してくれるようになります。

そして、下記のコードのようにonメソッドの引数に VAL を付けることでオプションで受け取った値を :into の指定先に格納することもできます。

require 'optparse'

opt = OptionParser.new

opt_params = {}

opt.on('-a VAL') { |v| v }
opt.on('--bbb VAL') { |v| v }

opt.parse!(ARGV, into: opt_params)

p opt_params

上記のコードの出力例↓

ruby ファイル名.rb -a xx --bbb yyy
{:a=>"xx", :bbb=>"yyy"} # オプションで渡した値が表示される

実際の使用例

それでは今まで書いたことを参考に

  1. オプションの有無をハッシュで受け取る
  2. オプションの有無で条件分岐し、出力を変える
  3. 出力先でオプションで受け取った値を使う

ができるコードを書いてみました。

require 'optparse'

opt = OptionParser.new

opt_params = {}

opt.on('-a') { |v| v }

opt.parse!(ARGV, into: opt_params)

# オプションのハッシュキー[:a]で取り出した値がtrueならオプションで入力した値出力に分岐
if opt_params[:a]
  puts "オプションが入力された処理#{ARGV}"

# オプションが未入力の場合、未入力用の処理へ分岐
else
  puts 'オプションが未入力の処理'
end

そしてonメソッドに VAL メソッドを付けることで下記のように条件分岐なしで書くこともできます。

require 'optparse'

opt = OptionParser.new

opt_params = {}

opt.on('-a VAL') { |v| v }

opt.parse!(ARGV, into: opt_params)

# opt_params[:a] が真であれば option に代入され、空であれば空の処理が代入される
option = opt_params[:a] || 'オプションが未入力の処理'

puts option

こうすると条件分岐を書かなくとも opt_params[:a] が空かどうかで代入する内容を変えられます。
今回のコードは最低限で小規模なものですが、何となくoptparseを使用してコードを書く流れが分かったかなと思います。

おわりに

以上でoptparseの基本的な使い方は以上になります!
とはいえ、公式リファレンスにはまだ当記事で紹介しきれていない情報があるので(help等)必要な際には適宜読んでみるのがいいと思います。
それではここまで読んでいただきありがとうございました!