ruby library optparseの使い方

使い方

optparse を使う場合、基本的には

  1. OptionParser オブジェクト opt を生成する。
  2. オプションを取り扱うブロックを opt に登録する。
  3. opt.parse(ARGV) でコマンドラインを実際に parse する。

というような流れになります。

実装例

require 'optparse'
# terminalでの標準入力
# ruby sample.rb -m hello

# terminalから値の受け取り方法
# 1. OptionParser オブジェクト opt を生成する
opt = OptionParser.new
# 2. オプションを取り扱うブロックを opt に登録する
opt.on('-m') { |v| }
# opt.parse(ARGV) でコマンドラインを実際に parse する
opt.parse!(ARGV)
# parseしたARGVの値を出力する
p ARGV
#=>["hello"]

参考文献

docs.ruby-lang.org

RubyでFizzBuzz書いてハマった話

学んだこと TL;DR

putsはnilを戻り値として返す。

最初のコード

def fizz_buzz(num)
  if num % 15 == 0
    puts "Fizz Buzz"
  elsif num % 3 == 0
    puts "Fizz"
  elsif num % 5 == 0
    puts "Buzz"
  else
    puts num.to_s
  end
end

require 'minitest/autorun'

class FizzBuzzTest < Minitest::Test
  def test_fizz_buzz
    assert_equal '1', fizz_buzz(1)
    assert_equal '2', fizz_buzz(2)
    assert_equal 'Fizz', fizz_buzz(3)
    assert_equal '4', fizz_buzz(4)
    assert_equal 'Buzz', fizz_buzz(5)
    assert_equal 'Fizz', fizz_buzz(6)
    assert_equal 'Fizz Buzz', fizz_buzz(15)
  end
end

実行結果

あれ?最初のアサーションで処理が止まってる??なんでや、、

修正後のコード

def fizz_buzz(num)
  if num % 15 == 0
     "Fizz Buzz"
  elsif num % 3 == 0
     "Fizz"
  elsif num % 5 == 0
     "Buzz"
  else
     num.to_s
  end
end

require 'minitest/autorun'
class FizzBuzzTest < Minitest::Test
  def test_fizz_buzz
    assert_equal '1', fizz_buzz(1)
    assert_equal '2', fizz_buzz(2)
    assert_equal 'Fizz', fizz_buzz(3)
    assert_equal '4', fizz_buzz(4)
    assert_equal 'Buzz', fizz_buzz(5)
    assert_equal 'Fizz', fizz_buzz(6)
    assert_equal 'Fizz Buzz', fizz_buzz(15)
  end
end

実行結果

ちゃんとテストパスできた〜

感想

puts やprintがnilを返すということは多分もう忘れないと思います。

あとrubyだとreturnをあんまり使わずに"文字列"だけを書いて戻り値とするんだなと知りました。

sudoを無闇に使ってパソコンがブラックアウトした話

やってしまったこと TL;DR

jobsの1を停止しようとして sudo kill 1を実行した。

停止したプロセス

/sbin/launchd が停止しました。

sbin/launchdは、macOSおよび他のUnixオペレーティングシステムで使用されるプロセス管理システムです。launchdは、システムの起動時やユーザーログイン時に実行されるジョブやデーモンを管理し、制御します。

beepというタイマージョブを停止させようとしたら、プロセスを管理しているプロセスを停止させてしまったんですね笑

とんでもないことをやらかしてしまいました。

起こったこと

キーボードもマウスも反応しなくなりパソコンがブラックアウトして落ちた、 その後自動で再起動した。

学んだこと

jobsを停止 => kill %<job番号>

psを停止 => kill <pid番号>

%が抜けていました。

もうsudoは無闇につけません。。

最近dockerについて学習を行っているのですが、今回のようなことが起きないように権限管理についてもう少し学習したいと思いました。

コンテナ内のrootユーザはホスト上でもroot権限を持つことになりセキュリティ上望ましくありません。Linuxのユーザ名前空間(User Namespace)の機能を使うことで、コンテナ内のrootユーザをホスト上の一般ユーザとして扱うことができ、コンテナとホスト間でユーザ権限の分離ができるようになります。

おまけ

気づいたら1時間経ってたを解消するlinuxbeep関数作ってみました。

.zshrcに記述してsorce /ect/.zshrcすれば使えるようになります。

zsh function beep() { while true; do echo -e "\a" sleep $1 done }

使い方、 terminalで beep <秒数>を実行 するとbeepで指定した秒数ごとに音が鳴ります。

止める時はctrl + cで止まります。

RailsアプリにDockerを導入する手順

Rails6+Webpacker+Postgresql 既存のRailsアプリをDocker化する手順について綴っていこうと思います。誤っている点や改善点などありましたらご指摘いただけると幸いです。

前提条件

~$ gem info rails
rails (7.0.4.3, 7.0.4, 6.1.7.3, 6.1.5, 6.0.6.1, 6.0.3) #今回は6.1.5を使用します
~$ruby -v
ruby 3.1.2
~$ docker -v
Docker version 20.10.16
~$ docker-compose -v
docker-compose version 1.29.2
~$  docker login
Authenticating with existing credentials...
Login Succeeded

事前準備

手順

  • rails _6.1.5_ new <app名 or . > --webpackrails アプリケーションを作成する。(rails new .の場合カレントディレクトリをアプリ名としてrailsアプリが作成されます。)
  • rails generate scaffold task title:stringで簡単なタスクアプリを作成する。
  • rails db:migrateでdb/migrate以下のファイルの変更をdbに反映する
  • config/routes.rbを編集する(rootにアクセスした際にtasksコントローラのindexアクションを用いるように記述する)
Rails.application.routes.draw do
  resources :tasks
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  root 'tasks#index'  # <=この記述を追加
end
  • export NODE_OPTIONS=--openssl-legacy-providerをterminalで実行(openSSL互換エラーを防ぐための環境変数を追加)
  • 1つの目端末(terminalのタブ)でbin/webpacker-dev-serverを実行(コンパイル用のサーバー)
  • 2つ目の端末(terminalのタブ)で'rails server'を実行(アプリケーションサーバー)

事前準備が終わった際のrepository構成は以下のgithubページから確認できます。

github.com

動作確認と簡単な解説 www.loom.com

zenn.dev

Railsアプリのdocker化

手順

  • Dockerfile作成

app名/Dockerfileを以下の内容で作成します。

# nodeイメージに対してasでエイリアスをつけます。エイリアスはCOPYコマンド等で使用することが可能となります
# このDockerfileではrubyのイメージに対して命令を記載しているため、FROM の定義順番もnode,rubyである必要があります
# 下記のnode全体は最終的なイメージには保存されません
FROM node:16.20.0-bullseye as node



FROM ruby:3.1.2
# Install Node.js and Yarn、nodeイメージがcreateされstartしてbashで入った際に以下のフォルダーが確認できた
# /opt/yarn-* , /usr/local/bin/node , /usr/local/lib/node_modules/
# 以下の記述はnodeコンテナで生成されたフォルダーをrubyコンテナにコピーしている
# ln -fs では左のソースを右のターゲット名で呼び出せるようにシンボリックリンクを作成している
COPY --from=node /opt/yarn-* /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
  && ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx \
  && ln -fs /opt/yarn/bin/yarn /usr/local/bin/yarn \
  && ln -fs /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg
# apt-getで必要なパッケージをインストールします
# -y オプションはyes/noのダイアログに対してyesと答えますという意味です、
RUN apt-get update && apt-get install -y \
  build-essential \
  libpq-dev \
  postgresql-client

# WORKDIR 以降の命令は、/myappで実行されます myapp$
WORKDIR /myapp

# build contextの中のファイルをdockerイメージに組み込んでコンテナが起動した際にコンテナのファイルシステムの/myapp/Gemfileに配置をしている
# ADDもCOPYもbuild contextファイルをdockerイメージに組み込んでコンテナのファイルシステムに配置している
# tarの圧縮ファイルをコピーして解凍したい時はADD、単純にファイルやフォルダをコピーする場合はCOPY
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
COPY package.json /myapp/package.json
COPY yarn.lock /myapp/yarn.lock

# bundle install -> Gemfile.lockの内容をもとにインストール
# yarn install -> yarn.lockの内容をもとにインストール
RUN bundle install && yarn install

# build contextに渡してディレクトリをコンテナファイルシステムの/myappに配置する
ADD . /myapp
  • docker-compose.yml作成

app名/docker-compose.ymlを以下の内容で作成します。

version: '3'

# 名前つきボリュームを定義します
# ボリュームはデータを永続化するための機能
# コンテナ上で生成されたファイルはコンテナのライフサイクルと共に消えてしまう。ボリュームはコンテナのライフサイクルとは独立してファイルの管理を行います。
volumes:
  db-data:
    driver: local #driverはAmazon EBS のような外部のストレージ・システムと統合した環境に Docker をデプロイできるようにする際に詳細に設定する
  bundle:
    driver: local

services:
  web:
    # Dockerfileを使ってbuildします。build contextにはdocker-composeが実行された際のカレントディレクトリを渡します
    build: .
    volumes:
      # ホスト上のカレントディレクトリ(.)の内容をコンテナ上の/myappに割り当てます(バインドマウント)
      - '.:/myapp'
      # コンテナ上のgemインストール先(/usr/local/bundle)をbuldleという名前でボリュームに割り当てますs
      - bundle:/usr/local/bundle
    # コンテナ稼働時に実行されるコマンドです
    # RUN -> volumes(マウント) ->CMD
    command: /bin/sh -c "rm -f tmp/pids/server.pid && rails db:create && rails db:migrate && rails s -p 3000 -b '0.0.0.0'"
    # 'ホスト側:コンテナ側'のポートを3000でマッピングしています
    ports:
      - '3000:3000'
    environment:
      # DB_PASSWORDに.envのDB_PASSWORD のバリューを格納してwebホスト上の環境変数として使用できるようにしています
      - 'DB_PASSWORD=${DB_PASSWORD}'
      # WEBPACKER_DEV_SERVER_HOSTでdev-serverの接続先を指定しています
      - 'WEBPACKER_DEV_SERVER_HOST=webpacker'
    # 擬似端末(キーボードによる入力)をコンテナに結びつけます(docker run -itの-tと同じ意味)
    tty: true
    # 標準入出力とエラー出力をコンテナに結びつけます(docker run -itの-iと同じ意味)
    stdin_open: true
    # dbコンテナが起動してからwebを起動します
    depends_on:
      - db

  webpacker:
    build: .
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
    command: ./bin/webpack-dev-server
    environment:
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0 #webpackerホスト名を指している
    ports:
      - "3035:3035"

  db:
    image: postgres:12
    volumes:
      - 'db-data:/var/lib/postgresql/data'
    environment:
      - 'POSTGRES_USER=${POSTGRES_USER}'
      - 'POSTGRES_PASSWORD=${POSTGRES_PASSWORD}'
  • .env作成

app名/.envを以下の内容で作成します。

DB_PASSWORD=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
  • .gitignore修正

app名/.gitignoreに以下の内容を追記します。

# .gitignoreファイルの最下部
.env
  • .dockerignore作成

app名/.dockerignoreを以下の内容で作成します。

.env
.git
.gitignore
**/.gitkeep
**/Dockerfile
docker-compose.yml
public/packs
log/*
tmp/*
vendor/bundle
node_modules
  • database.yml修正

app名/config/database.ymlを以下の内容に修正します。

default: &default
  adapter: postgresql
  encoding: unicode
  # docker-composeで割り当てられたhostname(db)に変更
  host: db
  user: postgres
  port: 5432
  password:  <%= ENV.fetch("DB_PASSWORD") %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  • Gemfile修正

app名/Gemfileにいかのgemを追記 && bundle install (bundle updateの際にpostgresqlが入ってないとエラーが発生するので、その際はbrew install postgresqlの後にbundle installを実行してください) 以下の記述をGemfileに追加したらbundle installを実行してください。

gem 'pg', '~> 1.1'

stackoverflow.com

  • webpacker.yml修正

app名/config/webpacker.ymlのdevelopmentを以下のように修正してください

development:
  <<: *default
  compile: true

  # Reference: https://webpack.js.org/configuration/dev-server/
  dev_server:
    https: false
    host: localhost #docker-compose.ymlのenvironment: WEBPACKER_DEV_SERVER_HOST: host名 で上書きされる。
    port: 3035
    public: localhost:3035 #ここでのlocalhostはdev_server: host: で指定したホスト名を指す
    hmr: true
    # Inline should be set to true if using HMR
    inline: true
    overlay: true
    compress: true
    disable_host_check: true
    use_local_ip: false
    quiet: false
    pretty: false
    headers:
      'Access-Control-Allow-Origin': '*'
    watch_options:
      ignored: '**/node_modules/**'

Railsアプリのdocker化が終わった際のrepository構成は以下のgithubページから確認できます。

github.com

動作確認と簡単な説明 docker-compose up

www.loom.com

points

  • RUN -> volumes -> CMD
  • docker-composeはアプリに対して1つのネットワークを作成します。サービス用の各コンテナはデフォルトのネットワークにservice:セクションで指定されたホスト名で接続し、そのネットワーク上でコンテナは相互に接続可能な状態になります
  • volumesを共有する設定にしないと、Railsが起動しているコンテナで新しいgemをインストールした際に、Webpackerのコンテナでgemがインストールされていないというエラーが発生します。そのエラーを回避するために、webpackerとrailsの両方のサービスでvolumesを指定して共有しています
めっちゃ参考にしたサイト

zenn.dev

blog.furu07yu.com

参考にしたサイト

自己紹介

23歳 | flutter, AWS 少し触ってました | 筋トレ・ランニング・散歩・サウナ・読書・スプラが好き。 2023/4/18~ Happiness chainで勉強中 twitter フォローしてくれると喜ぶかもしれない。

朝ランニングしてて思ったこと

前置き

運動をするとその後の3〜4時間くらいは集中力や判断力がアップするという情報を知ってからできるだけ毎日運動をおこなようにしています。

実際に集中できるしリフレッシュになっていいなと実感しています。

今日はそんな運動中に起こったことを綴っていけたらなと思います。

起こったこと

朝にランニングをしていたのですが、いつもより起きる時間が遅くなって小学生の登校時間と被ってしまったので、いつもとは違う道を選択。そしたらいつも見ないような女性ランナーの方が100m程前方にいました。少し速度が遅く、追い抜こうかなぁと思ったのですがその先の信号が赤になりそうだったので信号がまた青になったら追い抜こうと思い走るのをやめて僕は信号で止まりました。速度が遅かった女性は僕が止まっている間にも走り続けてかなり遠くの方まで行っていました。その後僕がその女性ランナーを追い抜くことはありませんでした。

思ったこと

なんかうさぎとかめみたいだなと思いました。進み続けることのパワーを物理的に実感しました。学習もマラソンだと思って頑張ろうと思います。タイピングとlinuxは毎日コツコツ続けていこうと思います。

Macユーザである私がよく使うコマンド集

達人プログラマーを目指すものとして

最近達人プログラマーを読んでいるのですが、家とかを作る職人が道具の手入れをするように達人プログラマーも道具の手入れをするようです。

プログラマーの道具に何があるのか正直把握しきれてないのですが、コマンドも道具の一種かなと思ったのでよく使うコマンドに絞って紹介したいなと思います。

よく使うコマンド達

  • command + t で新しいterminal、ブラウザのタブを開く
  • control + tab(->|) でterminal、ブラウザのタブの切り替え
  • SHIFT + OPTION + F でhtmlのフォーマット
  • "control + r" => peco (コマンド管理)
  • "control + g" => ghq(レポジトリ管理)
  • command + p (file検索,vscode)

少しづつ追記していけたらいいなと思います。

適当に使ってたCtrl + z とCtrl + cが何をしているのか整理してみる試み

TL;DR (簡潔に説明)

Ctrl + z

実行中のコマンドの一時停止

Ctrl + c

実行中のコマンドの終了

めっちゃ分かりやすいサイト

www.infraeye.com

説明に誤りとかあったら教えて欲しいです。

Rails serverで挙動を確認

rails sでサーバーが起動しています

rails s

Ctrl + zでjobs番号1で実行されていたrails s コマンドがsuspended(停止の過去形)しているのが確認できます。jobs番号の後の+はカレントジョブ(直前に操作のあったjob)を表してるらしいです。

jobs, Ctrl + z

停止中のjobなので以下のようにfgコマンドでフォアグラウンドに戻す事ができます。

fg %1, localhost:3000にアクセス

今度はCtrl + cを押してみると

Ctrl + c, jobs

=== puma shutdown: 2023-04-24 06:54:04 +0900 ===
- Goodbye!
Exiting

上記の文字が出力されています、文字から何かがstopしてfinishするためのrequestsをwaitingしてるらしいです。そしてpumaなるものがshutdownしたらしいです。 Goodbye! 唐突にお別れの挨拶を言われ、Exiting(退出中)してるらしいです。もうこの実行されていたコマンド君(一連のプロセス)は僕たちの元(フォアグラウンド、terminalで見れるところ)に帰ってこない可能性が高いです。 jobsコマンドを実行しても何も出力されません。

もう一度まとめると、

Ctrl + z

実行中のコマンドの一時停止

Ctrl + c

実行中のコマンドの終了

最後に見ておいてほしい画像、以下のサイトの一番下のジョブ制御という画像でイメージを掴んでおくと納得かもしれないです。

www.infraeye.com