diff --git a/kadai2/dobuzora/.gitignore b/kadai2/dobuzora/.gitignore new file mode 100644 index 0000000..f1093d8 --- /dev/null +++ b/kadai2/dobuzora/.gitignore @@ -0,0 +1,2 @@ +_testdata +_bin diff --git a/kadai2/dobuzora/README.md b/kadai2/dobuzora/README.md new file mode 100644 index 0000000..daee7f6 --- /dev/null +++ b/kadai2/dobuzora/README.md @@ -0,0 +1,48 @@ +# 課題 2 + +## io.Readerとio.Writer +io.Readerとio.Writerについて調べてみよう + +### 標準パッケージではどのように使われているか +私がよく使ったのは`func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)`です。 +第一引数が`io.Writer`となっているため、条件を満たしているものは何でも引数に指定できるため頻繁に使っています。 +`io.Writer`は`Write(p []byte) (n int, err error)`メソッドを持っていればよい。 +このため、`func (f *File) Write(b []byte) (n int, err error)`を持つ`os.File`オブジェクトを指定すればファイルに出力することができる。 + +io.Readerは競技プログラミングでお世話になります。 +読み込み高速化のために`bufio.NewScanner`を頻繁に使いますが、これは`func NewScanner(r io.Reader) *Scanner`です。 +僕は`bufio.NewScanner(os.Stdin)`をよく使いますが、`os.Stdin`は、`Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")`です。 +NewFile関数について調べると`func NewFile(fd uintptr, name string) *File`であり、Fileオブジェクトを返します。 +Fileオブジェクトは`func (f *File) Read(b []byte) (n int, err error)`であるため、`io.Reader`を満たします。 +普段は、`os.Stdin`しか使いませんが、別の入力を読み込む時は`buio.NewScanner`の引数を`io.Reader`を満たしているものに変えれば同様に読み込めます。 + +### io.Readerとio.Writerがあることでどういう利点があるのかを具体的に挙げて考えてみる。 + +上記でも、触れた通り書き込むこと、読み込むことに関して抽象化されていることによりプログラマーがほとんど意識を割く必要がない点に大きな利点があると考えます。 + +## テストを書いてみよう +1回目の宿題のテストを作ってみてください + +### テストのしやすさを考えてリファクタリングしてみる + +### テストのカバレッジを取ってみる + +### テーブル駆動テストを行う + +### テストヘルパーを作ってみる + +## Install + +``` +export GOBIN=`pwd`/_bin +$ go install github.com/gopherdojo/dojo6/kadai2/dobuzora/cmd/j2p +$ _bin/cmd +``` + +## How to use + +``` +./_bin/j2p DIRPATH +``` + +## 回答 diff --git a/kadai2/dobuzora/cmd/j2p/main.go b/kadai2/dobuzora/cmd/j2p/main.go new file mode 100644 index 0000000..dcae40f --- /dev/null +++ b/kadai2/dobuzora/cmd/j2p/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/gopherdojo/dojo6/kadai2/dobuzora/internal/cli" +) + +func main() { + cli.Do() +} diff --git a/kadai2/dobuzora/go.mod b/kadai2/dobuzora/go.mod new file mode 100644 index 0000000..709e5eb --- /dev/null +++ b/kadai2/dobuzora/go.mod @@ -0,0 +1,3 @@ +module github.com/gopherdojo/dojo6/kadai2/dobuzora + +go 1.12 diff --git a/kadai2/dobuzora/go.sum b/kadai2/dobuzora/go.sum new file mode 100644 index 0000000..f0ec61a --- /dev/null +++ b/kadai2/dobuzora/go.sum @@ -0,0 +1 @@ +github.com/gopherdojo/dojo6 v0.0.0-20190710155631-1b40d3406c2f h1:UOg/ZpRwvokKADOjfCukjqQXYHb7HOdVSgZGABZc2BQ= diff --git a/kadai2/dobuzora/internal/cli/cli.go b/kadai2/dobuzora/internal/cli/cli.go new file mode 100644 index 0000000..1a408ba --- /dev/null +++ b/kadai2/dobuzora/internal/cli/cli.go @@ -0,0 +1,75 @@ +/* +cli はコマンドライン引数を処理します。 +*/ +package cli + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + cnv "github.com/gopherdojo/dojo6/kadai2/dobuzora/internal/convert" +) + +// isDir は ディレクトリかどうかを判断します +func isDir(dirName string) bool { + dInfo, err := os.Stat(dirName) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return dInfo.IsDir() +} + +// ファイル名から拡張子を取ったファイル名を返します +func getFileNameWithoutExt(path string) string { + // Fixed with a nice method given by mattn-san + return filepath.Base(path[:len(path)-len(filepath.Ext(path))]) +} + +// imageConvert はディレクトリ名を受け取り、そのディレクトリ内のファイルを変換します +func imageConvert(dirName string) []cnv.ConvertFile { + var fileList []cnv.ConvertFile + + files, err := ioutil.ReadDir(dirName) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + // + for _, file := range files { + path := filepath.Join(dirName, file.Name()) + if isDir(path) { + flist := imageConvert(path) + fileList = append(fileList, flist...) + } else { + ext := filepath.Ext(path) + if ext == ".jpeg" || ext == ".jpg" { + newPath := filepath.Dir(path) + "/" + getFileNameWithoutExt(path) + ".png" + fileList = append(fileList, cnv.ConvertFile{Old: path, New: newPath}) + } + } + } + return fileList +} + +// Do は ファイルを走査し、convertパッケージを用いてJPEをPNG形式に変換します +func Do() { + if len(os.Args) != 2 { + fmt.Fprintln(os.Stderr, "Wrong number of arguments") + os.Exit(1) + } + rootDir := os.Args[1] + if !isDir(rootDir) { + fmt.Fprintln(os.Stderr, "Not a directory") + os.Exit(1) + } + + hoge := imageConvert(rootDir) + for _, v := range hoge { + v.ConvertToPng() + os.Remove(v.Old) + } +} diff --git a/kadai2/dobuzora/internal/cli/cli_test.go b/kadai2/dobuzora/internal/cli/cli_test.go new file mode 100644 index 0000000..34beb4c --- /dev/null +++ b/kadai2/dobuzora/internal/cli/cli_test.go @@ -0,0 +1,25 @@ +package cli_test + +import ( + "testing" + + "github.com/gopherdojo/dojo6/kadai2/dobuzora/internal/cli" +) + +var inputtests = []struct { + in string + expected string +}{ + {"ninja.png", "ninja"}, + {"ninja.jpeg", "ninja"}, + {"n.jpg", "n"}, +} + +func TestGetFileNameWithoutExt(t *testing.T) { + for _, c := range inputtests { + actual := cli.GetFileNameWithoutExt(c.in) + if actual != c.expected { + t.Errorf("getFileNameWithoutExt(%q) == %q, expect %q", c.in, actual, c.expected) + } + } +} diff --git a/kadai2/dobuzora/internal/cli/export_test.go b/kadai2/dobuzora/internal/cli/export_test.go new file mode 100644 index 0000000..5210566 --- /dev/null +++ b/kadai2/dobuzora/internal/cli/export_test.go @@ -0,0 +1,3 @@ +package cli + +var GetFileNameWithoutExt = getFileNameWithoutExt diff --git a/kadai2/dobuzora/internal/convert/convert.go b/kadai2/dobuzora/internal/convert/convert.go new file mode 100644 index 0000000..2ce2dd2 --- /dev/null +++ b/kadai2/dobuzora/internal/convert/convert.go @@ -0,0 +1,48 @@ +/* +JPEG形式の画像をPNG形式に変換するパッケージです。 +*/ +package convert + +import ( + "fmt" + "image" + _ "image/jpeg" + "image/png" + "os" +) + +// 変換する前と後のファイル名を持った構造体です。 +type ConvertFile struct { + Old string // 変換前のファイル名 + New string // 変換後のファイル名 +} + +// ConvertToPng は ファイルのパスを受け取り、JPGならPNG形式に画像を変換します +func (cnv *ConvertFile) ConvertToPng() error { + file, err := os.Open(cnv.Old) + if err != nil { + fmt.Printf("Can not open : %v ", err) + return err + } + defer file.Close() + + img, format, err := image.Decode(file) + if err != nil { + fmt.Printf("Can not Decode : %v ", err) + return err + } + if format != "jpeg" { + return nil + } + + out, err := os.Create(cnv.New) + defer out.Close() + + err = png.Encode(out, img) + if err != nil { + fmt.Println(err) + return err + } + + return nil +}