$GOROOT/src/race.bashとかのインデント

もハードタブだったの、どっちでも良いんだけど面白かった。Cとかも。

変な意味ではない。単純にgoでの標準はそうだから、goでのみハードタブにするし、go fmtで保証されるからどっち派とか関係なくハードタブで良いんだよ。みたいな感じだと思ってたけど、(少なくともgolangリポジトリでは)goに限らずインデントにハードタブ使ってんだなーと。

まあでも普段ハードタブ使ってない人が言語作ってハードタブを標準のフォーマットにしようとか思わなさそうだし、普通と言えば普通だと思った。

plistのシンタックスチェック

plistをロードできなくて、なにかしらダメなんだろうけど、launchctl: no plist was returned for: /Users/toqoz/Library/LaunchAgents/<PLIST_FILE> とだけ言ってくる。

とりあえずシンタックスエラーでもチェックしようと思って調べたら、plutil -lint ~/Library/LaunchAgents/<PLIST_FILE> というので出来た。

c.f. http://apple.stackexchange.com/a/46380

homebrewで入れたgoの$GOROOT

$BREW_HOME/Cellar/go/1.1.1 でよかったんだけど、https://github.com/mxcl/homebrew/commit/743bf42e2e0a5f0fc217b114e88c24f84c1fed97 以降は $BREW_HOME/Cellar/go/1.1.2/libexec としてやらないといけなくなった。

なんだけど、このtweetをたまたま見て、そもそもGOROOTはビルド時と違う場所に置いたりしてない限り別に設定しなくて良いらしい。ということを知った。

で少し調べた。

$ echo $GOROOT

$ go env
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH=""
GORACE=""
GOROOT="/Users/toqoz/brew/Cellar/go/1.1.2/libexec"
GOTOOLDIR="/Users/toqoz/brew/Cellar/go/1.1.2/libexec/pkg/tool/darwin_amd64"
CC="gcc"
GOGCCFLAGS="-g -O2 -fPIC -m64 -pthread -fno-common"
CGO_ENABLED="1"

pkg/runtime/zversion.godefaultGoroot って定数で持ってた。build時に http://golang.org/src/cmd/dist/buildruntime.c#L18 でそれを作ってる。

cf. http://golang.org/doc/install#tarball_non_standard

iOS remindersとかcalendarみたいな日付選択

iOSやるやる言いつつ、本読んでちょっと試して放置して2年ぐらい経つ気がするけど、先月ちょっと作ろうと思うものがあって始めた。

remindersとかcalendarみたいな日付選択を作りたくなって試してみた。

  • _datePickerCell, _dateFieldCellってクラス作ってnilと紐付ける。
  • _dateFieldCellを押した時に、_datePickerCell_cellsになかったら追加し、あれば削除
  • _datePickerCell編集開始時に_dateFieldCellの色を編集中の色にする、終れば確定の色にする。
  • _datePickerCellの値が変った時に_dateFieldCellの値を変える。

みたいなことをやった。(実際のコードから流れを簡易化するためにsectionを1個にしたり適当に手を加えた)

- (void)viewDidLoad
{
    // initialize _dateFieldCell, _datePickerCell
    // ...
    _cells = @{
        // ...
        _dateFieldCell
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self cellForIndexPath:indexPath] == _datePickerCell) {
        return _datePickerCell.picker.frame.size.height;
    }

    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [_cells count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [_cells indexPath.row];
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *selectedCell = [self cellForIndexPath:indexPath];

    if (selectedCell == _dateFieldCell) {
        [self toggleDatePickerCell];
    } else {
        // ...
    }

    [self closeSoftKeyboard];
}

- (void)toggleDatePickerCell
{
    if ([_cells containsObject:_datePickerCell]) {
        [self _hideDatePickerCell];
    } else {
        [self _showDatePickerCell];
    }
}

- (void)_showDatePickerCell
{
    int targetIndex = [NSIndexPath indexPathForRow:[_cells indexOfObject:_dateFieldCell] + 1;

    [self.tableView beginUpdates];
    [_cells insertObject:_datePickerCell atIndex:targetIndex];
    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:targetIndex inSection:0]]
                          withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];

    // 日付を編集中の色にしたり
    [_dateFieldCell didStartEditing];
}

- (void)_hideDatePickerCell
{
    int targetIndex = [NSIndexPath indexPathForRow:[_cells indexOfObject:_dateFieldCell] + 1;

    [self.tableView beginUpdates];
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:targetIndex inSection:0]]
                          withRowAnimation:UITableViewRowAnimationFade];
    [_cells removeObjectAtIndex:targetIndex];
    [self.tableView endUpdates];

    // 日付を確定の色にしたり
    [_dateFieldCell didEndEditing];
}

// DatePickerCell delegate(DatePickerCellが変更された時)
- (void)dateDidChange:(UIDatePicker *)datePicker
{
    _dateFieldCell.date = datePicker.date;
}

- (void)closeSoftKeyboard
{
    [self.tableView endEditing:YES];
}

bundle install --path=PATH で入れたgemを認識してほしい、Intellij

.bundle/config を見てくれないっぽくて困ってて、File -> Project Structure -> Modules にそのプロジェクトのLOAD_PATH設定する所を発見したけど

...
 "/Users/toqoz/dev/[a project]/vendor/gems/ruby/2.0.0/gems/uglifier-x.x.x/lib",
 "/Users/toqoz/dev/[a project]/vendor/gems/ruby/2.0.0/gems/turnip-x.x.x/lib",
 "/Users/toqoz/dev/[a project]/vendor/gems/ruby/2.0.0/gems/susy-x.x.x/lib",
....

みたいなのを一々追加できる人はいないのでどうしたものかと思っていたら、File -> Project Structure -> SDKs -> [a ruby version]Classpathってのがあって、

/Users/toqoz/dev/[a project]/vendor/gems/ruby/2.0.0/gems

を追加してやれば良かった。これだとプロジェクトごとにSDK作る必要ありそうだけど、とりあえずはこれでいいかなという感じ。

goで特定のエラーに対して別々にハンドリングする

  • エラーメッセージの比較
  • errorの比較
  • errorの型の比較

errorの比較がシンプルで好きだけど、それだけだと、動的にエラーメッセージ変えたい時とかに困る。

Demo: http://play.golang.org/p/F9qAcLoMhP

shell起動時にkey登録

# ~/.zshrc
test $(ssh-add -l | grep "/Users/toqoz/.ssh/id_rsa" | wc -l) = 0 && ssh-add

みたいな感じ。もっと登録すべきkeyがある場合は、追加していくと良いと思う。

ssh-add -l は一個も登録されてない時、The agent has no identities. っていうのを標準エラーではなく標準出力に出すから、 test $(ssh-add -l | wc -l) = 0 とかってやってもうまくいかない。

最後のwindowをquitする時に確認してくれるようにする(vim)

NeoBundle 'tyru/vim-altercmd'

command Q :call s:gentle_quitman()

function! s:gentle_quitman()
  let window_counter = 0
  windo let window_counter = window_counter + 1

  if window_counter == 1
    let a = input("Really quit last window? [n]|y")
    if a == "y"
      q
    endif
  else
    q
  endif
endfunction

call altercmd#load()
AlterCommand q Q
AlterCommand Q q

参考

pluginにした

https://github.com/ToQoz/gentle_quitman.vim

*_test.go の依存packageをinstallする。

*_test.go でのみimportされているpackageは、単純に go get ./... だと、入らないので go list -f '{{.TestImports}}' ./... | sed 's/\[//g' | sed 's/\]//g' | xargs go get する必要がある。

go help list 見ると色々なものを取得できることが分ってよかった。


追記: go get -t [pkg] で良いっぽい

github.com/go-sql-driver/mysql での datetimeとtime.Timeのマッピング

db, err := sql.Open("mysql", "user:passward@/dbname?parseTime=true")

みたいな感じで、parseTime=trueを設定してやる必要がある。https://github.com/go-sql-driver/mysql/blob/v1.1/packets.go#L649

ただ、これだとdatetime->time.Timeにparseする際に標準時として行なわれるので、parseTime=true&loc=SOME_LOCATIONと、locを設定する必要がある。

古いバージョンだと、loc=Asia/Tokyoとかをparseできないのでloc=Japanとかって指定すると良いと思う。https://github.com/go-sql-driver/mysql/commit/7503ab8073eb37c533ac4a211e9a9f469e5cd267 でescapeしたのを渡すようになってるので、これ以降のバージョンだと locl=Asia%2FTokyo って渡してやれば良い。


go get -u の挙動が良くわかってなくて、今まっさらな環境で go get github.com/go-sql-driver すると、v1.1が入るのに、 v1.0.2 が 入った環境で go get -u github.com/go-sql-driver してもupdateされなくて困ってる。

go get -u でupdateされなかった理由

  • go get はgo1 tag or branchがあれば、それを取ってくる
  • github.com/go-sql-driver/mysql では、go1 tag を持ってる
  • go get -u github.com/go-sql-driver/mysql
  • go get -u(git fetch)でtagのupdateがfetchされない
  • go1 tagに変化がない
  • updateされない

goで同一ディレクトリに、複数main.mainをおきたい

続編を書いた。

とりあえずここに落ち着いたGoの即時実行環境 -2014年冬- - コンドルが飛んでいる。


以下古いやつ

その場で書いて実行できて置いておける、みたいな場所が欲しい。go playgroundは便利だけど、それだけで十分かというと、そうではないので、適当なディレクリにスクリプト雑多においておいて go run a.go とか、go run b.go って出来るようにしておきたい。

それ自体はできるけど、Vim上とかで警告[1]されるのがつらい。

そういう時には、// +build ignore とか書いておいてビルド対象じゃなくすると良いっぽい。ignoreじゃなくても、コード書いてる環境がターゲットにならないような指定ならなんでもいいけど、ignoreって書いておくと通じやすいし良さそう。c.f. http://golang.org/pkg/go/build/#hdr-Build_Constraints

a.go

// +build ignore

package main

import (
    "fmt"
)

func main() {
    fmt.Println("b")
}

b.go

// +build ignore

package main

import (
    "fmt"
)

func main() {
    fmt.Println("b")
}

追記

importしたけど、使ってないpackageがある時とか未定義な変数使ったりしてる時の警告も出なくなるので、どっちが不便かわからない感じはする。

追記2

微妙な感じだけど、こんな感じで対処した。あと、:silent make <args> | cwindow 時に描画が変になるのをどうにかしたい。

augroup GoFile
  autocmd!
  " ....
  au BufWritePre *.go :call GoMakeSetting()
augroup END


function! GoMakeSetting()
  setl makeprg=go\ build
  augroup GoMakeSettingGroup
    au!
  augroup END

  if exists(":Make") != 2
    command -nargs=* Make silent make <args> | cwindow | redraw!
  endif

  if match(getline(1), "\/\/ *\+build *ignore") != -1
    setl makeprg=go\ build\ %

    augroup GoMakeSettingGroup
      au BufWritePost <buffer> :Make
      au WinEnter * if winnr('$') == 1 && getbufvar(winbufnr(winnr()), "&buftype") == "quickfix"|q|endif
    augroup END
  endif
endfunction
  • [1] main redeclared in this block previous declaration at みたいなやつ