AWS SDK for Ruby(v2) で簡単なS3操作
仕事でAWS SDK for Ruby (v2) をちょっとだけ使ったのでメモ。 AmazonS3の操作を行った。
環境
Credentialsの設定
~/.aws/credentials
に、IAMのユーザーのアクセスキーID・シークレットアクセスキーを書いておくと、
そちらから自動的に読み込まれる。
[default] aws_access_key_id = <AWS_ACCESS_KEY_ID> aws_secret_access_key = <AWS_SECRET_ACCESS_KEY>
他にもいくつか方法はあって、GitHubのREADME見るとこう書いてある
Default credentials are searched for in the following locations:
環境変数から直接読み込んでもくれるし、
Aws::Credentials.new
でインスタンスを作成してAws.config[:credentials]
にセットするというやり方でも良さそう。
とにかくGitHubとかにキーをPushするなと。
S3上での各種操作
今回はpryから触った。
Railsプロジェクトでsdkをbundle install
して利用するときは、最初のrequire
要らないはず。
S3のリージョンをセットし、S3用クライアントのインスタンスを生成。
require "aws-sdk-core" Aws.config[:region] = 'ap-northeast-1' s3 = Aws::S3::Client.new
s3.methods
実行すると、メソッドがいっぱいある...
バケットの一覧表示
resp = s3.list_buckets resp.buckets #=> [#<struct name="aono-test", creation_date=2015-02-15 09:25:20 UTC>] resp.buckets.map(&:name) #=> ["aono-test"]
バケットの作成・削除
s3.create_bucket(bucket: 'fugafuga') #=> #<struct location="http://fugafuga.s3.amazonaws.com/"> s3.delete_bucket(bucket: 'fugafuga') #=> #<struct>
オブジェクトの一覧表示
例えばバケットの直下に3枚の画像が入っているとする。
resp = s3.list_objects(bucket: 'aono-test') resp.contents.map(&:key) #=> ["foo.jpg", "bar.jpg", "hoge.jpg"]
フォルダーがあって、その下のやつだけ見たいときは、list_objects
メソッドにprefix
オプションを指定する。
s3.list_objects(bucket: 'aono-test', prefix: "folder")
こうすると、folderディレクトリとその直下のファイルだけが一覧される。
また、max_keys
オプションで一度に取得するオブジェクトの数を制限できる。
(デフォルトは1,000に設定されている模様)
レスポンスがページングに対応しているので、 それと組み合わせて適度な数だけ取得してくるのがベターな使い方、だろうか。
resp = s3.list_objects(bucket: 'aono-test', max_keys: 2) resp.last_page? #=> false resp.next_page? #=> true next_resp = resp.next_page
アップロード
file = File.open('/path/to/file') file_name = File.basename('/path/to/file') s3.put_object( bucket: "aono-test", body: file, key: file_name )
ダウンロード
File.open("/path/to/file", "w") do |file| s3.get_object(bucket: 'aono-test', key: "foo.jpg") do |chunk| file.write chunk end end
これで、バケットに置いてあるfoo.jpgをDLして、所定の場所に保存する。
おわり
メモおわり。
上記で挙げた基本的な操作以外にも、バケットポリシーやライフサイクルの更新や削除etc.できるみたいだし、 プログラムからほぼ全操作可能なのだろう。自動化には欠かせないし、今さらながら便利である...
年末年始で読んだ技術書など
社会人3年目の年末年始。去年と一昨年は、iOS版のFinalFantasy(4, 5)やりこんでたら冬休みがほぼ終わってた。今年は何となくゲームに手を付けず、技術書やマンガを読んだりHulu見たりして過ごしていた。
そんなわけで、読んだ技術書について、個人の日記レベルなメモを書いておこうかと思う。
よんだ技術書
評判が良さそうな本を何冊か読んだ。個人的にはどれも当たりの本で学びがあった。
- 『HTTPの教科書』
- 『Everyday Rails - RSpecによるRailsテスト入門』
- 『Webエンジニアが知っておきたいインフラの基本 ~インフラの設計から構成、監視、チューニングまで~』
1. HTTPの教科書
Web開発をする際に知っておくべき「HTTP」の解説を分かりやすくしてくれている本。
自分はRailsからプログラミングを始めた。 Railsだとある程度簡単にWebアプリを作れてしまうこともあり(これがRailsの良い所でもあるのだと思うが)、こういったWebの根幹の仕組みについて理解できていないことが結構多いのでは、という不安がある。(不安ではなくたぶん事実)
この本は、「Webエンジニア」を名乗るならたぶん知っておくべき内容の基礎が平易に書いてあり、さらっと読めた。セキュリティに関してや、SPDYなど新しめのトピックに関しても触れられており非常に良かった。
残念ながらこういった知識を一度で吸収できる脳みそではないので、この本や『Webを支える技術』などを定期的に読み返していくと良さそう。 セキュリティといえば徳丸さんの本ですが、こちらもまだ未読なので読まねば。
動く「成果物」を生み出すことが優先される環境にいると、こういった基礎的な内容がどうしても疎かになってしまう気がする。 けど、こういうのも絶対必要だよなー。(教養の面でも成果物のクオリティの面でも)
2. Everyday Rails - RSpecによるRailsテスト入門
https://leanpub.com/everydayrailsrspec-jp
RSpecの入門本。英語で書かれた原著の和訳。 英語版のアップデートが結構されてるぽいけど、和訳版もちゃんとそれに追随してくれており、RSpec3対応。(翻訳者の方々ありがとうございます)
本の中で利用されているサンプルコードもGitHubに置いてある。 everydayrails/rspec_rails_4
簡単なRailsアプリにRSpecを使ったテストを組み込んでいく内容。 読みつつ写経しつつ8章の終わり(全12章)まで読了。 モデルスペックやコントローラスペックの作成、FactoryGirlによるテストデータ作成、Capybaraを使ったフィーチャースペックの作成などを学べた。 RSpecの思想的なところもなんとなく分かってきて、なるほどなーという感じ。
そもそもちゃんと勉強してみるかーと思ったのは、業務で触っているRails3.2の某レガシーコードを4.0系にアップデートしたいと思ったため。 各種ライブラリのサポートも切られ始めてるし、これはそろそろマズイなと。
どのレイヤーのテストを書くべきか問題とか、カバレッジにどこまでこだわるのか問題とかまあ色々あるんだろうけど、 自分の関わっているアプリケーションはその問題に突き当たるレベルにまで達していないので、とりあえず少しずつ書いていきましょうという感じかなぁ。。 実際のアプリは本の中のアプリほど単純なわけでもなく、簡単なモデルスペックを少し書くだけでもつらみを感じた...
後からテスト書くと設計のクソさに気づくし、先にテスト書くとクソな設計を作りにくくなる、という効果もありそう。
3. Webエンジニアが知っておきたいインフラの基本 ~インフラの設計から構成、監視、チューニングまで~
先月の下旬に出た本。Twitterなどでちょこちょこ感想を見かけたので読んでみた。 「インフラ」に関する内容を広範囲に扱ってくれている。 前半部分はインフラの設計や要件定義などについて広く触れられており、 後半部分は監視や障害対応、パフォーマンスチューニングのポイントなどについて具体的に書いてあった。
周りにインフラをメインでやってるエンジニアの人がいないので、「ああ、インフラエンジニアの方はこうやって仕事しているのかー」という妙な驚きがあったw
「ちゃんとシステムを組む」ための方法が説明されている。 関わっているサービスのインフラ周り(主にAWS)をイメージしつつ読んでいたが、自分の知らない分野・理解の薄い分野の話を補完できて良かった。
DevOpsというワードが一時期流行ったが、これから双方の垣根がどんどん無くなっていくのは間違いない。 そういう意味で、こっち側の世界ももう少し知らんとまずいかなーと感じた。
そのほか
以前のWeb+DB PressのRails4の紹介記事だったり、以前購入して積ん読になってた『チーム開発実践入門』をつまみ食いして読んだりしていた。
(蛇足)よんだマンガ
漫画読んだりもしてた。 普通に過ごしてると少年ジャンプとかヤンジャン系の漫画ばっかりになるので、ちょっと違うのを新規に読んでみた。
みんな良い漫画はどうやって見つけてるんですか。
おわり
年末年始に読んだ本の簡単な紹介おわり。
冬休み、なんとなく2週間くらいあるイメージだったけど、それより全然短かった。。 インプット重視だったのもあり、あまりコードは書けず。 まあこうやって読書の時間をいっぱいとれる期間もなかなか無いので、良かったかなと思う。
僕の技術レベルはまだまだかなり低い。 自分が組織の成長の足を引っ張らないよう、今年も粛々と腕を磨かなくては...
と、ちょっとだけ意識の高いこと書いて終わります。
Goで簡単な行列計算
Golangでの簡単な行列計算。
ライブラリ
gonum/matrix を利用してみる。
実装
Goのバージョンは1.4。
行列の作成
行列は、mat64.NewDense
という関数を利用して宣言する。
下記の例では、[1 2 3]
という行列をx
に代入している。
// matrix.go package main import ( "fmt" "github.com/gonum/matrix/mat64" ) func main() { elem := []float64{1, 2, 3} x := mat64.NewDense(3, 1, elem) fmt.Println(x) }
実行。
$ go run matrix.go &{{3 1 1 [1 2 3]}}
NewDense
の実装を覗いてみる。
// matrix/mat64/dense.go func NewDense(r, c int, mat []float64) *Dense { if mat != nil && r*c != len(mat) { panic(ErrShape) } if mat == nil { mat = make([]float64, r*c) } return &Dense{RawMatrix{ Rows: r, Cols: c, Stride: c, Data: mat, }} }
列数, 行数, 要素を表す配列の3つを引数として渡し、 返り値のインスタンスには、列数, 行数, Stride(=行数), 行列が含まれる。
行列の要素へのアクセス
At
を使い、位置(列と行)を引数に指定。
elem := []float64{1, 2, 3} x := mat64.NewDense(3, 1, elem) fmt.Println(x.At(1, 0)) // => 2
行列の和や積
行列の和や積などの算出。
和はAdd
, 差はSub
という関数を利用。
返り値はなく、メソッドのレシーバに演算結果が代入される。
func main() { elem_x := []float64{1, 2, 3} elem_y := []float64{4, 5, 6} elem_a := make([]float64, 3) x := mat64.NewDense(3, 1, elem_x) y := mat64.NewDense(3, 1, elem_y) a := mat64.NewDense(3, 1, elem_a) a.Add(x, y) fmt.Println(a) // => &{{3 1 1 [5 7 9]}} a.Sub(x, y) fmt.Println(a) // => &{{3 1 1 [-3 -3 -3]}} }
続いて行列積。Mul
を利用。
下記のようにinit
関数を指定しておかないと、panic: mat64: no blas engine registered: call Register()
というpanicが発生した。
package main import ( "fmt" "github.com/gonum/blas/goblas" "github.com/gonum/matrix/mat64" ) func main() { elem_x := []float64{1, 2, 3, 4} elem_y := []float64{5, 6, 7, 8} elem_a := make([]float64, 4) x := mat64.NewDense(2, 2, elem_x) y := mat64.NewDense(2, 2, elem_y) a := mat64.NewDense(2, 2, elem_a) a.Mul(x, y) fmt.Println(a) // => &{{2 2 2 [19 22 43 50]}} } func init() { mat64.Register(goblas.Blas{}) }
2x2行列の積がちゃんと出てる。
逆行列
逆行列の算出には、Inverse
を利用。
func main() { elem_x := []float64{2, 5, 1, 3} x := mat64.NewDense(2, 2, elem_x) inv_x, _ := mat64.Inverse(x) fmt.Println(inv_x) // => &{{2 2 2 [3 -5 -1 2]}} }
[[2, 5], [1, 3]]
の逆行列は、[[3, -5], [-1, 2]]
。OK。
https://github.com/gonum/matrix/blob/master/mat64/matrix.go に、Inverse
の実装が載ってる。
番外: Rubyでやる
上記でやったようなことをRubyでやるとどうなるか。 Rubyのバージョンは、2.2.0preview2。
Matrix
クラスを利用。
# matrix.rb require 'matrix' a = Matrix[[1, 2], [3, 4]] b = Matrix[[5, 6], [7, 8]] sum = a + b # => Matrix[[6, 8], [10, 12]] mul = a * b # => Matrix[[19, 22], [43, 50]] c = Matrix[[2, 5], [1, 3]] c.inverse # => Matrix[[(3/1), (-5/1)], [(-1/1), (2/1)]]
...やっぱり簡単に書ける。
おわり
Goの簡単な行列演算などを試してみた。 はじめから分かってたけど、扱いやすさではRubyやPythonにやはり軍配が上がりますかね。。 あと、行列を転置する方法がよくわからなかったw
数値計算系のライブラリもう少し充実してくれたりすると嬉しいですね。
Golangを触り始めた② 文法・型
前回に引き続き、Web+DB vol.82のGo特集が分かりやすいのでそれ見ながら。
ぜんぶ網羅して書いてないけど、メモ。Goのバージョンは1.3.3です。
変数
var message string = "Hello world"
変数宣言は、var
で始まり、変数名、型の順。ちょっと違和感。
関数内部で変数宣言と初期化を行う場合は、以下のように:=
を利用しても書ける。こっちの書き方を使うことが多そう。変数の型は、代入する値から推論される。
/* import文は省略 */ func main() { message := "Hello world" fmt.Println(message) }
定数は、var
じゃなくてconst
で宣言。
if
条件部分に()
は付けないが、処理部分は{}
が必要。
func main() { a, b := 10, 1 if a > b { fmt.Println("aの方がデカイ") } }
for
func main() { for i := 0; i < 10; i++ { fmt.Println(i) } }
while
やloop
は無いので、for
で代替。
n := 0 for n < 10 { fmt.Println(n) n++ }
ループから抜けるのはbreak
、次の繰り返しに行くのはcontinue
。
switch
func main() { for n := 0; n < 31; n++ { switch { case n%15 == 0: fmt.Println("FizzBuzz") case n%5 == 0: fmt.Println("Buzz") case n%3 == 0: fmt.Println("Fizz") default: fmt.Println(n) } } }
関数
関数はfunc
で宣言。引数がある場合は、変数と合わせて型も指定。戻り値がある場合は、引数の次に書き、型を指定。
func sum(i, j int) int { return i + j } func main() { n := sum(1, 2) fmt.Println(n) // 3 }
関数は複数の値を戻り値として返すことができる。その際、戻り値を格納する変数を必要数分用意してあげないといけない。用意する変数の数が合わないとコンパイルエラー。無視したい戻り値があるときは、_
を利用して無視することを明示する。
func swap(i, j int) (int, int) { return j, i } func main() { x, y := 20, 30 x, y = swap(x, y) fmt.Println(x, y) // 30, 20 x, _ = swap(x, y) fmt.Println(x) // 20 }
関数でエラーを返す
上記のような複数の値を戻り値として返す特徴を利用し、Golangでは内部で発生したエラーを戻り値で表現する。
また、エラーはerrorsパッケージを使って自作できる。
// main.go package main import ( "errors" "fmt" "log" ) func div(i, j int) (int, error) { if j == 0 { return 0, errors.New("divided by zero") } return i / j, nil } func main() { n, err := div(10, 0) if err != nil { log.Fatal(err) } fmt.Println(n) }
上記を実行すると、こんな感じになる。
$ go run main.go 2014/10/26 15:29:31 divided by zero exit status 1
配列
Golangの配列は固定長。 例えば、長さが3で要素の型がstringだったら、こう書く。
arr := [3]string{"a", "b", "c"} // または arr := [...]string{"a", "b", "c"}
配列型は長さも情報として持っているため、長さが異なると別の型と認識される。
func show(arr [4]string) { fmt.Println(arr) } func main() { var arr1 [4]string var arr2 [5]string fn(arr1) fn(arr2) // コンパイルエラー! }
スライス
こっちが慣れ親しんでいる可変長配列。
var s []string
このように長さの情報を宣言に含めないで書くと、スライスになる。
append
スライス(の末尾)に値を追加をするにはappend
を利用。
var s []int s = append(s, 1, 2) fmt.Println(s) // [1 2]
range
配列やスライスに格納された値を先頭から順に処理するときは、range
を利用。
arr = [3]string{"a", "b", "c"} for i, s := range arr { fmt.Println(i, s) // iが添字、sが値 }
上記のような使い方はRubyのeach_with_index
的な感じかな。
値の切り出し
s := []int{1, 2, 3, 4, 5} fmt.Println(s[2:4]) // [3 4] fmt.Println(s[:3]) // [1 2 3] fmt.Println(s[3:]) // [4 5]
引数として使うとき
以下のように書くと、任意の長さのスライスを引数として使える
func sum(nums ...int) (result int) { for _, n := range nums { result += n } return } func main() { fmt.Println(sum(1, 2, 3, 4)) // 10 }
マップ
Rubyでいうところのハッシュ的なやつ。以下のように宣言。
var month map[int]string = map[int]string{} month[1] = "January" month[2] = "February"
宣言と初期化を同時にやるならこう書く。
month := map[int]string { 1: "January", 2: "February", } fmt.Println(month) // map[1:January 2:February]
値へのアクセス
Rubyなどと方法は同じ。
jan := month[1] fmt.Println(jan) // January
ただし、2つめの戻り値も実はある。 (このケースは変数を1つしか受け取らなくてもコンパイルエラー出ないのね)
2つめの戻り値は、指定したキーがこのマップに存在しているかを表すbool値。
_, ok = month[1] if ok { // データが存在したとき、何らかの処理 }
マップからデータ消すときはdelete
を使う。
delete(month, 1) fmt.Println(month) // map[2:February]
スライスと同様、range
で繰り返し処理を実現できるが、取り出される順番は保証されないらしい。。
ポインタ
ポインタ型の変数には、型の前に*
を付ける。アドレスは変数の前に&
をつけると分かる。Cと似ているらしい(触ったことない...)
func callByValue(i int) { i = 20 } func callByRef(i *int) { *i = 20 } func main() { i := 10 callByValue(i) fmt.Println(i) // 10 callByRef(&i) fmt.Println(i) // 20 }
defer
例えば、ファイル操作で利用するfile.Close()
(ファイルを閉じる作業)は必ず実行されなければならない。だが、関数の途中でパニックが起こったりすると、この文まで到達できない可能性がある。
そういったケースに使うのがdefer
。これを処理の前に書いておくと、main()を抜ける前にかならず実行されるようになる。
defer file.Close()
パニック
スライスの範囲外にアクセスしようとした時など、エラーを戻り値として返せない時、パニックという方法でエラーが発生する。
パニックは、recover()
で取得し、その中でエラー処理をする。recover()
をdefer
の中に書く。
// main.go func main() { defer func() { err := recover() if err != nil { log.Fatal(err) } }() a := []int{1, 2, 3} fmt.Println(a[10]) }
$ go run main.go 2014/10/26 16:33:39 runtime error: index out of range exit status 1
panicは自分でも発生させられる。
// main.go a := []int{1, 2, 3} for i := 0; i < 10; i++ { if i > len(a) { panic(errors.New("index out of range")) } fmt.Println(a[i]) }
$ go run main.go 1 2 3 panic: runtime error: index out of range goroutine 16 [running]: runtime.panic(0xb7e60, 0x142b5c) /usr/local/Cellar/go/1.3.3/libexec/src/pkg/runtime/panic.c:279 +0xf5 (以下略)
Goで書かれたソースをほとんど読んだことないので、使いどころのイメージがまだあまりできない。。エラーは、できるだけ戻り値として表現し、無理なときにpanicにするって感じだろうか。
構造体
Rubyのクラス的なやつ。type
を用いて宣言。
構造体のあとにフィールドを記述する。フィールドは、名前が大文字から始まればパブリック、小文字からならパッケージ内のみから見える。
type Task struct { ID int Detail string done bool } func main() { task := Task{ ID: 1, Detail: "Write a code", done: true, } fmt.Println(task.ID) // 1 fmt.Println(task.Detail) // "Write a code" }
taskには構造体が代入され、各フィールドにはドットでアクセスできる。
ポインタ型として扱うことも可能。
new()
new()
で構造体の初期化を行える。フィールドはすべてゼロ値となる。
func main() { var task *Task = new(Task) fmt.Println(task.done) // false }
コンストラクタ
Newではじまる関数を定義し、その中で構造体を生成することで、コンストラクタの役割を果たす。
func NewTask(id int, detail string) *Task { task := &Task{ ID: id, Detail: detail, done: false, } return task } func main() { task := NewTask(1, "Write a code") fmt.Printf("%+v", task) // &{ID:1 Detail:Write a code done:false}% }
メソッド
型にはメソッド定義ができる。 以下は、レシーバをポインタとして受け取るケース。
func (task *Task) Finish() { task.done = true } func main() { task := NewTask(1, "Write a code") task.Finish() fmt.Printf("%+v", task) // &{ID:1 Detail:Write a code done:true}% }
ポインタを使っているので、レシーバのdoneの値がtrueに変わっている。
インターフェース
インターフェースは、型がどのようなメソッドを実装すべきかを規定する。
type Finisher interface { Finish() }
こんなかんじで、関数名にerを付けて書くのがお作法らしい。
型の埋め込み
Goには、継承という概念が無いみたい。代わりに、「他の型を埋め込む」という形で構造体やインターフェースを拡張できる。
以下、構造体の埋め込み例。
// main.go package main import "fmt" type User struct { FirstName string LastName string } func (u *User) FullName() string { fullname := fmt.Sprintf("%s %s", u.FirstName, u.LastName) return fullname } func NewUser(firstName, lastName string) *User { return &User{ FirstName: firstName, LastName: lastName, } } type Task struct { ID int Detail string done bool *User } func NewTask(id int, detail, firstName, lastName string) *Task { task := &Task{ ID: id, Detail: detail, done: false, User: NewUser(firstName, lastName), } return task } func main() { task := NewTask(1, "Write a code", "Yusuke", "Aono") fmt.Println(task.FirstName) fmt.Println(task.FullName()) fmt.Println(task.User) }
$ go run hello.go Yusuke Yusuke Aono &{Yusuke Aono}
Taskの構造宣言時に、Userという型を埋め込む。これでTaskからUserのフィールドやメソッドにアクセスできるようになる。
おわり
お腹がすいたので、おわり。 Ruby書いてる時と異なり、留意しなきゃいけない点が多そうではある。ま、性質の違う言語なんだから当たり前か。。
エラー処理のあたりは難しそう(書くのめんどくさそう)な印象だが、もう少し書いてみないと判断できないですね。
Golangを触り始めた
タイトルの通り、ほんとに触り始めたという程度だけど。。 速いと聞くし、Rails以外の選択肢としてGo製のWAFもそのうち触ってみたいな〜と思っている。
インストール
もともとMacでpecoやghqといったコマンドラインツールを利用していたので、homebrewでのGoインストール、GOPATHの設定くらいはしていた。
$ brew install go $ go version go version go1.3.3 darwin/amd64 $ echo $GOPATH /Users/Aono
触ってみる
何を教材にしようかなと思っていたのだが、WEB+DB PRESS Vol.82 のGo特集が良さげだったので、それを見ながら書いている。
Hello world
よく分からないまま、とりあえずハローワールド。
外部のパッケージとか呼び出す、本元というかメインのファイルにpackage main
と書くのかな。
/* hello.go */ package main import ( "fmt" ) func main() { fmt.Println("hello world") }
$ go run hello.go hello world
コンパイルしてバイナリファイルにするには、
$ go build hello.go
同じディレクトリにhello
という実行ファイルが生成される。
$ ./hello hello world
結構厳しいコーディング規約
インデントがハードタブじゃないといけない。 あと、文字列をシングルクオーテーションで括ったらエラーが出た。 シングルクオーテーションで括るとルーンリテラルとなり、ダブルクォーテーションの時の文字列リテラルとは別物のようだ。
Golangには、この規約に従ってコードを整形してくれるコマンドが標準で付いている。
$ go fmt hello.go
Goフォーマットすると、ソフトタブ(半角スペース)がハードタブになるなどの変換が行われる。
Atomのプラグイン
毎回上記のコマンドを実行しなくても済むように、各エディタで拡張機能があるっぽい。 Atom Editorにもgo-plusというプラグインがあったので、それを利用。
Goのパッケージも必要みたいなので、go get
しておく。
$ go get code.google.com/p/go.tools/cmd/goimports $ go get github.com/golang/lint/golint
こうしてgo get
したパッケージは、$GOPATH/src
以下にインストールされていく。
実行ファイルは$GOPATH/bin
下に入るようなので、PATHを通しておいた。
これでAtomのパッケージ側にちょろっと設定をすれば、ファイル保存時にフォーマットしてくれたりするようになる。とりあえずのところはこれで大丈夫かな。
godocコマンド
パッケージのドキュメントを見るコマンド。 なんか雑誌の中ではさらっと使っていたのですが、僕のMacだとこのコマンドが最初使えなかった。
別途インストールが必要?みたい。
$ go get code.google.com/p/go.tools/cmd/godoc
これを実行した後も、$GOPATH/bin
下にgodoc
はなかった。
以下の記事を参考に、/usr/local/opt/go/libexec/bin
にもPATH通したら使えるようになった。
これで合ってるのかな...
godoc with homebrew installed Go
ちなみにタイミングを忘れてしまったのだけど、go get
の際、mercurialが入ってないのでコード取ってこれないぞ、と怒られた。homebrewでインストールした。
以下のようなコマンドで、ドキュメントを見れるようになった。
$ godoc fmt
Goのディレクトリのお作法とか
基本的に、
$GOPATH ├── bin ├── pkg └── src
というディレクトリ構造で開発していくようだ。分かりやすい。
今のところは、src
のみにフォーカス。src
下に実際に書いていくコードを格納する。
GitHub上に置いてある(置く予定の)ソースコードは、$GOPATH/src/github.com/<ユーザー名>/<リポジトリ名>
に設置して作業していく。ghq
を利用してソースコードを取得したりしていたのもあり、そんなに混乱はしなかった。
以下、またサンプルコード。
/* $GOPATH/src/github.com/ysk1031/gosample/gosample.go */ package gosample var Message string = "hello world"
/* $GOPATH/src/main/main.go */ package main import ( "fmt" "github.com/ysk1031/gosample" ) func main() { fmt.Println(gosample.Message) }
mainパッケージ側で、自作した外部のパッケージをインポートしている。
インポートの際は、$GOPATH/src
より下のファイル名を指定すれば自動で解釈してくれるようだ。
最後にパッケージのビルド。
さっきは、go build
でその場に実行ファイルを生成したが、今回はgo install
を利用。
$ cd $GOPATH/src/main $ go install
実行すると、$GOPATH/bin
下に実行ファイルmain
が生成される。なるほど!
すでに$GOPATH/bin
にPATHを通してあるので、コマンドラインのどこからでも、main
というコマンドを実行することができるようになった。
$ main hello world
Atomのところでgolintをgo get
でインストールした際、$GOPATH/bin
以下に実行ファイルも生成されていた。go get
は、$GOPATH/src
下にソースを持ってきた後go install
を実行している、という認識で合っているのかなあ。
おわり
今回はいったん終わり。 Web+DBの記事は非常に分かりやすく書かれていて、苦しまずに読み進めていけそう。
会社の方でSwiftも書く必要が出てきそうで(こちらも初心者)、Goにどこまでパワー割けるか分からないのだけれど、引き続き学んでいきたい。