Skip to content

Commit 07e5e9f

Browse files
committed
better use of reflection
1 parent 5fff8e4 commit 07e5e9f

6 files changed

Lines changed: 147 additions & 170 deletions

File tree

cmd/gss.js/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func Convert(input_string string, input_format string, output_format string, opt
5858
}
5959
}
6060

61-
output_string, err := gss.Convert(input_string, input_format, input_header, input_comment, output_format)
61+
output_string, err := gss.Convert(input_string, input_format, input_header, input_comment, output_format, false)
6262
if err != nil {
6363
console.Log(err.Error())
6464
return ""

cmd/gss/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ func main() {
3838
var output_format string
3939

4040
var version bool
41+
var verbose bool
4142
var help bool
4243

4344
flag.StringVar(&input_format, "i", "", "The input format: "+strings.Join(GO_GSS_FORMATS, ", "))
4445
flag.StringVar(&input_header_text, "h", "", "The input header if the stdin input has no header.")
4546
flag.StringVar(&input_comment, "c", "", "The input comment character, e.g., #. Commented lines are not sent to output.")
4647
flag.StringVar(&output_format, "o", "", "The output format: "+strings.Join(GO_GSS_FORMATS, ", "))
47-
flag.BoolVar(&version, "version", false, "Prints version to stdout.")
48+
flag.BoolVar(&version, "version", false, "Prints version to stdout")
49+
flag.BoolVar(&verbose, "verbose", false, "Print debug info to stdout")
4850
flag.BoolVar(&help, "help", false, "Print help.")
4951

5052
flag.Parse()
@@ -93,7 +95,7 @@ func main() {
9395
input_header = strings.Split(input_header_text, ",")
9496
}
9597

96-
output_string, err := gss.Convert(string(input_bytes), input_format, input_header, input_comment, output_format)
98+
output_string, err := gss.Convert(string(input_bytes), input_format, input_header, input_comment, output_format, verbose)
9799
if err != nil {
98100
fmt.Println(errors.Wrap(err, "Error converting"))
99101
os.Exit(1)

gss/Convert.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,41 @@
88
package gss
99

1010
import (
11+
"fmt"
1112
"github.com/pkg/errors"
1213
)
1314

14-
// Convert converts an input_string from the input_format to the output_format and returns an error, if any.
15-
func Convert(input_string string, input_format string, input_header []string, input_comment string, output_format string) (string, error) {
15+
// Convert converts an input_string from the input_format to the output_format.
16+
// Returns the output string and error, if any.
17+
func Convert(input_string string, input_format string, input_header []string, input_comment string, output_format string, verbose bool) (string, error) {
1618

17-
object, err := NewObject(input_string, input_format)
19+
input_type, err := GetType(input_string, input_format)
1820
if err != nil {
1921
return "", errors.Wrap(err, "error creating new object for format "+input_format)
2022
}
2123

24+
if verbose {
25+
fmt.Println("Input Format: " + input_format)
26+
fmt.Println("Output Format: " + output_format)
27+
fmt.Println("Input Type: " + fmt.Sprint(input_type))
28+
}
29+
2230
if input_format == "bson" || input_format == "json" || input_format == "hcl" || input_format == "hcl2" || input_format == "properties" || input_format == "toml" || input_format == "yaml" {
2331
if output_format == "bson" || output_format == "json" || input_format == "hcl" || input_format == "hcl2" || output_format == "properties" || output_format == "toml" || output_format == "yaml" {
24-
err := Deserialize(input_string, input_format, input_header, input_comment, &object)
32+
object, err := Deserialize(input_string, input_format, input_header, input_comment, input_type, verbose)
2533
if err != nil {
2634
return "", errors.Wrap(err, "Error deserializing input")
2735
}
36+
if verbose {
37+
fmt.Println("Object:", object)
38+
}
2839
output_string, err := Serialize(object, output_format)
2940
if err != nil {
3041
return "", errors.Wrap(err, "Error serializing output")
3142
}
3243
return output_string, nil
3344
} else if output_format == "jsonl" {
34-
object := []map[string]interface{}{}
35-
err := Deserialize(input_string, input_format, input_header, input_comment, &object)
45+
object, err := Deserialize(input_string, input_format, input_header, input_comment, input_type, verbose)
3646
if err != nil {
3747
return "", errors.Wrap(err, "Error deserializing input")
3848
}
@@ -50,8 +60,7 @@ func Convert(input_string string, input_format string, input_header []string, in
5060
}
5161
} else if input_format == "jsonl" || input_format == "csv" || input_format == "tsv" {
5262
if output_format == "bson" || output_format == "json" || output_format == "hcl" || output_format == "hcl2" || output_format == "toml" || output_format == "yaml" || output_format == "jsonl" || output_format == "csv" || output_format == "tsv" {
53-
object := []map[string]interface{}{}
54-
err := Deserialize(input_string, input_format, input_header, input_comment, &object)
63+
object, err := Deserialize(input_string, input_format, input_header, input_comment, input_type, verbose)
5564
if err != nil {
5665
return "", errors.Wrap(err, "Error deserializing input")
5766
}

gss/Deserialize.go

Lines changed: 96 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -36,83 +36,46 @@ func unescapePropertyText(in string) string {
3636
}
3737

3838
// Deserialize reads in an object from a string given format
39-
func Deserialize(input string, format string, input_header []string, input_comment string, output interface{}) error {
39+
func Deserialize(input string, format string, input_header []string, input_comment string, output_type reflect.Type, verbose bool) (interface{}, error) {
4040

4141
if format == "csv" || format == "tsv" {
42-
switch output_slice := output.(type) {
43-
case *[]map[string]string:
44-
reader := csv.NewReader(strings.NewReader(input))
45-
if format == "tsv" {
46-
reader.Comma = '\t'
47-
}
48-
if len(input_comment) > 1 {
49-
return errors.New("go's encoding/csv package only supports single character comment characters")
50-
} else if len(input_comment) == 1 {
51-
reader.Comment = []rune(input_comment)[0]
52-
}
53-
if len(input_header) == 0 {
54-
h, err := reader.Read()
55-
if err != nil {
56-
if err != io.EOF {
57-
return errors.Wrap(err, "Error reading header from input with format csv")
58-
}
59-
}
60-
input_header = h
61-
}
62-
for {
63-
inRow, err := reader.Read()
64-
if err != nil {
65-
if err == io.EOF {
66-
break
67-
} else {
68-
return errors.Wrap(err, "Error reading row from input with format csv")
69-
}
42+
output := reflect.MakeSlice(output_type, 0, 0)
43+
reader := csv.NewReader(strings.NewReader(input))
44+
if format == "tsv" {
45+
reader.Comma = '\t'
46+
}
47+
if len(input_comment) > 1 {
48+
return nil, errors.New("go's encoding/csv package only supports single character comment characters")
49+
} else if len(input_comment) == 1 {
50+
reader.Comment = []rune(input_comment)[0]
51+
}
52+
if len(input_header) == 0 {
53+
h, err := reader.Read()
54+
if err != nil {
55+
if err != io.EOF {
56+
return nil, errors.Wrap(err, "Error reading header from input with format csv")
7057
}
71-
*output_slice = append(*output_slice, RowToMapOfStrings(input_header, inRow))
72-
}
73-
case *[]map[string]interface{}:
74-
reader := csv.NewReader(strings.NewReader(input))
75-
if format == "tsv" {
76-
reader.Comma = '\t'
7758
}
78-
if len(input_comment) > 1 {
79-
return errors.New("go's encoding/csv package only supports single character comment characters")
80-
} else if len(input_comment) == 1 {
81-
reader.Comment = []rune(input_comment)[0]
82-
}
83-
if len(input_header) == 0 {
84-
h, err := reader.Read()
85-
if err != nil {
86-
if err != io.EOF {
87-
return errors.Wrap(err, "Error reading header from input with format csv")
88-
}
59+
input_header = h
60+
}
61+
for {
62+
inRow, err := reader.Read()
63+
if err != nil {
64+
if err == io.EOF {
65+
break
66+
} else {
67+
return nil, errors.Wrap(err, "Error reading row from input with format csv")
8968
}
90-
input_header = h
9169
}
92-
for {
93-
inRow, err := reader.Read()
94-
if err != nil {
95-
if err == io.EOF {
96-
break
97-
} else {
98-
return errors.Wrap(err, "Error reading row from input with format csv")
99-
}
100-
}
101-
*output_slice = append(*output_slice, RowToMapOfInterfaces(input_header, inRow))
70+
m := reflect.MakeMap(reflect.TypeOf(output.Elem()))
71+
for i, h := range input_header {
72+
m.SetMapIndex(reflect.ValueOf(strings.ToLower(h)), reflect.ValueOf(inRow[i]))
10273
}
103-
default:
104-
return errors.New("Cannot deserialize to type " + fmt.Sprint(reflect.ValueOf(output)))
74+
output = reflect.Append(output, m)
10575
}
76+
return output.Interface(), nil
10677
} else if format == "properties" {
107-
m := reflect.ValueOf(output)
108-
if m.Kind() == reflect.Ptr {
109-
if m.Elem().Kind() != reflect.Map {
110-
return errors.New("Output is not of kind map.")
111-
}
112-
m = m.Elem()
113-
} else if m.Kind() != reflect.Map {
114-
return errors.New("Output is not of kind map.")
115-
}
78+
m := reflect.MakeMap(output_type)
11679
if len(input_comment) == 0 {
11780
input_comment = "#"
11881
}
@@ -136,104 +99,94 @@ func Deserialize(input string, format string, input_header []string, input_comme
13699
}
137100
}
138101
if len(propertyName) == 0 {
139-
return errors.New("error deserializing properties for property " + property)
102+
return nil, errors.New("error deserializing properties for property " + property)
140103
}
141104
m.SetMapIndex(reflect.ValueOf(unescapePropertyText(strings.TrimSpace(propertyName))), reflect.ValueOf(unescapePropertyText(strings.TrimSpace(propertyValue))))
142105
property = ""
143106
}
144107
}
145108
}
109+
return m.Interface(), nil
146110
} else if format == "bson" {
147-
return bson.Unmarshal([]byte(input), output)
111+
if output_type.Kind() == reflect.Map {
112+
ptr := reflect.New(output_type)
113+
ptr.Elem().Set(reflect.MakeMap(output_type))
114+
err := bson.Unmarshal([]byte(input), ptr.Interface())
115+
return ptr.Elem().Interface(), err
116+
} else {
117+
return nil, errors.New("Invalid output type for json " + fmt.Sprint(output_type))
118+
}
148119
} else if format == "json" {
149-
return json.Unmarshal([]byte(input), output)
120+
if output_type.Kind() == reflect.Map {
121+
ptr := reflect.New(output_type)
122+
ptr.Elem().Set(reflect.MakeMap(output_type))
123+
err := json.Unmarshal([]byte(input), ptr.Interface())
124+
return ptr.Elem().Interface(), err
125+
} else if output_type.Kind() == reflect.Slice {
126+
ptr := reflect.New(output_type)
127+
ptr.Elem().Set(reflect.MakeSlice(output_type, 0, 0))
128+
err := json.Unmarshal([]byte(input), ptr.Interface())
129+
return ptr.Elem().Interface(), err
130+
} else {
131+
return nil, errors.New("Invalid output type for json " + fmt.Sprint(output_type))
132+
}
150133
} else if format == "jsonl" {
151-
152-
//s.Interface()(type)
153-
// reflect.TypeOf(s).Elem()
154-
155-
/*s := reflect.ValueOf(output)
156-
if s.Kind() == reflect.Ptr {
157-
fmt.Println("s.Interface():", s.Interface())
158-
s = reflect.Indirect(s).Elem()
159-
if s.Kind() != reflect.Slice {
160-
return errors.New("Output is not of kind slice.")
161-
}
162-
} else if s.Kind() != reflect.Slice {
163-
return errors.New("Output is not of kind slice.")
164-
}*/
165-
166-
//fmt.Println("reflect.TypeOf(output)", reflect.TypeOf(output))
167-
168-
switch output_slice := output.(type) {
169-
case *[]map[string]string:
170-
//output_slice := s.Interface().(*[]map[string]string)
171-
scanner := bufio.NewScanner(strings.NewReader(input))
172-
scanner.Split(bufio.ScanLines)
173-
for scanner.Scan() {
174-
line := strings.TrimSpace(scanner.Text())
175-
if len(input_comment) == 0 || !strings.HasPrefix(line, input_comment) {
176-
obj := map[string]string{}
177-
err := json.Unmarshal([]byte(line), &obj)
178-
if err != nil {
179-
return errors.Wrap(err, "Error reading object from JSON line")
180-
}
181-
*output_slice = append(*output_slice, obj)
182-
}
183-
}
184-
case *[]map[string]interface{}:
185-
//output_slice := s.Interface().(*[]map[string]interface{})
186-
scanner := bufio.NewScanner(strings.NewReader(input))
187-
scanner.Split(bufio.ScanLines)
188-
for scanner.Scan() {
189-
line := strings.TrimSpace(scanner.Text())
190-
if len(input_comment) == 0 || !strings.HasPrefix(line, input_comment) {
191-
obj := map[string]interface{}{}
192-
err := json.Unmarshal([]byte(line), &obj)
193-
if err != nil {
194-
return errors.Wrap(err, "Error reading object from JSON line")
195-
}
196-
*output_slice = append(*output_slice, obj)
197-
}
198-
}
199-
case []map[string]interface{}:
200-
//output_slice := s.Interface().([]map[string]interface{})
201-
scanner := bufio.NewScanner(strings.NewReader(input))
202-
scanner.Split(bufio.ScanLines)
203-
for scanner.Scan() {
204-
line := strings.TrimSpace(scanner.Text())
205-
if len(input_comment) == 0 || !strings.HasPrefix(line, input_comment) {
206-
obj := map[string]interface{}{}
207-
err := json.Unmarshal([]byte(line), &obj)
208-
if err != nil {
209-
return errors.Wrap(err, "Error reading object from JSON line")
210-
}
211-
output_slice = append(output_slice, obj)
134+
output := reflect.MakeSlice(output_type, 0, 0)
135+
scanner := bufio.NewScanner(strings.NewReader(input))
136+
scanner.Split(bufio.ScanLines)
137+
for scanner.Scan() {
138+
line := strings.TrimSpace(scanner.Text())
139+
if len(input_comment) == 0 || !strings.HasPrefix(line, input_comment) {
140+
obj := reflect.MakeMap(output_type.Elem())
141+
err := json.Unmarshal([]byte(line), obj.Interface())
142+
if err != nil {
143+
return nil, errors.Wrap(err, "Error reading object from JSON line")
212144
}
145+
output = reflect.Append(output, obj)
213146
}
214-
default:
215-
return errors.New("Cannot deserialize to type " + fmt.Sprint(reflect.TypeOf(output).String()))
216147
}
148+
return output, nil
217149
} else if format == "hcl" {
150+
ptr := reflect.New(output_type)
151+
ptr.Elem().Set(reflect.MakeMap(output_type))
218152
obj, err := hcl.Parse(input)
219153
if err != nil {
220-
return errors.Wrap(err, "Error parsing hcl")
154+
return nil, errors.Wrap(err, "Error parsing hcl")
221155
}
222-
if err := hcl.DecodeObject(output, obj); err != nil {
223-
return errors.Wrap(err, "Error decoding hcl")
156+
if err := hcl.DecodeObject(ptr.Interface(), obj); err != nil {
157+
return nil, errors.Wrap(err, "Error decoding hcl")
224158
}
159+
return ptr.Elem().Interface(), nil
225160
} else if format == "hcl2" {
226161
file, diags := hclsyntax.ParseConfig([]byte(input), "<stdin>", hcl2.Pos{Byte: 0, Line: 1, Column: 1})
227162
if diags.HasErrors() {
228-
return errors.Wrap(errors.New(diags.Error()), "Error parsing hcl2")
163+
return nil, errors.Wrap(errors.New(diags.Error()), "Error parsing hcl2")
229164
}
230-
output = &file.Body
165+
return &file.Body, nil
231166
} else if format == "toml" {
232-
_, err := toml.Decode(input, output)
233-
return err
167+
if output_type.Kind() == reflect.Map {
168+
ptr := reflect.New(output_type)
169+
ptr.Elem().Set(reflect.MakeMap(output_type))
170+
_, err := toml.Decode(input, ptr.Interface())
171+
return ptr.Elem().Interface(), err
172+
} else {
173+
return nil, errors.New("Invalid output type for toml " + fmt.Sprint(output_type))
174+
}
234175
} else if format == "yaml" {
235-
return yaml.Unmarshal([]byte(input), output)
176+
if output_type.Kind() == reflect.Map {
177+
ptr := reflect.New(output_type)
178+
ptr.Elem().Set(reflect.MakeMap(output_type))
179+
err := yaml.Unmarshal([]byte(input), ptr.Interface())
180+
return ptr.Elem().Interface(), err
181+
} else if output_type.Kind() == reflect.Slice {
182+
ptr := reflect.New(output_type)
183+
ptr.Elem().Set(reflect.MakeSlice(output_type, 0, 0))
184+
err := yaml.Unmarshal([]byte(input), ptr.Interface())
185+
return StringifyMapKeys(ptr.Elem().Interface()), err
186+
} else {
187+
return nil, errors.New("Invalid output type for yaml " + fmt.Sprint(output_type))
188+
}
236189
}
237190

238-
return nil
191+
return nil, nil
239192
}

0 commit comments

Comments
 (0)