Skip to content

Kadai2-hisamura #15

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 1 commit 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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module dojo6
27 changes: 27 additions & 0 deletions kadai2/hisamura/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

### 標準パッケージでどのように使われているか

fmt.Fprintでは以下のように記述されている。
```
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
n, err = w.Write(p.buf)
p.free()
return
}
```
同じファイル内のFprint内での呼び出しは以下。

```
Fprintf(os.Stdout, format, a...)
```

io.writerのインターフェースはwriteをメソッドに持っている型なら引数に設定できるので、os.Stdoutを引数に指定し、呼び出している。

### io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる

- コードが簡潔にできるために使用することができる。
- interfaceがないと、それぞれの型を引数に指定し、複数の関数を作らなくてはいけない。
- それがinterfaceを設定できることで、interfaceの関数は使用できることが約束される。
- io.Readerの型を満たしているということはReadメソッドが使用できることが約束されており、引数にio.Readerを指定することで関数内でその引数の型の違いを気にすることなく、Readメソッドを使うことができ、シンプルにコードを記述することができる。
125 changes: 125 additions & 0 deletions kadai2/hisamura/convert/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Package convert is image conversion processing
//
// 画像変換処理。
// 変換前と変換後の拡張子を指定し、画像変換を行います。
// ディレクトリを選択し、再帰的にディレクトリ探索を行い変換します。
// 変換前のファイルを削除したい場合は、remove(-r)フラグを指定します。
package convert

import (
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"io/ioutil"
"os"
"path/filepath"
"strings"
)

// FlagOps is flag option
type FlagOps struct {
Dir string
Src string
Dest string
Remove bool
}

// FileDetails have Extionsion and FileName info
type FileDetails struct {
Extension string
FileName string
}

// Convert is image conversion processing
func Convert(flagOps FlagOps) (string, error) {

files := dirwalk(flagOps.Dir)
var convertedName string

for _, file := range files {
fileDetails := FileDetails{
filepath.Ext(file),
filepath.Clean(file),
}

if strings.HasSuffix(fileDetails.Extension, flagOps.Src) {

decodeImg, err := decodeImage(fileDetails)
if err != nil {
return "", err
}

if flagOps.Remove {
defer os.Remove(fileDetails.FileName)
}

fileNameRemoveExt := strings.Replace(fileDetails.FileName, flagOps.Src, "", 1)
dstFile, err := os.Create(fmt.Sprintf(fileNameRemoveExt + flagOps.Dest))
if err != nil {
return "", err
}
convertedName = dstFile.Name()
defer dstFile.Close()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deferで指定した関数呼び出しは関数終了時に実行されるのでforの中で呼び出さない。
関数に分けることで避けることができる。


err = encodeImage(decodeImg, flagOps, dstFile)
if err != nil {
return "", err
}
}
}
return convertedName, nil

}

func decodeImage(fileDetails FileDetails) (image.Image, error) {
srcFile, err := os.Open(fileDetails.FileName)

defer srcFile.Close()

if err != nil {
return nil, err
}

decodeImg, _, err := image.Decode(srcFile)
return decodeImg, err
}

func encodeImage(decodeImg image.Image, flagOps FlagOps, dstFile *os.File) error {
switch flagOps.Dest {
case "jpeg", "jpg":
err := jpeg.Encode(dstFile, decodeImg, nil)
return err

case "gif":
err := gif.Encode(dstFile, decodeImg, nil)
return err

case "png":
err := png.Encode(dstFile, decodeImg)
return err

default:
return fmt.Errorf("Error: invalid extension")
}
}

//指定したディレクトリ配下のファイルを取得
func dirwalk(dir string) []string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filepath.Walkを使わない理由は?

files, err := ioutil.ReadDir(dir)
if err != nil {
panic(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

panicは使わない。
プロダクトを開発している際に使うことは殆どない。

}

var paths []string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

for _, file := range files {
if file.IsDir() {
paths = append(paths, dirwalk(filepath.Join(dir, file.Name()))...)
continue
}
paths = append(paths, filepath.Join(dir, file.Name()))
}

return paths
}
70 changes: 70 additions & 0 deletions kadai2/hisamura/convert/convert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package convert
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

パッケージを分ける(convert_testにする)


import (
"testing"
)

type testImage struct {
name string
src string
dest string
expected string
}

func TestSuccess(t *testing.T) {

cases := []testImage{
testImage{"jpgToGif", "jpg", "gif", "../testdata/test.gif"},
testImage{"jpgToGif", "jpg", "gif", "../testdata/test.gif"},
testImage{"jpgToPng", "jpg", "png", "../testdata/test.png"},
testImage{"gifToJpg", "gif", "jpg", "../testdata/test.jpg"},
testImage{"gifToPng", "gif", "png", "../testdata/test.png"},
testImage{"pngToGif", "png", "gif", "../testdata/test.gif"},
testImage{"pngToJpg", "gif", "png", "../testdata/test.png"},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
testSuccessConvert(t, c)
})
}
}

func testSuccessConvert(t *testing.T, c testImage) {
t.Helper()
myflag := FlagOps{"../testdata", c.src, c.dest, false}
convertedNmae, err := Convert(myflag)

if convertedNmae != c.expected {
t.Fatal("differnt name")
}
if err != nil {
t.Fatal(err)
}
}

func TestFail(t *testing.T) {
cases := []testImage{
testImage{"jpgToGif", "jpg", "img", "../testdata/test.img"},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
testFailConvert(t, c)
})
}

}

func testFailConvert(t *testing.T, c testImage) {
t.Helper()
myflag := FlagOps{"../testdata", c.src, c.dest, false}
convertedNmae, err := Convert(myflag)

if convertedNmae != "" {
t.Fatal("not empty name")
}
if err == nil {
t.Fatal("err nil")
}
}
1 change: 1 addition & 0 deletions kadai2/hisamura/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module dojo6/kadai2/hisamura
42 changes: 42 additions & 0 deletions kadai2/hisamura/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"dojo6/kadai2/hisamura/convert"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

標準パッケージ以外は空行を分けることが多い。
その際、サードパティパッケージが下になる。

"flag"
"fmt"
)

func main() {

var (
dir = flag.String("dir", "./", "変換したいディレクトリ配下")
src = flag.String("s", "png", "変換前の拡張子")
dest = flag.String("d", "jpg", "変換後の拡張子")
remove = flag.Bool("r", false, "変換前の拡張子ファイルを削除するかのflag")
)

flag.Parse()

flagOps := convert.FlagOps{Dir: *dir, Src: *src, Dest: *dest, Remove: *remove}

result := validation(flagOps)
if result {
fmt.Print("invalid extension")
return
}

convertFile, err := convert.Convert(flagOps)

if err != nil {
fmt.Println(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

エラーはos.Stderrに出す。

}

fmt.Printf("convert to %v", convertFile)
}

func validation(flagOps convert.FlagOps) bool {
if flagOps.Dest != "png" && flagOps.Dest != "jpg" && flagOps.Dest != "jpeg" && flagOps.Dest != "gif" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ifの条件をそのままreturnしても良さそう

return true
}
return false
}
Binary file added kadai2/hisamura/testdata/test.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Binary file added kadai2/hisamura/testdata/test.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added kadai2/hisamura/testdata/test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.