とりあえずここに落ち着いたGoの即時実行環境 -2014年冬-

goで同一ディレクトリに、複数main.mainをおきたい - コンドルが飛んでいる。

の続編。上記の方法だと色々と不満があったので、適当なtempdirにmain.go置いて$EDITOR立ちあげて編集終えると実行するやつみたいなの作った。

ToQoz/gomain · GitHub

一回で上手くかけるとは限らないのでさっきの続きから書きはじめるのどうしようかなーと思って放置してたんだけど、 実行後にもっかい編集する? って聞いて同意した場合前回のやつから書けるようにした。

demo.gif

近所の医者に行ったら、オイ、デングということでデカめ病院のとこに行かされて検査してきたんだけど特に何もなくて単なる風邪っぽいねってなった。 まあ良かったんだけど、とにかくこの一連の行動に半日ぐらいかかってメチャクチャ疲れた。 後日おたふくワクチンの効果が切れかけだから今度打っとけってのと、サイトメガロウイルスとやらの抗体がないからそのうちそれ感染するかもだから覚えといてってのも言われた。

Internal Server Error

GoでWeb API書いてる時に、システム内部のエラーだったりで詳細をそのままユーザーに返さないもの、例えば(*sql.DB).Execとかでもいいんだけどそういうのをどう扱うか悩んでる。

  • どうせhttp.Handlerはpanic起こったらInternal server error返すようみたいな作りにするだろうし、モデルっぽいところでpanicしてしまう。
  • http.Handler内でエラーを比較してって必要なものだけ詳細を返す、マッチしなかったらログ吐いて、serveInternalServerError(http.ResponseWriter, *http.Response)みたいなのに渡す。

gopwt(PowerAssert for golang)がだいたいできた

http://github.com/ToQoz/gopwt

この時は、「Assert内で副作用のある関数を呼んでいるとそれがコケた場合に、出力の時に再度呼ばれて実際の値と違うものが表示されたり、それ以降のテストに影響がある」みたいな問題があった。それを解決するには適当に関数の呼び出しをキャッシュしてやる必要があって、型のチェックが実行時にしかない言語なら、a() == b() とかってのを memorized(a) == memorized(b) とかってできると思うけど、わりかし大変だった。

  • reflect.ValueOf(f).Call(reflect.ValueOf(arg1), reflect.ValueOf(arg2))[0].Interface() というように変換して変換後のコンパイル時の型のチェックを捨てる
  • そうすると取れる型が決まってる二項演算子が使えない Opなんとか(x, y interface{}) を実装してその中で型をチェックしながら適当に適用していく感じにする
  • 組み込みの関数は、reflect.ValueOf(f).Call で呼べないから普通に呼ぶがそうすると型がハマらないので Op*と一緒のようなものを実装する
  • このへんまではまあ別にいいかなと思ってたんだけど、型の変換(string('r')) で上手くいかないことに気付いてかなり辛くなる。
  • こざかしいことをして*ast.CallExprが普通の関数呼び出しか型の変換かを調べて、後者なら reflect.ValueOf(x).Convert(reflect.ValueOf(new(t)).Elem().Type()) に変換する。

みたいなことをやった。こざかしいことは、code.google.com/p/go.tools/goのgcimporterとtypesのおかげで、楽に出来たんだけど一気にブラックボックス感が高まった感じがした。

そもそもこういうアプローチはGoっぽくないと思う(作る前もgo testに乗せれないかとかなんとか色々悩んだ)けど、TDDでdebugの代わりのテストみたいなのを書いて開発してく時とか、CIでテストコケた時の情報量の多さは結構メリットがあるかなと思う。自分以外が関わるところでこれに依存したテストをコミットするかどうかは今のところ自分自身悩ましい感じはある。まずはv0.0.1を打てるようにやっていく予定

(仕事する気力が無さすぎてエントリ書き出したものの気力がないから雑になった。)

go-unitypackageっての作った

https://github.com/ToQoz/go-unitypackage

.unitypackageに初めて触れてみてて、クリックしてインストールしたのは良いものの、アンインストールできなくて辛すぎて作った。(Pro版は知らん)

あと、

  • ファイルリスト取って全部 .gitignore にぶっこみたい(色々ぶちまけられるので手で設定するのは無理)
  • 使用する .unitypackage のファイルリストにバッティングするものがないかどうか知りたい
  • 依存unitypackageを一括インストール、その後にゴニョゴニョ みたいなことをするスクリプトとか書きたい(「インストール後ここ書き変えて」ってpackageがあったから)

みたいな気持ちがあった。

まあ、とりあえずはおおまかにそのようなことが出来るようになったけど、一般的にこのへんの管理マジでどうやってるのか知りたい。 (unitypackageが吐き出すファイルをignoreせずにimportするごとにcommitしておいてアンインストールはrevertみたいなのはあんまりやりたくない...)

gog 紹介

http://github.com/ToQoz/gog

Logo of gog

静的サイト作るやつみたいな感じ。一般的なものにくらべて、機能が著しく少ない。_layout.html書いといてヘッダーフッター共通化しか機能がない。

ただ各ディレクトリに、GOG_BUILD.goってやつ置けて、それはgo runされる。置いておくと、例えば、build時にどっかからjson取ってきてHTML生成するみたいなことができる。

別のAPI経由でDB更新していって、jenkinsとかに3分に一回HTMLをbuildさせててたりすると、動的サイトみたいになれる。ユーザーからリクエストが来た時に計算はしなくても、動けるのかということを考えたりした。やらないけど。

それはそうと、なんでこういう機能を付けたかというと、http://github.com/ToQoz/toqoz.github.io/tree/master/_src/go/pkg で使いたかったというのもあるけど、

みたいな想いを持っていたことを思い出したことが大きい。

golangでパッケージ作る時の名前をこうやって付けてます。という話

これが最高とかって話ではない。

gemとかにおけるキラキラネームの良さは、被らないことだと思う。しかし、goにおいてはimport pathが別の人が作ったのと被るのを気にしなくて良いから、良さは特にないと思っているけど単に好みで割と付けようとしてしまう。

大体 1 -> 2 -> 3 って感じで考えてるけど、その順番も毎回必ずそうかというとそうでもない。

1. しっくりくるキラキラネーム、ダジャレを思いついた時

それを使う。子供に奇抜な名前付けると、名前だけで識別できる。

  • package: キラキラネーム
  • repository: 同上

2. 1に失敗して、golangに関係した(golangで書いたではない)パッケージを作る時

つまりpackage名にgoを含めたいようなものを作る時(e.g. godoc)

  • package: go prefix を付けて、ひねりのない名前を付ける。
  • repository: 同上

3. それ以外(これはgolangで書いたやつですみたいなの)

go- prefix を付けて、ひねりのない名前を付ける。packageには付けない。あくまでリポジトリの識別性を上げるためにgo-って付けてる。(e.g. go-formspec)。近所に同じ名前の子がいたら名字一緒に呼んであげると良いと思う。

  • package: go- prefix を付けずに、ひねりのない名前を付ける。
  • repository: go- prefix を付けて、ひねりのない名前を付ける。

ただ2分前ぐらいに思ったのは、https://github.com/google/go-github みたいに、リポジトリgo- prefix付けて、そこにprefixなしgithubのディレクトリ掘ってそこに package github とか置くやつのほうが良いかなと思った。

package名とimport pathの最後が一致してるのはやっぱり良いなーと。

testing.afterを自由にしたかった。テストの最後になんかしたかった。golang

追記

1.4から普通にできるようになった。


なにかと最後に掃除したりしたい例があった。

要は、application側が、

package main

import (
    "xxx.com/xxx/xxx/models"
)

func main() {
    db, err := sql.Open()
 
    if err != nil {
        panic(err)
    }

        defer db.Close
    models.InitDbmap(db)

    // main
}

やらなんやら、別にこの例はどうでも良いけど、全体の最後になにかするのが出来るんだから、testing.Mainも自由にやりたい、もしくはtesting.after書きかえたい、なにかを追加したいみたいな希望があった。

go test は Package.TestGoFiles を順にロードして、testing.T.Testsにappendしてってるので、その最後に来るようにすれば良いかなーでもなーとか思ってる時に http://golang.org/src/pkg/net/http/z_last_test.go を発見したので、とりあえずこういう感じてやってこうかと思ってやってみている。

z_last_test.go

package models

import (
    "os/exec"
    "strings"
    "testing"
)

func TestThisFileIsLastTestFile(t *testing.T) {
    cmd := exec.Command("go", "list", "-f", "{{.TestGoFiles}}")
    output, err := cmd.CombinedOutput()

    if err != nil {
        panic(err)
    }

    tests := strings.Split(strings.Trim(string(output), " \n[]"), " ")
    lastTest := tests[len(tests)-1]

    if lastTest != "z_last_test.go" {
        t.Errorf("expected last_test is z_last_test.go, but got %v", lastTest)
    }
}

func TestHogeHoge(t *testing.T) {
    // なんか
}

golang初め

とうことで https://github.com/ToQoz/api というのを作った。

json api書く用に、ちょっと便利にしてくれるやつ。需要があるかはわからないけど、そういうの書いてる時に毎回こういう層準備するのが面倒で書いた。sinatraっぽいRouterのinterfaceに依存してるけど、特定のrouterに依存してなくて、そういうのが作りたかった。

そういうapi便利pkgのためにrouterに依存しちゃうと、あれもこれもみたいな感じになって、個人的なgolang感と離れてしまうのでそういう風にした。golangで書く時だと特にframeworkとかじゃなくて、薄いpkg組み合わせて書きたくなる。

  • sinatraっぽいRouterのinterface
type Router interface {
    Get(string, http.Handler)
    Head(string, http.Handler)
    Post(string, http.Handler)
    Put(string, http.Handler)
    Delete(string, http.Handler)
    http.Handler
}

keyremap4macbookで特定のアプリに対してだけキーマップを設定したい時は、組込みで入ってるxmlを参考にすると良い

特定のアプリに対してキーマップを設定するとか独自で定義するとかって時は, private.xmlに書けば良いんだけど、

例えば、macだと基本C-eで行末にいけるけど、xってアプリがC-eを上書きしてるから、それ使ってる時だけkeyremap4macbook側でC-eを行末移動に変えたいとかって時に、簡単に書けることもあれば、どう書けば良いかよくわからなかったりすることもある。

上記のようにキーバインド自体は組込みで入ってるのと一緒だったり、似ていたりする場合はそれを見るのが良いと思う。

/Applications/KeyRemap4MacBook.app/Contents/Resources/include/checkbox/emacs_mode.xml さっきの例だとこれを見れば良い。

考えてみれば当然だけど、無意識にgoogle.comにアクセスした後我に帰って気付いた。

length: {maximum: 10} みたいなvalidatorを作る(is_a ActiveModel::EachValidator)

# Example
#     validates :email, email: true

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    fuzzy_valid_email_regexp = //
    record.errors.add(attribute, :invalid_email) unless fuzzy_valid_email_regexp =~ value
  end
end

みたいなのは作ったことあったけど、任意の値を渡したくなるvalidatorを書くことがなかったので知らなかった。

UTF-8の文字列を扱ってるシステムなんだけど、深淵な理由からSJISエンコードした時のbytesizeでvalidationしないといけないみたいな要件があり、調べた。特に特別にやらないといけないことはなかった。

# Example
#     validates :email, sjis_bytesize: {maximum: 100}

class SjisBytesizeValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    sjis_bytesize = ほげほげ value
    if sjis_bytesize > options[:maximum]
      record.errors.add(attribute, :too_long, count: [:maximum])
    end
  end
end

みたいに optionsを参照すれば良い。渡した値を事前に加工したりチェックしたければ initialize でごにょごにょした後にsuper呼んどけば良い。

c.f.

heroku create -bをhkで

せっかくgolang webappなんだからheroku commandじゃなくhkでデプロイしたい。

と思ったけど、hk create -b なくて、herokuあんまり触ったことなく知らなくて、一瞬どうせheroku commandいるんだ...的なテンションになってたけど、

$ hk create
$ hk set BUILDPACK_URL=https://github.com/kr/heroku-buildpack-go.git

すれば良い。

他は大体 http://mmcgrana.github.io/2012/09/getting-started-with-go-on-heroku.html 参考にすれば良いと思う。

c.f. https://github.com/heroku/heroku/blob/69cb44a2945abdc3eecef3c99ed3f91ef1e2d715/lib/heroku/command/apps.rb#L268

それとは関係なく、v20131205ぐらいのバージョン使ってたら、hk create後のherokuからのjsonがunmarshalできないのかエラー出るのでupdateすると良い。

$GOROOT/miscにはvim/emacs pluginだけじゃなく、便利なものが色々ある

例えば

$ cat $(go env GOROOT)/misc/git/pre-commit
#!/bin/sh
# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# git gofmt pre-commit hook
#
# To use, store as .git/hooks/pre-commit inside your repository and make sure
# it has execute permissions.
#
# This script does not handle file names that contain spaces.

gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
[ -z "$gofiles" ] && exit 0

unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0

# Some files are not gofmt'd. Print message and fail.

echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
        echo >&2 "  gofmt -w $PWD/$fn"
done

exit 1

これを知らずに適当に自分で作ったりしてたけど、こっちを使うようにした。

  • misc/chrome/gophertool とかもちょっと便利で、これにshortcut登録しておくとpkgのドキュメントに行ったりが楽になる。
  • misc/goplay はめちゃくちゃ便利で、gopalygroundじゃなく、ローカルだ試したいのって時に良い。powで、goplay.devでアクセスできるようにしてる。

どっかのドキュメント見てvim pluginはruntime path通しただけで、他になにがあるか見てなかったけど、ふと思いたって見てみると得した。

FontAwesomeKitはそれ自体に組み込まれてないアイコンフォントを使う場合にも役立つ

例えば、 https://github.com/erikflowers/weather-icons を使いたいって時の例。

  • weather-icons.cssweathericons-regular-webfont.ttf とかをリポジトリに入れておく。
  • コードジェネレータを準備(CodeGenerator.rb, gen.rb)
  • FAKWeatherIcons.fakgen.[h|m]を生成(ruby gen.rb)
$ tree WeatherIcons
WeatherIcons
├── FAKWeatherIcons.fakgen.h
├── FAKWeatherIcons.fakgen.m
├── code_generator.rb
├── gen.rb
├── weather-icons.css
└── weathericons-regular-webfont.ttf
  • weathericons-regular-webfont.ttfをリソースに追加
  • FAKIconを継承したTQWeatherIconsを作る
  • TQWeatherIconsFAKWeatherIcons.fakgen.[h|m] をコピペして、singleton生成のためのクラスメソッド書く。

※ コードジェネレータを準備のとこで、提供されてるCSSに合わせたgen.rbを適当に書く

require './CodeGenerator.rb' # https://github.com/PrideChung/FontAwesomeKit/blob/master/CodeGenerators/CodeGenerator.rb

names = []
codes = []

_lines = File.read("./weather-icons.css").lines

lines = []
_lines.each_with_index do |l, index|
  case l
  when /^\.wi-.+{/
    lines << l + _lines[index + 1] + _lines[index + 2]
  end
end

lines.each do |line|
  name = ''
  line.gsub(/(?<=wi-).*(?=:before)/i) { |match| name = match }
  nameParts = name.split('-')
  nameParts = nameParts.each_with_index.map do |p, i|
    if i < 1
      p
    else
      p = p.capitalize
    end
  end
  name = nameParts.join
  names.push name

  code = ''
  line.gsub(/".*"/) { |match| code = match[2..(match.length-2)] }
  codes.push "\\u#{code}"
end

generator = CodeGenerator.new('WeatherIcons', names, codes)
generator.generate

こういう風に元々FontAwesomeKitに入ってないフォントでも、UIImage化したりとかFAKIconが提供している便利機能を使えて良い。