Skip to content

Kadai2 dobuzora #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions kadai2/dobuzora/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
_testdata
_bin
48 changes: 48 additions & 0 deletions kadai2/dobuzora/README.md
Original file line number Diff line number Diff line change
@@ -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
```

## 回答
9 changes: 9 additions & 0 deletions kadai2/dobuzora/cmd/j2p/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

import (
"github.com/gopherdojo/dojo6/kadai2/dobuzora/internal/cli"
)

func main() {
cli.Do()
}
3 changes: 3 additions & 0 deletions kadai2/dobuzora/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/gopherdojo/dojo6/kadai2/dobuzora

go 1.12
1 change: 1 addition & 0 deletions kadai2/dobuzora/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github.com/gopherdojo/dojo6 v0.0.0-20190710155631-1b40d3406c2f h1:UOg/ZpRwvokKADOjfCukjqQXYHb7HOdVSgZGABZc2BQ=
75 changes: 75 additions & 0 deletions kadai2/dobuzora/internal/cli/cli.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
25 changes: 25 additions & 0 deletions kadai2/dobuzora/internal/cli/cli_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
3 changes: 3 additions & 0 deletions kadai2/dobuzora/internal/cli/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package cli

var GetFileNameWithoutExt = getFileNameWithoutExt
48 changes: 48 additions & 0 deletions kadai2/dobuzora/internal/convert/convert.go
Original file line number Diff line number Diff line change
@@ -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
}