思いついたネタだけど、作る時間がないので公開してみた
タイトル通りですが、ネタ帳で塩漬けされてたネタを列挙してみた。
もし面白いネタがあれば自由に使っても構わないです
駅情報の管理システム
確定申告の前に自分の行った駅を後から確認したり、交通費を簡単に算出できるサービス。
自分の移動した駅を出来るだけ簡単に登録できるのが前提。
考えてた実装方法は2通り
週40時間を表示する砂時計
仕事開始前にwebページの[Start]を押すと砂時計の砂が落ちて、仕事終了時に[End]を押して砂時計を止められるwebページ
FelicaとSNSを連携した認証システム
FelicaカードとSNSのアカウントを紐付けて、カードだけで簡単にSNSアカウントを識別できるサービス
使い道
あまり使い道が思い浮かばない...。
ただ、今はほとんどの人が1つ以上Felica(Suica, お財布携帯など)を持っているので、何かに使える気がする
自分の行きたい店、空いてる日を登録できるサービス
行きたいお店があった時、そのお店に行きたい他のユーザを簡単に検索できるサービス
- 一緒にお店に行ける人を手軽に募集できる
- 行きたいお店、空いてる日、参加条件、確定条件を入れておいて、確定したらメールがくる
- 参加条件: 女性のみ、20〜30歳まで、相互フォローしてる相手のみとか
- 確定条件: 4人以上、paypal支払い済み6人以上、男女比1:1とか
不動産の部屋の間取りを3Dで表示
8帖でも部屋の形とかで変わってくるので、間取り図(画像)、部屋の高さ(数値)、部屋の広さ(平米の数値)から3D化できたら便利かもと。
引越し時の思いつきネタ。
TDDネタ
TDDで書いてみようかなーと思ってたネタ
- ダーツのクリケット
- トランプのポーカー
- 麻雀の役の判定
ある程度の複雑さ、追加仕様として他ユーザとの対戦(スレッド)とかのテストも出来るかもしれない。
gitの作業ディレクトリでの移動が捗るgit_cdを作りました
11月19日にオラクルでSCMBootCamp in Tokyo 2というイベントがあり、そこでgitの講師してました。
周りの方のgitの質問に答えたり、コマンドの説明をしていたり。
濃い話が聞けたり、普段触らない他DVCSの話も聞けて楽しかったです。
あと、花映塚はやっぱり面白いですね!
そんな#scmbcの演習中
@1syoさんからの質問(質問だったと思う)で「gitの作業ディレクトリのrootに簡単に移動するコマンドとかないですか?」というものがありました。
具体的に書くと、こんな感じ。
例えば、下記のようなフォルダ構成だったとして。
~/rails_proj/.git ~/rails_proj/app/controllers
こういう時に
$ pwd /home/sinsoku/rails_proj/app/controllers $ git cd $ pwd /home/sinsoku/rails_proj/
こういう事ができないか?と。
言われるまで気づかなかったけど、便利そうなので調べてみましたが、標準には無いようです。
じゃあ、作りましょう!
仕様
仕様は上述した通りなのですが、もう一つ便利そうなのでこんな仕様を加えてみました。
$ pwd /home/sinsoku/rails_proj/app/controllers $ git cd spec $ pwd /home/sinsoku/rails_proj/spec
こんな感じのスクリプトの作り方を考えてみました。
bashrcに関数作った
出来れば"git cd"にしたかったけど、難しそうなので諦めて"git_cd"にして.bashrcに関数作りました。
git_cd() { path="`git rev-parse --git-dir`/../$1" ret=$? if [ ${ret} -eq 0 ]; then cd ${path}; fi } alias gcd="git_cd"
これでGitの作業ディレクトリでの移動が楽になって、作業が捗りますね!
何、勘違いしているんだ…まだ、俺のバトルフェイズは終了してないぜ…!!
追加スクリプト発動!
#!bash # # version: 0.2 # license: New BSD License # # how to install # =============== # # * Ubuntu # $ cp git_cd.bash /etc/bash_completion.d/git_cd _git_cd() { if [ ${COMP_CWORD} -lt 2 ]; then git_repo="`git rev-parse --git-dir 2>/dev/null`" ret=$? if [ ${ret} -ne 0 ]; then return 0; fi if [ "${git_repo}" == ".git" ]; then git_root="`pwd`/" else git_root="${git_repo%.git}" fi cur="${COMP_WORDS[COMP_CWORD]}" if [ -n "${cur##*/}" ]; then cur_d="${cur}/" else cur_d="${cur}" fi dist="${git_root}${cur_d}" if [ -d "${dist}" ]; then subs=`compgen -d "${dist}"` opts=`for s in ${subs}; do echo ${s#${git_root}}; done` else subs=`compgen -d "${dist%/[^/]*}/"` opts=`for s in ${subs}; do echo ${s#${git_root}}; done` fi COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) fi } complete -F _git_cd git_cd complete -F _git_cd gcd
このスクリプトを入れておくと、bash-completionでディレクトリの補完が効くようになります。
たぶんgit_cdの関数本体よりもこの補完スクリプトの方が時間かかってる。
git submodule を100倍便利にするpost-commit hook
追記[2011/11/20]
- submodule のコミット書き換えは上手く動いていないので、該当箇所を取り消し線で削除
100倍は釣りです。
深夜にgit helpを読みながら構築した黒魔術の構築式がこちらです。
git submoduleについて
gitで外部リポジトリを扱うコマンドです。
詳しくはgit submodule --help、もしくは参考ページを読んでください。
これは何?
親プロジェクトのGitリポジトリで変更をコミットした時、追加している全てのサブモジュールでも同時にコミットを行います。
コミットメッセージは親プロジェクトのコミットのコミットメッセージとsha-1になり、下記のようになります。
commit 5cd4716a7bb8b38557e11886256b878d004bd82e Author: sinsoku <sinsoku.listy[at]gmail.com> Date: Thu Oct 27 02:28:27 2011 +0900 親プロジェクトのコミットメッセージ This related commit ec7fa14290d651c02b27b6d151d7aac86b3ba2d4
注) 同時に行うのはコミットだけなので、submoduleのpushは手動です。
post-commit.for_submodule
コードはGitHubに置いてあります。
post-commitにリネーム&実行権限を追加して、使用したいリポジトリの.git/hooksにコピーして下さい。
sinsoku/dotfiles - GitHub post-commit.for_submodule.sample
Ubuntu 11.04で動作確認しており、Windowsでの動作は未検証です。
- post-commit.for_submodule.sample (c877bb5)
#!/bin/sh # # An example hook script that is called after a successful # commit is made. # # To enable this hook, rename this file to "post-commit". export supermsg="`git log -n 1 --format="%B" HEAD`" export pre_submsg="`git log -n 1 --format="%B%nThis related commit %H" HEAD`" git submodule foreach 'if [ -n "`git status -s`" ]; then git add -A; git commit -m "${pre_submsg}"; fi' submodules=`cat .gitmodules | grep "\[submodule" | awk 'match($0,/\"[-0-9a-zA-Z_\.\/]*\"/) { print substr($0,RSTART+1,RLENGTH-2) }'` for m in $submodules; do if [ -n "`git status -s $m`" ]; then git add $m fi done treeobj=`git write-tree` commitobj=`git commit-tree ${treeobj} -p HEAD^ <<EOF ${supermsg} EOF` git reset ${commitobj} export fix_submsg="`git log -n 1 --format="%B%nThis related commit %H" HEAD`" git submodule foreach 'if [ "`git log -n 1 --format="%B"`" = "${pre_submsg}" ]; then git commit --amend -m "${fix_submsg}"; fi'
hookの解説
簡単にpost-commit.for_submodule の作り方の説明。
post-commit
- Pro Gitから引用
コミットプロセスが全て完了した後に、post-commitフックが実行されます。パラメータは必要無く、git log -1 HEADを実行することで直前のコミットを簡単に取り出すことができます。一般的にこのスクリプトは何かしらの通 知といった目的に使用されます。
実行タイミングとしては、ユーザがコミットメッセージを作成し終わった時になります。
後述しますが、post-commit.for_submodule は親コミットを書き換える必要があるため、post-commitにしてあります。
post-commit-hook.for_submodule がやっている事
post-commit-hook.for_submodule は下記のような事をやってます。
- 親プロジェクトでコミットする。(この後にフックが起動する)
- 親プロジェクトのコミットメッセージを取得する。
- 各サブモジュールで変更をコミットする。
- 親プロジェクトのコミットを書き換え、サブモジュールのsha-1の変更をコミットに含める。
各サブモジュールのコミットを書き換え、親プロジェクトの書き換え後のsha-1をコミットメッセージに追加する。
一回のcommit-hookで、最低でも2回コミットが書き換わるお得なhookです。
図で分かるgit-mergeの--ff, --no-ff, --squashの違い
git-merge の--ff, --no-ff, --squashの違いをまとめてみた。
git helpから引用
まずは、git helpを読みましょう
- git merge --helpから引用(抜粋)
NAME git-merge - Join two or more development histories together SYNOPSIS git merge [-n] [--stat] [--no-commit] [--squash] [-s <strategy>] [-X <strategy-option>] [--[no-]rerere-autoupdate] [-m <msg>] <commit>... git merge <msg> HEAD <commit>... git merge --abort OPTIONS --ff, --no-ff Do not generate a merge commit if the merge resolved as a fast-forward, only update the branch pointer. This is the default behavior of git-merge. With --no-ff Generate a merge commit even if the merge resolved as a fast-forward. --squash, --no-squash Produce the working tree and index state as if a real merge happened (except for the merge information), but do not actually make a commit or move the HEAD, nor record $GIT_DIR/MERGE_HEAD to cause the next git commit command to create a merge commit. This allows you to create a single commit on top of the current branch whose effect is the same as merging another branch (or more in case of an octopus). With --no-squash perform the merge and commit the result. This option can be used to override --squash. --ff-only Refuse to merge and exit with a non-zero status unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward.
fast-forward(ファーストフォワード)って何?
マージの説明の前に、まずはGitのfast-forwardについて。
- 入門Git p.230 から引用
2つのコミットAとBとがあるときに、コミットAにいたる歴史がコミットBにいたる歴 史にすべて含まれている場合、2つのコミットはファーストフォワードの関係にある、と か、コミットAはコミットBにファーストフォワードする、といいます。
少し分かりにくいので、絵にしてみた。
各マージの解説
本題の各マージについて。
1. --ff
デフォルトの設定です。
もしマージ対象のブランチとfast-forwardの関係にある場合、マージコミットは作られず、ブランチの参照先の更新だけを行います。
(fast-forwardの関係でない場合、マージコミットが作られます)
$ git merge topic
各オプションの使い分けの前に
まずはプロジェクトのリポジトリの運用について決める必要があります。
- コミットの粒度
- rebase は必須であるか?
- トピックブランチのマージの時にマージコミットを作るか?
などを決め、プロジェクトのポリシーに沿ったコミットログを作るのが良いと思います。
オプションの使い分け
私はこうやって使っている・・・という例を紹介します。
他の便利な例や突っ込みがあれば、コメントで。
--ff
ログが一本になり、トピックブランチがあったという情報がなくなる。
トピックブランチの存在をログに残す必要がなく、そのままマージしてもコミット粒度が問題無い場合に使う。
--no-ff
--ffと異なり、トピックブランチがあったという情報が残る。
基本的には「A successful Git branching model」を参考に--no-ffを使うのが良い。
--squash
トピックブランチがあった情報も、コミットログも全て残らない。
トピックブランチで行った作業が少なく、1コミットにまとめてしまっても問題ない場合に使う。
git mergeで常に--no-ffにする
ついでに、常に--no-ffにする設定を紹介します。
この方法は2つあります。
方法1. エイリアスを使う
エイリアスを設定し、--no-ffのマージを行う時はgit nffmerge を使うようにする。
$ git config --global alias.nffmerge "merge --no-ff"
方法2. mergeoptions
マージオプションを設定すると、指定したブランチのマージでは設定値がデフォルトとして使用されます。
git config branch.<name>.mergeoptions "--no-ff"
ただし、この設定を行うとgit pull の実行時にもマージコミットが出来てしまい、マージコミットが大量に出来てしまうため、リモートの変更を取得したい時はgit pull --rebase を使う必要があります。
特定のブランチで必ずpull --rebase を有効にする
次のコマンドで設定できる。
$ git config branch.<name>.rebase true
全てのブランチでpull --rebase を有効にする
もし全てのブランチで設定したい場合、次のコマンドで設定する。
$ git config branch.autosetuprebase always
RSpecでArelのメソッドチェインをスタブにする
テストでメソッドチャインできるメソッドをスタブにする。
describe BlogsController do before do(:all) u = User.new User.stub_chain(:where, :limit, :order).and_return(u) end end
こういう書き方も出来る
describe BlogsController do before do(:all) u = User.new User.stub_chain([:where, :limit, :order] => u) end end
テスト対象のControllerの親クラスのfilterをskipする
テスト対象のControllerのActionのみをテストする時に便利。
describe BlogsController do before do superclass = controller.class.superclass super_filters = superclass._process_action_callbacks.map(&:filter) controller.class.skip_filter *super_filters end end
少しだけキモいコードになってしまいました。
もっと素敵な書き方があれば、コメントやブコメで教えて頂けるとありがたいです。
RubyでFizzBuzzを書いてみた
ネタは前回の記事のデコレータ式と同じだけど、Rubyだとこんな感じになる。
余計なメソッドが多いのは、なんとなくRubyっぽいからです。特に意味はない。
仕様
前回と同じ
1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。
テストコード
- fizzbuzz_spec.rb
#!/usr/bin/env ruby # -*- coding: utf-8 -*- require './fizzbuzz' describe "FizzBuzz" do describe "one" do subject { 1 } it { should_not be_fizz } it { should_not be_buzz } it { should_not be_fizzbuzz } its(:fizzbuzz) { should == '1' } end describe "three" do subject { 3 } it { should be_fizz } it { should_not be_buzz } it { should_not be_fizzbuzz } its(:fizzbuzz) { should == 'Fizz' } end describe "five" do subject { 5 } it { should_not be_fizz } it { should be_buzz } it { should_not be_fizzbuzz } its(:fizzbuzz) { should == 'Buzz' } end describe "fifteen" do subject { 15 } it { should_not be_fizz } it { should_not be_buzz } it { should be_fizzbuzz } its(:fizzbuzz) { should == 'FizzBuzz' } end end
テスト実行結果
FizzBuzz one should not be fizz should not be buzz should not be fizzbuzz fizzbuzz should == "1" three should be fizz should not be buzz should not be fizzbuzz fizzbuzz should == "Fizz" five should not be fizz should be buzz should not be fizzbuzz fizzbuzz should == "Buzz" fifteen should not be fizz should not be buzz should be fizzbuzz fizzbuzz should == "FizzBuzz" Finished in 0.00265 seconds 16 examples, 0 failures
FizzBuzzの実装
#!/usr/bin/env ruby # -*- coding: utf-8 -*- class Numeric def fizz? not fizzbuzz? and self % 3 == 0 end def buzz? not fizzbuzz? and self % 5 == 0 end def fizzbuzz? self % 3 == 0 and self % 5 == 0 end def fizzbuzz if fizz? 'Fizz' elsif buzz? 'Buzz' elsif fizzbuzz? 'FizzBuzz' else self.to_s end end end if __FILE__ == $0 (1..100).each { |x| puts x.fizzbuzz } end
fizzbuzz.rb を実行すると、「1, 2, Fizz, ... , 98, Fizz, Buzz」が標準出力に表示される。