git用のpre-commit gemが便利すぎる
まずは
$ gem install pre-commit # In your git repo $ pre-commit install
これだけで、うっかり残念なコミットをする事故が防げます。
Git フック使ってますか?
コミットする前にバリデーションかけて、通らなかったらコミット中止する。コミットメッセージにブランチ名を自動挿入する。など、ルーティンワークをフックに仕込んでおけば、誰も読まないガイドラインページを書く手間が省けますし、強制する事ができて幸せです。
じゃあ、何をフックに設定するかと言うと
コードレビューしていると、気になるけどいちいち指摘するのも面倒くさい事が良いんじゃないかと。
- 行末の空白文字くらい消せよ!
- タブインデント止めて!
- binding.pry消し忘れてんぞ! などなど
そこで、pre-commit gemですよ
https://github.com/jish/pre-commit
デフォルトで便利なバリデーションをたくさん持っているので、いちいち自分で作成する必要が無いところがありがたい。 現在のチェック項目を確認したい場合は、pre-commit listで確認できます。
$ pre-commit list Available providers: default(0) git(10) git_old(11) yaml(20) env(30) Available checks : before_all ci closure coffeelint common console_log csslint debugger gemfile_path go jshint jslint json local merge_conflict migration nb_space php pry rails rspec_focus rubocop ruby ruby_symbol_hashrockets scss_lint tabs whitespace yaml Default checks : common rails Enabled checks : common rails Evaluated checks : tabs nb_space whitespace merge_conflict debugger pry local jshint console_log migration Default warnings : Enabled warnings : Evaluated warnings :
common と rails がデフォルトで有効になっているcheck項目で、実際には"Evaluated checks"のが実行されます。
- tabs: インデントにタブが使われていないか
- nb_space: ノーブレークスペースが使われていないか
- whitespace: git diff --check --cachedを実行する(Git自体に便利コマンドがある!)
- merge_conflict: コンフリクトが解消されていないファイルを上げようをしていないか
- debugger: debuggerを消し忘れていないか
- pry: binding.pryを消し忘れていないか
- local: ユーザが定義したバリデーションが通るか
- jshint: JSファイルがjshintを通るか
- console_log: console.logを消し忘れていないか
- migration: Railsのdb, schemaファイルの整合性は取れているか(片方だけコミットしようとしていないか)
これだけでも、十分有用です
check追加したい
git configに追加する方法と、YAMLファイルで管理する方法があります。YAML形式で書き出しておいて、このファイルもプロジェクトに含めてしまえば、他のチームメンバーはpre-commit installをするだけで済むので、YAMLがいいんじゃないかと。
checks, warningsの違いはチェックに引っかかった時に、コミットを許容するか否かです。 cheksだと、そのままコミットさせない。warningsだと、警告を出すだけにとどめる。
$ pre-commit <enable|disable> <git|yaml> <checks|warnings> check1 [check2...]
# rubocopのチェックを追加するが、警告を出すだけ $ pre-commit enable yaml warnings rubocop
独自バリデーションも適応したい
config/pre-commit.rb というファイルを置いておけば、引数としてコミット対象のファイル名を渡してくれます。exitで0よりも大きな数字を返せば、バリデーションに通らなかったことを通知できます。
# config/pre-commit.rb valid = ARGV.all? do |file| # validate end exit valid ? 0 : 1
Guidelines as a Code
人力チェックリストを作るくらいなら、機械にテストさせた方がよっぽど正確だよね。って話でした。
新人への洗礼
新人の子が離席時にPCロックを忘れている!
チャンスですね
ls
ど定番
alias ls=sl
echo
牛さんのAAに癒されます
alias echo=cowsay
_______ < hello > ------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
xcowsayは、最近知りました。 より癒されます。
alias echo=xcowsay
cat
猫がマウスカーソルを追いかけてきます。 無駄な引数があると、エラーになるので引数は捨て去りますw
function cat() { oneko }
EDITOR
nanoで十分です
export EDITOR=nano alias vim=nano alias gvim=nano alias emacs=nano alias xemacs=nano alias sbul=nano alias atom=nano
32bit Win7上でVagrant使って開発環境構築 box構築編
本日の流れ
- veeweeのtemplateから作成したいVMのtemplate選ぶ→definition作成
- definitionを微修正
- definitionを基にubuntuをインストール
- Vagrant用boxファイル作成
- vagrant up
VMのtemplate選ぶ
veewee落としてきたディレクトリへ移動する
ここは、適宜読み替えて
> cd work\veewee
template一覧表示
> bundle exec veewee vbox templates
ubuntu-13.04-desktop-i386が無いorz
しょうがないので、server版をインストールして、後でGUI対応する。
> bundle exec veewee vbox define 'ubuntu-13.04-desktop-i386' 'ubuntu-13.04-server-amd64'
これで、definitions\ubuntu-13.04-desktop-i386以下にtemplateがコピーされるわけだが
改行コードがWin仕様だと、Ubuntuが正しく解釈できないので
全てのファイルの改行コードを\nに変換しておく。
忘れると、invalid operationと言われ泣きを見るはめになる。。。
definitionを微修正
definitions\ubuntu-13.04-desktop-i386\definition.rbを編集
32bitな民は、amd64ではなくi386のイメージを指定する。
8,11c8,11 < :os_type_id => 'Ubuntu_64', < :iso_file => "ubuntu-12.10-server-amd64.iso", < :iso_src => "http://releases.ubuntu.com/12.10/ubuntu-12.10-server-amd64.iso", < :iso_md5 => '4bd3270bde86d7e4e017e3847a4af485', --- > :os_type_id => 'Ubuntu', > :iso_file => "ubuntu-13.04-server-i386.iso", > :iso_src => "http://releases.ubuntu.com/raring/ubuntu-13.04-server-i386.iso", > :iso_md5 => '73d595b804149fca9547ed94db8ff44f',
apt.shに追記
1行目にsourceのURLをミラーサーバから取得するよう変更するsed追記
変えなくても取得は可能だが、転送スピードが1.5~2倍近く早くなるので、推奨。
> sed -i -e 's#us.archive.ubuntu.com#mirror.math.ucdavis.edu#g' /etc/apt/sources.list
末尾に、ubuntu-desktopをインストールする行を追記。
このままだと、CLIなのでGUI用のパッケージ入れる。
> apt-get -y install ubuntu-desktop
definitionを基にubuntuをインストール
> bundle exec veewee vbox build 'ubuntu-13.04-desktop-i386' --workdir=C:/Users/takeshi.takizawa/work/veewee
Downloading vbox guest additions iso v 4.2.16 - http://download.virtualbox.org/virtualbox/4.2.16/VBoxGuestAdditions_4.2.16.iso Checking if isofile VBoxGuestAdditions_4.2.16.iso already exists. Full path: C:/Users/takeshi.takizawa/work/veewee/iso/VBoxGuestAdditions_4.2.16.iso The isofile VBoxGuestAdditions_4.2.16.iso already exists. Building Box ubuntu-13.04-desktop-i386 with Definition ubuntu-13.04-desktop-i386: - debug : false - cwd : C:/Users/takeshi.takizawa/work/veewee - force : false - nogui : false - auto : false - checksum : false - redirectconsole : false - postinstall_include : [] - postinstall_exclude : [] We did not find an isofile here : C:/Users/takeshi.takizawa/work/veewee/iso/ubuntu-13.04-server-i386.iso. The definition provided the following download information: - Download url: http://releases.ubuntu.com/raring/ubuntu-13.04-server-i386.iso - Md5 Checksum: 73d595b804149fca9547ed94db8ff44f Download? (Yes/No)
忘れずに、Yesとタイプする。
時間がかかるので、まったりコーヒーでも飲みながら待つ。
The box ubuntu-13.04-desktop-i386 was built successfully! You can now login to the box with: ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 7222 -l vagrant 127.0.0.1
成功!
Win7 32bit Core i5-2520M 2.5GHz 4.00GB
で、3時間程度かかった。
Vagrant用boxファイル作成
> bundle exec veewee vbox export 'ubuntu-13.04-desktop-i386'
vagrantに登録
> vagrant box add ubuntu-13.04-desktop-i386 'C:/Users/takeshi.takizawa/work/veewee/ubuntu-13.04-desktop-i386.box'
vagrant up
ここからは、boxファイルに対して色々操作していく。
作業用ディレクトリに移動して
> cd working\directory
Vagrantfile作成
> vagrant init 'ubuntu-13.04-desktop-i386'
いざ、起動!
> vagrant up
sshで入れるかな?
> vagrant ssh
Welcome to Ubuntu 13.04 (GNU/Linux 3.8.0-19-generic i686) * Documentation: https://help.ubuntu.com/ Last login: Thu Aug 15 07:15:17 2013 from 10.0.2.2 vagrant@ubuntu-13:~$
すばらっ
あとは、rails等のCookbookを
http://community.opscode.com/
から、ありがたく頂戴すれば良いはず。
32bit Win7上でVagrant使って開発環境構築 準備編
動機
備えあれば憂いなしでございます。
準備
- Install Ruby http://rubyinstaller.org/
- Install pik https://github.com/vertiginous/
- Install Development Kit http://rubyinstaller.org/downloads/
- Install veewee https://github.com/jedi4ever/veewee
- Install VirtualBox https://www.virtualbox.org
- Install Vagrant http://www.vagrantup.com
- Install Git http://git-scm.com/downloads
Install pik
2013/08/17 14:00
rubyのバージョンを1.9.2 -> 1.9.3に変更
Rubyのバージョン管理してくれるgem
Windows版のrmvもしくはrbenv
同じバージョンだけれど、gemだけ分けたいってのは無理なのかな?こういうの
$ rvm use 1.9.2@veewee --create
この件は、いったん保留して
サクッとgem install
> gem install pik
まだ、終わりじゃない。
PATH通っているところに、pikコマンドをインストールする必要がある。
Cドライブ直下に、binディレクトリ作ってパス通しておく。
> mkdir C:\bin
コントロールパネル -> システム -> システムの詳細設定 -> 詳細設定 -> 環境変数 -> システム環境変数
無ければPathを新規作成して、あればpathを編集
末尾に追記
;C:\bin
pikコマンドをインストールする
> pik_install C:\bin
ようやく完了。
ruby-1.9.3入れとく。
> pik install ruby 1.9.3 > pik use 1.9.3
もし、7zipが無いと怒られたら
エラーの通り、7zipを入れる。
親切なエラーですね、エラーってこうあるべき。
> pik package 7zip install
Install Development Kit
C/C++の拡張をbuildするのに必要。
最初のRubyと一緒に入れても良かったけれど
pikで取ってきたRubyにもインストールするので
ここで、一緒に入れる。
インストール手順
https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
Cドライブ直下に、DevKitフォルダ作る
https://github.com/oneclick/rubyinstaller/downloads/
から、DevKit-4.5.2 self extracting archive ダウンロードする
展開先を、C:\DevKitにする
> cd C:\DevKit > ruby dk.rb init
気をつけるのは、config.ymlにpikで入れたRubyのpathを追加することくらい
最後の行に、pikで入れたRubyのpathを追記。
# This configuration file contains the absolute path locations of all # installed Rubies to be enhanced to work with the DevKit. This config # file is generated by the 'ruby dk.rb init' step and may be modified # before running the 'ruby dk.rb install' step. To include any installed # Rubies that were not automagically discovered, simply add a line below # the triple hyphens with the absolute path to the Ruby root directory. # # Example: # # --- # - C:/ruby19trunk # - C:/ruby192dev # --- - C:/Ruby192 - C:/Users/takeshi.takizawa/.pik/rubies/Ruby-193-p429
インストール
pikで新しくruby追加したら、そのバージョンにも忘れずにDevKit入れる。
> ruby dk.rb install
defaultのrubyを変更したい場合は、環境変数のPathのrubyの向き先を変える必要がある。
今回の場合、Pathには
C:/Ruby192
が書かれているので
C:/Users/takeshi.takizawa/.pik/rubies/Ruby-193-p429
に変更する。
いちいち面倒だな。。。
Install veewee
Vagrantのbox作成をサポートしてくれるgem
既存のboxで十分な場合は、不要。
既存のVagrant box一覧は、こちら
http://www.vagrantbox.es/
veeweeを使う場合、githubから頂戴してくる
> cd <path_to_workspace> > git clone https://github.com/jedi4ever/veewee.git > cd veewee
bundlerでinstall
> gem install bundler > bundle install
veeweeコマンド叩いて、コマンド一覧が見れれば
インストール成功
> bundle exec veewee
Install VirtualBox
仮想マシンを実行する仮想化ソフトウェア・パッケージ
Install Git
バージョン管理さまさま
RubyでDSL作ってみる
てことで
- DSL用のメソッドAを用意
- DSLで書かれたファイルを読み込む
- メソッドAと同じインスタンスで、ファイルの内容をinstance_eval
- -_-b
Example
DSL用のメソッドを持ったクラス
class DSL attr_reader :names def self.execute contents = File.open('DSLFile', 'rb'){ |f| f.read } dsl = new dsl.instance_eval(contents) p dsl.names end def initialize @names = [] end def hello(name) @names << name end end
DSLファイル
hello 'world' hello 'again' hello 'kitty'
実行してみる
DSL.execute ["world", "again", "kitty"]
imagemagickをインストール
公式のFAQや、似たような記事は多数あるのですが、それでも嵌ったのでメモ残しときます。
事前準備
Install XQuartz
結果を出力するときに、ウィンドウ(X11)に出す場合は、先にXQuartzをインストールしておく必要があります。
display: delegate library support not built-in `' (X11) @ error/display.c/DisplayImageCommand/1909.
Unsatisfied dependency: XQuartz· Homebrew does not package XQuartz. Installers may be found at: https://xquartz.macosforge.org
こんなエラーが出る場合は、XQuartzが入ってないです。
エラーが教えてくれている通りに、 https://xquartz.macosforge.org からインストールします。
Install libtool
なかったら入れておきます。
sudo brew install libtool
動かしたときに、以下のエラーが出る場合はリンク張りましょう
Library not loaded: /usr/local/lib/libltdl.7.dylib (LoadError)
sudo brew link --force libtool
set display
表示先を指定しておきます
export DISPLAY=:0.0
Install imagemagick
デフォルトだと、X11(XQuartz)利用しないので、オプションに指定してインストールします。
sudo brew install imagemagick --with-x11
お疲れ様です。インストール完了です。
動かしたときに、以下のエラーが出る場合は、X11が起動してません。
`display': unable to open X server `' @ error/display.c/DisplayImages/1666 (Magick::ImageMagickError)
/Applications/Utilities/XQuartz をダブルクリックして起動してやりましょう。
やれやれ、インストールで力つきちゃったよ。。。
バイナリ形式にするだけでメモリ節約プログラミング
比較条件に関係しない値なら、バイナリにする価値あり
小さい数値を多く扱う場合は、バイナリ(可変長表現)にすると結構小さくできます。
データ量が小さくなれば、DBからの取得速度が向上し、アプリのメモリ上にもより多くのデータを保持できるようになります。
ただ、バイナリ形式のままだと大小比較などの計算ができないので、必要に応じて数値型に戻してあげる必要があります。
コード
今回比較に利用したコードは、githubに上げてあります。
https://github.com/TakiTake/seiseki
数値とバイナリの速度比較
学校の生徒100人が毎日テストを5科目受けたときの成績管理用DBを想定
バイナリ形式のDBは、科目カラムに5科目分のデータを保持させます。
テストデータなんで、土日祝日お構いなしにテスト受けてますw
ノーマルなDB
カラム名 | 型 |
日付 | text |
学籍番号 | text |
科目1 | integer |
科目2 | integer |
科目3 | integer |
科目4 | integer |
科目5 | integer |
バイナリ形式のDB
カラム名 | 型 |
日付 | text |
学籍番号 | text |
科目 | blob |
結果
1年分のデータ
size
normal 1.9MB binary 1.7MB
insert
user system total real normal 4.740000 11.920000 16.660000 ( 94.378284) binary 4.660000 11.920000 16.580000 ( 93.093927)
select
user system total real normal 0.210000 0.010000 0.220000 ( 0.221661) binary 0.190000 0.010000 0.200000 ( 0.201906)
5年分のデータ
size
normal 9.6MB binary 8.8MB
insert
user system total real normal 23.860000 58.860000 82.720000 (476.608330) binary 23.530000 58.400000 81.930000 (507.330652)
select
user system total real normal 1.190000 0.070000 1.260000 ( 1.300539) binary 0.980000 0.070000 1.050000 ( 1.078891)
10年分のデータ
size
normal 19MB binary 18MB
insert
user system total real normal 47.350000 118.030000 165.380000 (920.600014) binary 46.610000 118.380000 164.990000 (935.340207)
select
user system total real normal 2.140000 0.100000 2.240000 ( 2.236974) binary 1.790000 0.100000 1.890000 ( 1.891564)
なぜ、サイズが小さくなるのか?
小さい数値を表すのに、8 byte もいらないよね
環境差分はありますが、自分の環境ではRubyのFixnumは、8 byte でした。
0~255までの数値なら 1byte で表すことができるので、固定長ではなく可変長で数値を扱えば、 7byte 削減できというわけです。
どうやって変換すればいいの?
数列 -> バイナリ文字列
Array#pack のテンプレートに w(BER-compressed integer) を指定するだけです。
http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-pack
バイナリ文字列 -> 数列
String#unpack テンプレートに w(BER-compressed integer) を指定するだけです。
http://www.ruby-doc.org/core-1.9.3/String.html#method-i-unpack
応用編
ただの文字列なので、文字列結合もできます
[33, 49, 300, 99, 1000].pack('w5') // "!1\x82,c\x87h"
'abc' + [33, 49, 300, 99, 1000].pack('w5') // "abc!1\x82,c\x87h"
また、こういった文字列処理には、StringScannerが便利です。
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/strscan/rdoc/StringScanner.html
先頭から、3 byte 取得
str = 'abc' + [33, 49, 300, 99, 1000].pack('w5') ss = StringScanner.new(str) ss.peek(3) // "abc"
3 byte 分ポインタを進める
ss.pos += 3
ここから後ろは、可変長なので何byte分取得すればいいかわかりません。
そんなときは、文字列中にbyte数を持たせてあげれば、そこから判断できます。
サイズを含む文字列
packed = [33, 49, 300, 99, 1000].pack('w5') # packした文字列のサイズをさらに、packする # C(8-bit unsigned)にすることで、この1byteを読めば続く文字列のサイズが分かる # 文字列のサイズが、8bitで表しきれない場合は、テンプレートにS, L, Qを適宜使う packed_size = [packed.size].pack('C') str = 'abc' + packed_size + packed ss = StringScanner.new(str) # "abc"の3byte分進める ss.pos += 3 # 1byte取得して、unpackすることで保存しておいたサイズを取得 # unpackは、配列で返ってくるので、最初の要素を取得している ss.peek(1).unpack('C').first // 7 # サイズを格納している、1byte分進める ss.pos += 1 # 最後に、先ほど判明した7byte分取得して、unpackすると # めでたく最初の数列が取得できる ss.peek(7).unpack('w5') // [33, 49, 300, 99, 1000]