Repository: BurntSushi/toml
Pull request #304 (2021-06-24 06:16:05)

Move the tag/untag code for toml-test-{en,de}coder to internal/tag
This was duplicated in toml_test.go and the ./cmd/toml-test* commands.
Need to modify it to fix the locale datetime tests.

No functional changes, just moves the code.


Patch:
diff --git a/internal/tag/add.go b/internal/tag/add.go
new file mode 100644
index 0000000..76fc2b8
--- /dev/null
+++ b/internal/tag/add.go
@@ -0,0 +1,53 @@
+package tag
+
+import (
+	"fmt"
+	"math"
+	"time"
+)
+
+func Add(tomlData interface{}) interface{} {
+	switch orig := tomlData.(type) {
+	default:
+		panic(fmt.Sprintf("Unknown type: %T", tomlData))
+
+	case map[string]interface{}:
+		typed := make(map[string]interface{}, len(orig))
+		for k, v := range orig {
+			typed[k] = Add(v)
+		}
+		return typed
+	case []map[string]interface{}:
+		typed := make([]map[string]interface{}, len(orig))
+		for i, v := range orig {
+			typed[i] = Add(v).(map[string]interface{})
+		}
+		return typed
+	case []interface{}:
+		typed := make([]interface{}, len(orig))
+		for i, v := range orig {
+			typed[i] = Add(v)
+		}
+		return typed
+	case time.Time:
+		return tag("datetime", orig.Format("2006-01-02T15:04:05.999999999Z07:00"))
+	case bool:
+		return tag("bool", fmt.Sprintf("%v", orig))
+	case int64:
+		return tag("integer", fmt.Sprintf("%d", orig))
+	case float64:
+		if math.IsNaN(orig) {
+			return tag("float", "nan")
+		}
+		return tag("float", fmt.Sprintf("%v", orig))
+	case string:
+		return tag("string", orig)
+	}
+}
+
+func tag(typeName string, data interface{}) map[string]interface{} {
+	return map[string]interface{}{
+		"type":  typeName,
+		"value": data,
+	}
+}
diff --git a/internal/tag/rm.go b/internal/tag/rm.go
new file mode 100644
index 0000000..1a8a91b
--- /dev/null
+++ b/internal/tag/rm.go
@@ -0,0 +1,75 @@
+package tag
+
+import (
+	"log"
+	"strconv"
+	"time"
+)
+
+func Remove(typedJson interface{}) interface{} {
+	switch v := typedJson.(type) {
+	case map[string]interface{}:
+		if len(v) == 2 && in("type", v) && in("value", v) {
+			return untag(v)
+		}
+		m := make(map[string]interface{}, len(v))
+		for k, v2 := range v {
+			m[k] = Remove(v2)
+		}
+		return m
+	case []interface{}:
+		a := make([]interface{}, len(v))
+		for i := range v {
+			a[i] = Remove(v[i])
+		}
+		return a
+	}
+	log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
+	panic("unreachable")
+}
+
+func in(key string, m map[string]interface{}) bool {
+	_, ok := m[key]
+	return ok
+}
+
+func untag(typed map[string]interface{}) interface{} {
+	t := typed["type"].(string)
+	v := typed["value"]
+	switch t {
+	case "string":
+		return v.(string)
+	case "integer":
+		v := v.(string)
+		n, err := strconv.Atoi(v)
+		if err != nil {
+			log.Fatalf("Could not parse '%s' as integer: %s", v, err)
+		}
+		return n
+	case "float":
+		v := v.(string)
+		f, err := strconv.ParseFloat(v, 64)
+		if err != nil {
+			log.Fatalf("Could not parse '%s' as float64: %s", v, err)
+		}
+		return f
+	case "datetime":
+		v := v.(string)
+		t, err := time.Parse("2006-01-02T15:04:05.999999999Z07:00", v)
+		if err != nil {
+			log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
+		}
+		return t
+	case "bool":
+		v := v.(string)
+		switch v {
+		case "true":
+			return true
+		case "false":
+			return false
+		}
+		log.Fatalf("Could not parse '%s' as a boolean.", v)
+	}
+	log.Fatalf("Unrecognized tag type '%s'.", t)
+	panic("unreachable")
+}


Test patch:
diff --git a/cmd/toml-test-decoder/main.go b/cmd/toml-test-decoder/main.go
index e1f5491..b114eac 100644
--- a/cmd/toml-test-decoder/main.go
+++ b/cmd/toml-test-decoder/main.go
@@ -5,14 +5,12 @@ package main
 import (
 	"encoding/json"
 	"flag"
-	"fmt"
 	"log"
-	"math"
 	"os"
 	"path"
-	"time"
 
 	"github.com/BurntSushi/toml"
+	"github.com/BurntSushi/toml/internal/tag"
 )
 
 func init() {
@@ -39,53 +37,7 @@ func main() {
 
 	j := json.NewEncoder(os.Stdout)
 	j.SetIndent("", "  ")
-	if err := j.Encode(addJSONTags(decoded)); err != nil {
+	if err := j.Encode(tag.Add(decoded)); err != nil {
 		log.Fatalf("Error encoding JSON: %s", err)
 	}
 }
-
-func addJSONTags(tomlData interface{}) interface{} {
-	switch orig := tomlData.(type) {
-	default:
-		panic(fmt.Sprintf("Unknown type: %T", tomlData))
-
-	case map[string]interface{}:
-		typed := make(map[string]interface{}, len(orig))
-		for k, v := range orig {
-			typed[k] = addJSONTags(v)
-		}
-		return typed
-	case []map[string]interface{}:
-		typed := make([]map[string]interface{}, len(orig))
-		for i, v := range orig {
-			typed[i] = addJSONTags(v).(map[string]interface{})
-		}
-		return typed
-	case []interface{}:
-		typed := make([]interface{}, len(orig))
-		for i, v := range orig {
-			typed[i] = addJSONTags(v)
-		}
-		return typed
-	case time.Time:
-		return tag("datetime", orig.Format("2006-01-02T15:04:05.999999999Z07:00"))
-	case bool:
-		return tag("bool", fmt.Sprintf("%v", orig))
-	case int64:
-		return tag("integer", fmt.Sprintf("%d", orig))
-	case float64:
-		if math.IsNaN(orig) {
-			return tag("float", "nan")
-		}
-		return tag("float", fmt.Sprintf("%v", orig))
-	case string:
-		return tag("string", orig)
-	}
-}
-
-func tag(typeName string, data interface{}) map[string]interface{} {
-	return map[string]interface{}{
-		"type":  typeName,
-		"value": data,
-	}
-}
diff --git a/cmd/toml-test-encoder/main.go b/cmd/toml-test-encoder/main.go
index 02a2378..2f16d1e 100644
--- a/cmd/toml-test-encoder/main.go
+++ b/cmd/toml-test-encoder/main.go
@@ -8,10 +8,9 @@ import (
 	"log"
 	"os"
 	"path"
-	"strconv"
-	"time"
 
 	"github.com/BurntSushi/toml"
+	"github.com/BurntSushi/toml/internal/tag"
 )
 
 func init() {
@@ -36,75 +35,7 @@ func main() {
 		log.Fatalf("Error decoding JSON: %s", err)
 	}
 
-	if err := toml.NewEncoder(os.Stdout).Encode(removeJSONTags(tmp)); err != nil {
+	if err := toml.NewEncoder(os.Stdout).Encode(tag.Remove(tmp)); err != nil {
 		log.Fatalf("Error encoding TOML: %s", err)
 	}
 }
-
-func removeJSONTags(typedJson interface{}) interface{} {
-	switch v := typedJson.(type) {
-	case map[string]interface{}:
-		if len(v) == 2 && in("type", v) && in("value", v) {
-			return untag(v)
-		}
-		m := make(map[string]interface{}, len(v))
-		for k, v2 := range v {
-			m[k] = removeJSONTags(v2)
-		}
-		return m
-	case []interface{}:
-		a := make([]interface{}, len(v))
-		for i := range v {
-			a[i] = removeJSONTags(v[i])
-		}
-		return a
-	}
-	log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
-	panic("unreachable")
-}
-
-func untag(typed map[string]interface{}) interface{} {
-	t := typed["type"].(string)
-	v := typed["value"]
-	switch t {
-	case "string":
-		return v.(string)
-	case "integer":
-		v := v.(string)
-		n, err := strconv.Atoi(v)
-		if err != nil {
-			log.Fatalf("Could not parse '%s' as integer: %s", v, err)
-		}
-		return n
-	case "float":
-		v := v.(string)
-		f, err := strconv.ParseFloat(v, 64)
-		if err != nil {
-			log.Fatalf("Could not parse '%s' as float64: %s", v, err)
-		}
-		return f
-	case "datetime":
-		v := v.(string)
-		t, err := time.Parse("2006-01-02T15:04:05.999999999Z07:00", v)
-		if err != nil {
-			log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
-		}
-		return t
-	case "bool":
-		v := v.(string)
-		switch v {
-		case "true":
-			return true
-		case "false":
-			return false
-		}
-		log.Fatalf("Could not parse '%s' as a boolean.", v)
-	}
-	log.Fatalf("Unrecognized tag type '%s'.", t)
-	panic("unreachable")
-}
-
-func in(key string, m map[string]interface{}) bool {
-	_, ok := m[key]
-	return ok
-}
diff --git a/toml_test.go b/toml_test.go
index ad7b4e6..9e85f5e 100644
--- a/toml_test.go
+++ b/toml_test.go
@@ -6,16 +6,13 @@ import (
 	"bytes"
 	"encoding/json"
 	"fmt"
-	"log"
-	"math"
 	"path/filepath"
-	"strconv"
 	"strings"
 	"testing"
-	"time"
 
 	"github.com/BurntSushi/toml"
 	tomltest "github.com/BurntSushi/toml-test"
+	"github.com/BurntSushi/toml/internal/tag"
 )
 
 // Test if the error message matches what we want for invalid tests. Every slice
@@ -164,7 +161,7 @@ func (p parser) Encode(input string) (output string, outputIsError bool, retErr
 	}
 
 	buf := new(bytes.Buffer)
-	err = toml.NewEncoder(buf).Encode(p.removeJSONTags(tmp))
+	err = toml.NewEncoder(buf).Encode(tag.Remove(tmp))
 	if err != nil {
 		return err.Error(), true, retErr
 	}
@@ -189,123 +186,9 @@ func (p parser) Decode(input string) (output string, outputIsError bool, retErr
 		return err.Error(), true, retErr
 	}
 
-	j, err := json.MarshalIndent(p.addJSONTags(d), "", "  ")
+	j, err := json.MarshalIndent(tag.Add(d), "", "  ")
 	if err != nil {
 		return "", false, err
 	}
 	return string(j), false, retErr
 }
-
-func (p parser) addJSONTags(tomlData interface{}) interface{} {
-	tag := func(typeName string, data interface{}) map[string]interface{} {
-		return map[string]interface{}{
-			"type":  typeName,
-			"value": data,
-		}
-	}
-
-	switch orig := tomlData.(type) {
-	default:
-		panic(fmt.Sprintf("Unknown type: %T", tomlData))
-
-	case map[string]interface{}:
-		typed := make(map[string]interface{}, len(orig))
-		for k, v := range orig {
-			typed[k] = p.addJSONTags(v)
-		}
-		return typed
-	case []map[string]interface{}:
-		typed := make([]map[string]interface{}, len(orig))
-		for i, v := range orig {
-			typed[i] = p.addJSONTags(v).(map[string]interface{})
-		}
-		return typed
-	case []interface{}:
-		typed := make([]interface{}, len(orig))
-		for i, v := range orig {
-			typed[i] = p.addJSONTags(v)
-		}
-		return typed
-	case time.Time:
-		return tag("datetime", orig.Format("2006-01-02T15:04:05.999999999Z07:00"))
-	case bool:
-		return tag("bool", fmt.Sprintf("%v", orig))
-	case int64:
-		return tag("integer", fmt.Sprintf("%d", orig))
-	case float64:
-		if math.IsNaN(orig) {
-			return tag("float", "nan")
-		}
-		return tag("float", fmt.Sprintf("%v", orig))
-	case string:
-		return tag("string", orig)
-	}
-}
-
-func (p parser) removeJSONTags(typedJson interface{}) interface{} {
-	in := func(key string, m map[string]interface{}) bool {
-		_, ok := m[key]
-		return ok
-	}
-
-	untag := func(typed map[string]interface{}) interface{} {
-		t := typed["type"].(string)
-		v := typed["value"]
-		switch t {
-		case "string":
-			return v.(string)
-		case "integer":
-			v := v.(string)
-			n, err := strconv.Atoi(v)
-			if err != nil {
-				log.Fatalf("Could not parse '%s' as integer: %s", v, err)
-			}
-			return n
-		case "float":
-			v := v.(string)
-			f, err := strconv.ParseFloat(v, 64)
-			if err != nil {
-				log.Fatalf("Could not parse '%s' as float64: %s", v, err)
-			}
-			return f
-		case "datetime":
-			v := v.(string)
-			t, err := time.Parse("2006-01-02T15:04:05.999999999Z07:00", v)
-			if err != nil {
-				log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
-			}
-			return t
-		case "bool":
-			v := v.(string)
-			switch v {
-			case "true":
-				return true
-			case "false":
-				return false
-			}
-			log.Fatalf("Could not parse '%s' as a boolean.", v)
-		}
-		log.Fatalf("Unrecognized tag type '%s'.", t)
-		panic("unreachable")
-	}
-
-	switch v := typedJson.(type) {
-	case map[string]interface{}:
-		if len(v) == 2 && in("type", v) && in("value", v) {
-			return untag(v)
-		}
-		m := make(map[string]interface{}, len(v))
-		for k, v2 := range v {
-			m[k] = p.removeJSONTags(v2)
-		}
-		return m
-	case []interface{}:
-		a := make([]interface{}, len(v))
-		for i := range v {
-			a[i] = p.removeJSONTags(v[i])
-		}
-		return a
-	}
-	log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
-	panic("unreachable")
-}