diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a2dcce..69b0443 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v2 with: - version: v1.31 + version: v1.37 env: VERBOSE: "true" diff --git a/Makefile b/Makefile index 332a4f8..3207404 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +GOMODNAME := $(shell grep 'module' go.mod | sed -e 's/^module //') SOURCES := $(shell find . -name "*.go" -or -name "go.mod" -or -name "go.sum" \ -or -name "Makefile") @@ -18,7 +19,7 @@ SHELL ?= /bin/bash SHELL := env \ GO111MODULE=on \ GOBIN=$(CURDIR)/$(TOOLDIR) \ - CGO_ENABLED=1 \ + CGO_ENABLED=0 \ PATH='$(CURDIR)/$(BINDIR):$(CURDIR)/$(TOOLDIR):$(PATH)' \ $(SHELL) @@ -34,7 +35,6 @@ SHELL := env \ # TOOLS += $(TOOLDIR)/gobin -gobin: $(TOOLDIR)/gobin $(TOOLDIR)/gobin: GO111MODULE=off go get -u github.com/myitcv/gobin @@ -42,16 +42,13 @@ $(TOOLDIR)/gobin: define tool # 1: binary-name, 2: go-import-path TOOLS += $(TOOLDIR)/$(1) -.PHONY: $(1) -$(1): $(TOOLDIR)/$(1) - $(TOOLDIR)/$(1): $(TOOLDIR)/gobin Makefile gobin $(V) "$(2)" endef $(eval $(call tool,godoc,golang.org/x/tools/cmd/godoc)) $(eval $(call tool,gofumports,mvdan.cc/gofumpt/gofumports)) -$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.31)) +$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.37)) .PHONY: tools tools: $(TOOLS) @@ -75,25 +72,18 @@ clean-golden: .PHONY: test test: - go test $(V) -count=1 -race $(TESTARGS) $(TEST) - -.PHONY: test-update-golden -test-update-golden: - @$(MAKE) test UPDATE_GOLDEN=1 - -.PHONY: regen-golden -regen-golden: clean-golden test-update-golden + CGO_ENABLED=1 go test $(V) -count=1 -race $(TESTARGS) $(TEST) .PHONY: test-deps test-deps: go test all .PHONY: lint -lint: golangci-lint +lint: $(TOOLDIR)/golangci-lint GOGC=off golangci-lint $(V) run .PHONY: format -format: gofumports +format: $(TOOLDIR)/gofumports gofumports -w . .SILENT: bench @@ -161,7 +151,8 @@ check-tidy: # Serve docs .PHONY: docs -docs: godoc +docs: $(TOOLDIR)/godoc + $(info serving docs on http://127.0.0.1:6060/pkg/$(GOMODNAME)/) @godoc -http=127.0.0.1:6060 # diff --git a/go.mod b/go.mod index 414655d..4b6c16d 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/jimeh/undent go 1.15 -require github.com/stretchr/testify v1.6.1 +require ( + github.com/rhysd/go-fakeio v1.0.0 + github.com/stretchr/testify v1.6.1 +) diff --git a/go.sum b/go.sum index afe7890..b0d47db 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rhysd/go-fakeio v1.0.0 h1:+TjiKCOs32dONY7DaoVz/VPOdvRkPfBkEyUDIpM8FQY= +github.com/rhysd/go-fakeio v1.0.0/go.mod h1:joYxF906trVwp2JLrE4jlN7A0z6wrz8O6o1UjarbFzE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/undent.go b/undent.go index 5d76c37..7d040d0 100644 --- a/undent.go +++ b/undent.go @@ -4,6 +4,7 @@ package undent import ( "fmt" + "io" "regexp" ) @@ -60,3 +61,38 @@ func String(s string) string { func Stringf(format string, a ...interface{}) string { return fmt.Sprintf(String(format), a...) } + +// Print will undent any strings arguments before passing them to fmt.Print. +func Print(a ...interface{}) (n int, err error) { + return fmt.Print(undentInterfaces(a)...) +} + +// Printf will undent the given format string before passing it and all +// arguments to fmt.Printf. +func Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(String(format), a...) +} + +// Fprint will undent any string arguments before passing them to fmt.Fprint. +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, undentInterfaces(a)...) +} + +// Fprintf will undent the given format string before passing it and all +// arguments to fmt.Fprintf. +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, String(format), a...) +} + +func undentInterfaces(a []interface{}) []interface{} { + var r []interface{} + + for _, v := range a { + if s, ok := v.(string); ok { + v = String(s) + } + r = append(r, v) + } + + return r +} diff --git a/undent_example_test.go b/undent_example_test.go index ee3f4f6..5249d3f 100644 --- a/undent_example_test.go +++ b/undent_example_test.go @@ -1,6 +1,7 @@ package undent_test import ( + "bytes" "fmt" "github.com/jimeh/undent" @@ -60,3 +61,57 @@ func ExampleStringf() { // "hello": "world" // } } + +func ExamplePrint() { + undent.Print(` + { + "hello": "world" + }`, + ) + // Output: + // { + // "hello": "world" + // } +} + +func ExamplePrintf() { + undent.Printf(` + { + "hello": "%s" + }`, + "world", + ) + // Output: + // { + // "hello": "world" + // } +} + +func ExampleFprint() { + var buf bytes.Buffer + undent.Fprint(&buf, ` + { + "hello": "world" + }`, + ) + fmt.Println(buf.String()) + // Output: + // { + // "hello": "world" + // } +} + +func ExampleFprintf() { + var buf bytes.Buffer + undent.Fprintf(&buf, ` + { + "hello": "%s" + }`, + "world", + ) + fmt.Println(buf.String()) + // Output: + // { + // "hello": "world" + // } +} diff --git a/undent_test.go b/undent_test.go index 7ba537a..7d1b10b 100644 --- a/undent_test.go +++ b/undent_test.go @@ -1,9 +1,12 @@ package undent import ( + "bytes" "testing" + "github.com/rhysd/go-fakeio" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var stringTestCases = []struct { @@ -443,6 +446,62 @@ func TestStringf(t *testing.T) { } } +func TestPrint(t *testing.T) { + for _, tt := range stringTestCases { + t.Run(tt.name, func(t *testing.T) { + got, err := fakeio.Stdout().Do(func() { + Print(tt.s, 5, tt.s) + }) + require.NoError(t, err) + + assert.IsType(t, "", got) + assert.Equal(t, tt.want+"5"+tt.want, got) + }) + } +} + +func TestPrintf(t *testing.T) { + for _, tt := range stringfTestCases { + t.Run(tt.name, func(t *testing.T) { + got, err := fakeio.Stdout().Do(func() { + Printf(tt.s, tt.a...) + }) + require.NoError(t, err) + + assert.IsType(t, "", got) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestFprint(t *testing.T) { + for _, tt := range stringTestCases { + t.Run(tt.name, func(t *testing.T) { + var buf bytes.Buffer + + Fprint(&buf, tt.s, 5, tt.s) + got := buf.String() + + assert.IsType(t, "", got) + assert.Equal(t, tt.want+"5"+tt.want, got) + }) + } +} + +func TestFprintf(t *testing.T) { + for _, tt := range stringfTestCases { + t.Run(tt.name, func(t *testing.T) { + var buf bytes.Buffer + + Fprintf(&buf, tt.s, tt.a...) + got := buf.String() + + assert.IsType(t, "", got) + assert.Equal(t, tt.want, got) + }) + } +} + func BenchmarkBytes(b *testing.B) { for _, tt := range stringTestCases { b.Run(tt.name, func(b *testing.B) {