Rubyプロジェクトの始め方の備忘録
Rubyプロジェクトの始め方の備忘録
自分の記憶力が薄弱すぎて、Rubyで何か書くかとなった時にいつも下準備の仕方を調べている気がするので、後で楽するために備忘録を残しておきたいと思います。
余談ですが、自分の記憶力が薄弱すぎて(大事なことなので2回繰り返した)「自分のために残すメモ的な意味の熟語なんだっけ?忘備録だったっけ?」って思ってググったら、「備忘録」(忘れるのに備える記録で備忘録)が正しくて、よく見る「忘備録」は誤記で「備えるのを忘れた記録になる」という意味になってしまうようです。 勉強になりました。
前提となる環境
準備
ディレクトリを作ってgit init
してからgiboで.gitignoreをお手軽に作成する。giboは、RubyとOSXとVimを引数に指定する(OSXとVimはなくてもいいかも)
$ mkdir rubyproject $ cd rubyproject $ git init $ touch .gitignore $ gibo Ruby OSX Vim >> .gitignore
simonwhitaker/gibo · GitHub https://github.com/simonwhitaker/gibo
Rubyの設定
使用するRubyの設定をする。 rbenvでその時点での最新版のRubyを入れる。
$ rbenv install -l $ rbenv install x.x.x(インストールするRubyのバージョン) $ rbenv local x.x.x $ rbenv rehash
sstephenson/rbenv · GitHub https://github.com/sstephenson/rbenv
Bundlerの設定
基本的にプロジェクトで使用するBundlerでgemはローカルディレクトリに保存するけど、Bundlerとrubocopはシステムワイドにインストールしているので、その2つを最新版にする。 その後使用するgemをローカルにインストールする。
$ gem update --system $ gem update bundler $ gem update rubocop $ bundle init $ vim Gemfile (使うgemを記述する) $ bundle install --path vendor/bundle
Bundler: The best way to manage a Ruby application's gems http://bundler.io/
Gemfile
プロジェクトで使用するgem以外のデバッグ等に使用するgemは以下を使っている。
source "https://rubygems.org" ruby 'x.x.x'(インストールしたRUbyのバージョン) group :development do gem 'awesome_print' gem 'tapp' gem 'pry' gem 'pry-doc' gem 'pry-byebug' gem 'pry-stack_explorer' gem 'refe2' end
- awesome_print
デバッグ時等にオブジェクトのデータ構造を分かりやすく表示してくれる。 .pryrcに下記のように書いてpry起動時に自動的にrequireするようにしている。
# awesome_print begin require "awesome_print" AwesomePrint.pry! rescue LoadError => e puts "no awesome_print"
michaeldv/awesome_print · GitHub https://github.com/michaeldv/awesome_print
- tapp
メソッドチェーンの途中に挟むと、pp(puts)しながらレシーバを返すObject#tappやObject#taputsが使えるようになる。 プリントデバッグが捗る。
esminc/tapp · GitHub https://github.com/esminc/tapp
- pry
強いirb。
pry/pry · GitHub https://github.com/pry/pry
- pry-doc
show-source
でCで書かれているRuby組み込みのクラスやメソッドのソースを見ることができる。
pry/pry-doc · GitHub https://github.com/pry/pry-doc
- pry-byebug
binding.pry
でデバッグする時にピンポイントで処理を止めてステップ実行できる。
deivid-rodriguez/pry-byebug · GitHub https://github.com/deivid-rodriguez/pry-byebug
- pry-stack_explorer
デバッグ時に show-stack
でその時のスタックの情報が見られる。
pry/pry-stack_explorer · GitHub https://github.com/pry/pry-stack_explorer
- refe2
refe
でコマンドラインからRubyリファレンスマニュアルを見ることができる。
refe2 | RubyGems.org | your community gem host https://rubygems.org/gems/refe2/versions/0.9.0
終わりに
vagrant up した時に共有フォルダのマウントでエラーが出る問題
問題
大分前から vagrant up
した時に共有フォルダのマウントに時間がかかり下記のエラーが出ていた。
$ vagrant up (中略) ==> web: Mounting shared folders... web: /vagrant => /Users/hoge/path/to/dir/project Failed to mount folders in Linux guest. This is usually because the "vboxsf" file system is not available. Please verify that the guest additions are properly installed in the guest and can work properly. The command attempted was: mount -t vboxsf -o uid=`id -u vagrant`,gid=`getent group vagrant | cut -d: -f3` vagrant /vagrant mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` vagrant /vagrant The error output from the last command was: /sbin/mount.vboxsf: mounting failed with the error: No such device
エラーメッセージを雑に読むと、ゲストとホストで共有フォルダのマウントが上手くいってないようだ。
しかし、その後に普通に vagrant ssh
したら接続はできるのでずっと放置していた。
放置していたが、さすがにそろそろ解決しようと思って色々と調べて解決した。
自分の環境
解決方法
まずはvagrantに接続しvboxのリビルドを試す。 以下はvagrant内でのコマンド操作。
$ sudo /etc/init.d/vboxadd setup Removing existing VirtualBox non-DKMS kernel modules [ OK ] Building the VirtualBox Guest Additions kernel modules The headers for the current running kernel were not found. If the following module compilation fails then this could be the reason. The missing package can be probably installed with yum install kernel-devel-2.6.32-504.el6.x86_64 Building the main Guest Additions module [失敗] (Look at /var/log/vboxadd-install.log to find out what went wrong) Doing non-kernel setup of the Guest Additions [ OK ]
Guest Additions の構築に失敗する。
メッセージ通り、 kernel-devel-2.6.32-504.el6.x86_64 を yum install
してみる。
$ sudo yum install kernel-devel-2.6.32-504.el6.x86_64 読み込んだプラグイン:fastestmirror インストール処理の設定をしています Loading mirror speeds from cached hostfile * base: www.ftp.ne.jp * epel: ftp.kddilabs.jp * extras: www.ftp.ne.jp * remi-safe: remi.kazukioishi.net * updates: www.ftp.ne.jp パッケージ kernel-devel.2.6 は利用できません。 エラー: 何もしません
そんなものは存在しない!
仕方がないので、 kernel-devel-2.6.32-504.el6.x86_64 をキーワードにググり、web上のrpmパッケージを拾ってきてインストールする。
ググったらヒットした RPM Scientific Linux 6 kernel-devel 2.6.32 x86_64 rpm の中から適当なリンクのrpmパッケージをインストールする。
$ sudo yum install ftp://mirror.switch.ch/pool/4/mirror/scientificlinux/6.6/x86_64/os/Packages/kernel-devel-2.6.32-504.el6.x86_64.rpm
インストール後にもう一度vboxのリビルドを行う。
$ sudo /etc/init.d/vboxadd setup Removing existing VirtualBox non-DKMS kernel modules [ OK ] Building the VirtualBox Guest Additions kernel modules Building the main Guest Additions module [ OK ] Building the shared folder support module [ OK ] Building the OpenGL support module [ OK ] Doing non-kernel setup of the Guest Additions [ OK ] Starting the VirtualBox Guest Additions [ OK ]
今度は成功した。
その後、ホストに戻り、vagrant halt
& vagrant up
してもエラーが出ずにすぐに環境構築できるようになって解決した(Building the VirtualBox Guest Additions kernel modules にOKが出ていないのが気になるけど)。
Vimのカラースキームを設定できない問題
問題
VimのカラースキームをSolarizedに設定しようとして、.vimrcに以下のように書いて
NeoBundle 'altercation/vim-colors-solarized' syntax enable set background=dark colorscheme solarized
何かファイルを開こうとすると、以下の Cannot find color scheme のエラーが出てカラースキームが設定されない。
$ vim .vimrc Error detected while processing /Users/user/.vimrc: line 100: E185: Cannot find color scheme 'solarized' Press ENTER or type command to continue
解決方法
Cannot find color scheme solarized · Issue #104 · altercation/vim-colors-solarized
によると、 colorscheme solarized
は call vundle#end()
の後に書けとのこと。
というわけで、.vimrcを
· · · NeoBundle 'altercation/vim-colors-solarized' · · · call neobundle#end() · · · syntax enable set background=dark colorscheme solarized
と書くようにしたら、エラーを解消してカラースキームの設定をすることができた。
ファイルの文字列をソートし直しててファイルに出力するRubyスクリプト
コマンドライン引数に指定されたファイルに書かれてある文字列をソートし直して1行ずつ新たなファイルに出力するRubyスクリプトを書いた。
ファイルの文字列をソートし直しててファイルに出力するRubyスクリプト
# -*- coding: utf-8 -*- input_file = ARGV[0] added_filename = '_in_line' # 入力ファイルネームが'hoge.txt'なら出力ファイルネームは'hoge_in_line.txt'とする output_file = File.basename(input_file, '.*') + added_filename + File.extname(input_file) File.open input_file do |i_file| File.open output_file, 'w' do |o_file| o_file.puts i_file.read.split(/\s+/).sort end end
こんなファイルを
aaa ddd eee ggg fff ccc hhh iii bbb
以下のように出力し直す。
aaa bbb ccc ddd eee fff ggg hhh iii
動機として、 $ brew list
で出力されたものを1行ずつ改行した形でファイルに出力したものが欲しかったので書いた。
ただ、すぐに $ brew list > hoge.txt
とリダイレクトを使えば望むものが手に入ることが分かったので、今後は使うことはないと思う。
CentOSローカル開発環境構築用のAnsibleのplaybookを作った
概要
VagrantでCentOS6.6にGit,(私の)dotfiles,Zsh,Oh-My-Zsh,peco,tmux,Vim,Nginx,MySQL,rbenvをインストールしてローカル開発環境構築を自動化するAnsibleのplaybookを作った。
以下が作ったplaybook。
背景
Railsで遊ぶためにVagrantでローカル開発環境を構築しようと思ったけど、どうせなら環境構築を自動化したいと思い、構成管理ツールの中で興味があったAnsibleの勉強がてらVagrantのCentOSのローカル開発環境構築用のAnsibleのplaybookを作った。Railsと言いながらrbenvのインストールまでの自動化になっている^^;
環境
- VirtualBox 5.0.2
- Vagrant 1.7.4
- Ansible 1.9.2
- Vagrant Box chef/centos-6.6
実行
$ git clone git@github.com:shifumin/vagrant-ansible-centos.git $ cd vagrant-ansible-centos $ vagrant up
playbookの内容
CentOS6.6に
- Git 2.5.0
- (私の)dotfiles ( https://github.com/shifumin/dotfiles )
- Zsh 5.0.8 (+Oh-My-Zsh)
- peco
- tmux 2.0
- Vim 7.4
- Nginx
- MySQL 5.6
- rbenv
をインストールする。
各rolesの詳しい内容は以下のとおり。
yum_repo
yum_install
- 必要そうなパッケージをインストール
- Development Tools をグループインストール
Git
- 依存パッケージのインストール
- ソースコードからGitをダウンロードして解凍してインストール
dotfiles
Zsh
peco
- pecoのバイナリをダウンロードして解答して/usr/local/binにコピーする。
tmux
Vim
- Vimパッケージ他のインストール
Nginx
- Nginxパッケージをインストールする
- ginxを起動し、自動起動の設定をonにする
MySQL
rbenv
- 依存パッケージのインストール
- rbenvのインストール
- ruby-buildのインストール
- rbenv-default-gemsのインストール
- ~/dotfiles/default-gemsのシンボリックリンク張り
- rbenv-updateのインストール
- ソースコードからRSenseをダウンロードして解凍してインストール
ディレクトリ構成
vagrant-ansible-centos/ ├── playbook/ │ ├── group_vars/ │ │ └── all.yml │ ├── roles/ │ │ ├── dotfiles/ │ │ │ └── tasks/ │ │ │ └── main.yml │ │ ├── git/ │ │ │ └── ... │ │ ├── rbenv/ │ │ │ └── ... │ │ ├── tmux/ │ │ │ └── ... │ │ ├── vim/ │ │ │ └── ... │ │ ├── yum_repo/ │ │ │ └── ... │ │ ├── yum_update/ │ │ │ └── ... │ │ └── zsh/ │ │ │ └── ... │ ├── hosts │ └── site.yml ├── Vagrantfile └── ansible.cfg
基本的には、公式のベストプラクティスに沿った構成になっているはず。 メインのplaybookは playbook/site.yml 、inventoryファイルは playbook/hosts、変数の格納ファイルは playbook/group_vars/all.yml とした。
詰まったところ
全てがSSH関連でほとんどがgitモジュール関連。
SSH Error: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)
問題
ansible-playbookしようとすると、初っ端に以下のエラーが出る。
fatal: [192.168.xx.xx] => SSH Error: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password). while connecting to 192.168.42.30:22 It is sometimes useful to re-run the command using -vvvv, which prints SSH debug output to help diagnose the issue.
公開鍵が云々。
解決方法
原因はこれらしい。 ansible.cfgに private_key_file を付け加える。
[defaults] private_key_file = .vagrant/machines/web/virtualbox/private_key
Warning: Permanently added the RSA host key for IP address '192.30.xx.xx' to the list of known hosts
問題
gitモジュールでgit cloneしようとすると、以下のエラーが出る。
failed: [192.168.xx.xx] => {"cmd": "/usr/local/bin/git ls-remote '' -h refs/heads/HEAD", "failed": true, "rc": 128} stderr: Warning: Permanently added the RSA host key for IP address '192.30.xx.xx' to the list of known hosts. Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. msg: Warning: Permanently added the RSA host key for IP address '192.30.xx.xx' to the list of known hosts. Permission denied (publickey). fatal: Could not read from remote repository.
known hostsにhostkeyが云々。
解決方法
Vagrant上に構築する仮想環境に秘密鍵を置かずにGithubとやり取りをするためにansible.cfgに ForwardAgent=yes を付け加える。
[ssh_connection] ssh_args = -o ForwardAgent=yes
Failed to find required executable git
問題
同じく、gitモジュールでgit cloneしようとすると、以下のエラーが出る。
failed: [192.168.xx.xx] => {"failed": true} msg: Failed to find required executable git FATAL: all hosts have already failed -- aborting
gitのバイナリがない?って言われる。
解決方法
sudo時にgitへのPATHが通っていないからっぽい。 gitモジュールではsudoじゃなくてユーザで実行させるために、taskに sudo=no をつける。
--- - name: git clone dotfiles repository sudo: no git: repo=git@github.com:shifumin/dotfiles.git dest=/home/{{ user }}/dotfiles accept_hostkey=yes
github.com has an unknown hostkey
問題
さらに同じく、gitモジュールでgit cloneしようとすると、以下のエラーが出る。
failed: [192.168.xx.xx] => {"failed": true} msg: github.com has an unknown hostkey. Set accept_hostkey to True or manually add the hostkey prior to running the git module
github.comに登録されてあるhostkeyが違う?ので、accept_hostkeyを有効にしろって言われる。
解決方法
playbookの一番最初に実行するgitモジュールのtaskに accept_hostkey=yes をつける。 初回のみでいいはず。
--- - name: git clone dotfiles repository sudo: no git: repo=git@github.com:shifumin/dotfiles.git dest=/home/{{ user }}/dotfiles accept_hostkey=yes
以下メモ
変数をどこに格納するか
変数をどこに書くかに大分迷ったけど、変数の使い分け等をしない場合は group_vars/all に書いておけば特に指定しなくても全rolesに適用されるようだ。 また、ファイル名をall.ymlとすることで、シンタックスハイライトを付けることができる(YAMLファイルにシンタックスハイライトを設定している場合)
したがって、変数は、 group_vars/all.yml に記述することにした。
ソースコードをダウンロードして解凍してmake installするやり方
他の人の方法を見ていたら色々なやり方・書き方があることが分かって、当初は全てをshellモジュールを使って一気通貫で処理させていた。 例えば以下のように記述していた。
- name: install tmux shell: | wget https://github.com/tmux/tmux/releases/download/{{ tmux_ver }}/tmux-{{ tmux_ver }}.tar.gz tar zxvf tmux-{{ tmux_ver }}.tar.gz rm -f tmux-{{ tmux_ver }}.tar.gz cd tmux-{{ tmux_ver }} ./configure make make install args: chdir: "{{ src_dir }}"
しかし、shellモジュールは冪等性が担保されずに初回以降も毎回実行されて (上手く条件分岐すれば回避できるだろうけど)スキップされないので、Ansible標準のモジュールを使いtaskを分けるようにした。
つまり、以下のように、get_urlモジュールでソースコードをダウンロードして、unarchiveモジュールで解凍して、最後のmake installだけをshellモジュールで処理するようにした。
--- - name: download tmux source get_url: url=https://github.com/tmux/tmux/releases/download/{{ tmux_ver }}/tmux-{{ tmux_ver }}.tar.gz dest="{{ src_dir }}/tmux-{{ tmux_ver }}.tar.gz" - name: extract tmux source unarchive: src="{{ src_dir }}/tmux-{{ tmux_ver }}.tar.gz" dest="{{ src_dir }}" copy=no - name: install tmux shell: > {{ item }} chdir="{{ src_dir }}/tmux-{{ tmux_ver }}" creates="{{ bin_dir }}/tmux" with_items: - ./configure - make - make install
get_urlモジュールはdestに既にファイルが存在する場合はスキップされ、unarchiveモジュールもdestのディレクトリに解凍後のファイルがあればスキップされるので冪等性は保たれる。そして、最後のmake installのshellモジュールはcreatesでインストールされていたらスキップするようにした。
YAMLで複数行にわたる書き方
上記の、ソースコードからmake installするshellモジュールの書き方を考えている時に、どうしたらきれいに書けるだろうと調べていたら、YAMLにはLiteral StyleとFolded Styleという書き方があることを知った。
Literal Style
Literal Styleはインジケータとして "|" を使う書き方で、
text: | hoge foo bar
"text" => "hoge\nfoo\nbar\n"
各行の改行が保存される。
Folded Style
そして、Folded Styleは、インジケータとして ">" を使う書き方で、
shell: > hoge foo bar
"text" => "hoge foo bar\n"
各行の改行が半角スペースに置換され、最終行の改行は保存される。
この2つを使えば、例えば、shellモジュールで./configureした後にmakeしてその後にmake installする処理は、
shell: | ./configure make make install
と書けるし、
./configure && make && make intallする処理を複数行に分けて書きたい時は、
shell: > ./configure && make && make install
と書くことができる。
詳しくは、
YAML Ain’t Markup Language (YAML™) Version 1.2
の 8.1.2. Literal Style と 8.1.3. Folded Style 辺りに書いてあった。
終わり
ゆくゆくはさくらVPSのCentOS本番環境構築自動化に取り組みたい。
・・・の前にNginxとMySQLの初期設定の自動化にも取り組みたい。
参考
Best Practices — Ansible Documentation
Configuration file — Ansible Documentation
git - Deploy software (or files) from git checkouts — Ansible Documentation
YAML Ain’t Markup Language (YAML™) Version 1.2
Ansibleを使い出す前に押さえておきたかったディレクトリ構成のベストプラクティス - 双六工場日誌
Kobitoのデータをバックアップするシェルスクリプト
はじめに
ドットインストールのシェルスクリプト入門を見たので、せっかくだから勉強がてら何かを書こうと思い、Kobitoのデータをバックアップするシェルスクリプトを書きました。
環境
前提
Kobitoのデータ
Kobitoのデータは、 ~/Library/Containers/com.qiita.Kobito/Data/Library/Kobito にある
- Kobito.db
- Kobito.db-shm
- Kobito.db-wal
- Kobito.db.xxxxxxx.bak
の3つ(4つ)。
Kobitoのデータの保存は、
- Kobitoを終了する
- メニュー - アイテム - 保存 を選択する
の2つの時にされるっぽい。
スクリプト
コード
#!/bin/bash # データをバックアップするディレクトリ backup_dir_path=~/Dropbox/project/Kobito # Kobitoの元データ保存されているディレクトリ data_dir_path=~/Library/Containers/com.qiita.Kobito/Data/Library/Kobito # バックアップディレクトリの作成 if [ ! -e $backup_dir_path ]; then mkdir -p $backup_dir_path fi # バックアップファイルネームの作成 date=`date +"%Y%m%d"` db_filename=Kobito.db.$date.bak db_shm_filename=Kobito.db-shm.$date.bak db_wal_filename=Kobito.db-wal.$date.bak # バックアップ処理 echo "バックアップディレクトリは $backup_dir_path です" cp -p $data_dir_path/Kobito.db $backup_dir_path/$db_filename && echo "Kobito.db を $db_filename としてバックアップしました" cp -p $data_dir_path/Kobito.db-shm $backup_dir_path/$db_shm_filename && echo "Kobito.db-shm を $db_shm_filename としてバックアップしました" cp -p $data_dir_path/Kobito.db-wal $backup_dir_path/$db_wal_filename && echo "Kobito.db-wal を $db_wal_filename としてバックアップしました"
説明
4-7行目:ディレクトリの指定
backup_dir_pathにバックアップを作成するディレクトリを指定する。 上のコードは、"~/Dropbox/project/Kobito"ディレクトリを指定している。
9-12行目:バックアップディレクトリの作成
バックアップを作成するディレクトリが存在しなければ作る。
14-18行目:バックアップファイルネームの作成
バックアップファイルネームはそれぞれ、"(元のファイルネーム)YYYYMMDD.bak"。 例えば、Kobito.dbを2015年7月16日にバックアップすると、"Kobito.db.20150716.bak"という名前になる。
20-27行目:バックアップ処理
ファイルのバックアップに成功すると、バックアップした旨を表示する。
実行
$ chmod 744 backup_kobito.sh $ ./backup_kobito.sh Kobito.db を Kobito.db.20150716.bak としてバックアップしました Kobito.db-shm を Kobito.db-shm.20150716.bak としてバックアップしました Kobito.db-wal を Kobito.db-wal.20150716.bak としてバックアップしました
$ ls ~/Dropbox/project/Kobito Kobito.db-shm.20150716.bak Kobito.db-wal.20150716.bak Kobito.db.20150716.bak
以上
すでに同名バックアップファイルが存在した時の上書き処理があった方がいいんだろうけど、どういう処理がベストなのかよくわからない……
ソースコードからインストールしたGitをアンインストールできない問題
問題
さくらVPSのCentOSのソースコードからインストールしたGit(2.3.1)をアンインストールして最新版のGit(2.4.5)をインストールしようとしたところ、アンインストールできなかった。
# cd /usr/local/src/git-2.3.1/ # make uninstall make: *** ターゲット `uninstall' を make するルールがありません. 中止.
# find . -type f -name "Makefile" (前略) ./Makefile (後略)
Makefileはあるけど、Uninstallに関する記述がない?
環境
CentOS 6.6
Git 2.3.1 # アンインストールできなかったバージョン
(インストールディレクトリは $ ./configure --prefix=/usr/local/
と指定した)
解決
適当なディレクトリにもう一度インストールしてみて、その時インストールされたファイルをリストにしてそれを元に消すという方法。
まず、適当なディレクトリを作成し、そこにGitをインストールする。
# mkdir /tmp/test_git # cd /usr/local/src/git-2.3.1/ # make prefix=/tmp/test_git install
次に、インストールされたファイルをリストとして出力する。
# find /tmp/test_git -type f -print > /tmp/git-installlist.txt
そして、出力されたファイルの全行の /tmp/test_git
を /usr/local
(元のインストールディレクトリ)に置換する。
# vim /tmp/git-installlist.txt
:%s/\/tmp\/test_git/\/usr\/local/g
置換した結果
/tmp/test_git/libexec/git-core/git-send-pack /tmp/test_git/libexec/git-core/git-am /tmp/test_git/libexec/git-core/git (後略)
↓↓↓
/usr/local/libexec/git-core/git-send-pack /usr/local/libexec/git-core/git-am /usr/local/libexec/git-core/git (後略)
最後に、| xargs
でgit-installlist.txtの内容をrmに渡してファイルを消す。
# cat /tmp/git-installlist.txt | xargs rm -f
アンインストール完了。 これにて一件落着です。