goa_model_gen 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7688fbd0deceb1a0e7c2bcf7db894bae0a8fcb02c391e00c34dda9760f525601
4
- data.tar.gz: 646ff959fe0cce1b7256d7bf7de046aebed82a4e030168429a005b8e32c48658
3
+ metadata.gz: 128844e0701ac2c0ccbb8931770e8778ce28527c7c4dca2948d3fb647b33073d
4
+ data.tar.gz: 6b03045e22675b21b93762927c3551e0c43e5711ce9aa9f48e64a92bcbffa145
5
5
  SHA512:
6
- metadata.gz: 47eafcee348fa1a47b3aada4540f49bdcca3f6a8e6ccd45ecee2613dceeddb676981dbebf31b8656da30a08592962df53514d726258d02e898e19af10fa72d55
7
- data.tar.gz: 99ebfd800233dadca64e4d292efd15a6947c6a6bbf59f2a379ea01ad51df59da77d37dce3f0d24bf5d0cc1395338face2ca987fc893ab7619662135447872302
6
+ metadata.gz: d1a948144492a1ea82cae9bd2afb709a89c29b8cf2ed7286385eeef43e4e7dd5259ed3b153656d14f39429ea7cb53552b0fe4477a26c2731aaf5ed007a549acd
7
+ data.tar.gz: 5044445888128712fd8419cb4487308d86d6d1e4abfe77d1cdc342c9048877fa20d2160dd4cb71041ea2965b3786a1927fcb8218546d4f577204fe142cf0cc56
@@ -1,11 +1,16 @@
1
+ # coding: utf-8
1
2
  require "goa_model_gen"
2
3
 
4
+ require 'json'
5
+
6
+ require "active_support/core_ext/string"
3
7
  require "thor"
4
8
 
5
9
  require "goa_model_gen/logger"
6
10
  require "goa_model_gen/config"
7
11
  require "goa_model_gen/loader"
8
12
  require "goa_model_gen/generator"
13
+ require "goa_model_gen/go_struct"
9
14
 
10
15
  module GoaModelGen
11
16
  class Cli < Thor
@@ -61,17 +66,32 @@ module GoaModelGen
61
66
  end
62
67
  end
63
68
 
64
- desc "converter FILE1...", "Generate converter files from definition files and swagger.yaml"
65
- def converter(*paths)
69
+ desc "structs_gen", "Generate go source files to generate structs.json"
70
+ def structs_gen
71
+ setup
72
+ new_generator.process({
73
+ "templates/structs_base.go.erb" => File.join(cfg.structs_gen_dir, "structs.go"),
74
+ "templates/structs_main.go.erb" => File.join(cfg.structs_gen_dir, "main.go"),
75
+ })
76
+ end
77
+
78
+ desc "converter FILE", "Generate converter files from definition file structs.json"
79
+ def converter(path)
66
80
  setup
67
81
  new_generator.process({
68
82
  "templates/converter_base.go.erb" => File.join(cfg.converter_dir, "base.go"),
69
83
  })
70
- load_types_for(paths) do |source_file|
71
- next if source_file.types.all?{|t| !t.payload && !t.media_type}
72
- new_generator.tap{|g| g.source_file = source_file }.process({
73
- 'templates/converter.go.erb' => File.join(cfg.converter_dir, source_file.basename, "conv.go"),
74
- })
84
+ structs = JSON.parse(File.read(path))
85
+ (structs['model'] || []).each do |mt|
86
+ m = GoStruct.new(mt)
87
+ pt = (structs['payload'] || []).detect{|t| t["Name"] == "#{m.name}Payload" }
88
+ rt = (structs['result'] || []).detect{|t| t["Name"] == m.name }
89
+ variables = {
90
+ model: m,
91
+ payload: pt ? GoStruct.new(pt) : nil,
92
+ result: rt ? GoStruct.new(rt) : nil
93
+ }
94
+ new_generator.run('templates/converter.go.erb', File.join(cfg.converter_dir, m.name.underscore, "conv.go"), variables)
75
95
  end
76
96
  end
77
97
 
@@ -16,6 +16,7 @@ module GoaModelGen
16
16
  model_dir
17
17
  store_dir
18
18
  converter_dir
19
+ structs_gen_dir
19
20
  validator_path
20
21
  generator_version_comment
21
22
  ].freeze
@@ -29,6 +30,7 @@ module GoaModelGen
29
30
  @model_dir ||= "./model"
30
31
  @store_dir ||= "./stores"
31
32
  @converter_dir ||= "./converters"
33
+ @structs_gen_dir ||= "./cmd/structs"
32
34
  @validator_path ||= "gopkg.in/go-playground/validator.v9"
33
35
  @generator_version_comment ||= false
34
36
  self
@@ -65,13 +65,18 @@ module GoaModelGen
65
65
  "datastore" => "google.golang.org/appengine/datastore",
66
66
  }
67
67
 
68
- def generate(template_path)
68
+ def generate(template_path, variables = {})
69
69
  clear_dependencies
70
70
  user_editable(value: false)
71
71
 
72
72
  abs_path = File.expand_path('../' + template_path, __FILE__)
73
73
  erb = ERB.new(File.read(abs_path), nil, "-")
74
74
  erb.filename = abs_path
75
+
76
+ variables.each do |key, val|
77
+ define_singleton_method(key){ val }
78
+ end
79
+
75
80
  body = erb.result(binding).strip
76
81
 
77
82
  raise "No package given in #{abs_path}" if package.blank?
@@ -97,10 +102,10 @@ module GoaModelGen
97
102
  clear: "\e[0m",
98
103
  }
99
104
 
100
- def run(template_path, output_path)
101
- content = generate(template_path)
105
+ def run(template_path, output_path, variables = {}, &block)
106
+ content = generate(template_path, variables, &block)
102
107
 
103
- if user_editable? && keep_editable
108
+ if user_editable? && keep_editable && File.exist?(output_path)
104
109
  $stderr.puts("%sKEEP%s %s" % [COLORS[:blue], COLORS[:clear], output_path])
105
110
  return
106
111
  end
@@ -0,0 +1,68 @@
1
+ # coding: utf-8
2
+ require 'goa_model_gen'
3
+
4
+ require "active_support/core_ext/string"
5
+
6
+ module GoaModelGen
7
+ class GoStruct
8
+ attr_reader :name, :pkg_path, :size, :fields
9
+ def initialize(d)
10
+ @name = d['Name']
11
+ @pkg_path = d['PkgPath']
12
+ @size = d['Size']
13
+ @fields = (d['Fields'] || []).map do |f|
14
+ GoStructField.new(f)
15
+ end
16
+ end
17
+ end
18
+
19
+ class GoStructField
20
+ attr_reader :name, :type, :anonymous, :tags
21
+ def initialize(d)
22
+ @name = d['Name']
23
+ @anonymous = d['Anonymous']
24
+ @type = GoStructFieldType.new(d['Type'])
25
+ @tags = d['Tag'] || {}
26
+ end
27
+ end
28
+
29
+ class GoStructFieldType
30
+ attr_reader :name, :kinds, :pkg_path, :representation
31
+ def initialize(d)
32
+ @name = d['Name']
33
+ @kinds = d['Kinds']
34
+ @pkg_path = d['PkgPath']
35
+ @representation = d['Representation']
36
+ end
37
+
38
+ def ==(other)
39
+ (pkg_path == other.pkg_path) &&
40
+ (name == other.name) &&
41
+ (kinds == other.kinds) &&
42
+ (representation == other.representation)
43
+ end
44
+ alias_method :assignable_with?, :==
45
+
46
+ def pointer_of?(other)
47
+ (pkg_path == other.pkg_path) &&
48
+ (name == other.name) &&
49
+ (kinds == (other.kinds + ['ptr']))
50
+ end
51
+ def pointee_of?(other)
52
+ other.pointer_of?(self)
53
+ end
54
+
55
+ def needs_error_to_convert_to?(other)
56
+ return false if other.name == 'string'
57
+ return true if name == 'string'
58
+ return false
59
+ end
60
+
61
+ def method_part_name
62
+ parts =
63
+ kinds.first == 'struct' ?
64
+ [name] + kinds[1..-1] : kinds
65
+ parts.map(&:camelize).join
66
+ end
67
+ end
68
+ end
@@ -7,96 +7,110 @@ def method_calling_exp(m, argument)
7
7
  end
8
8
  end
9
9
  -%>
10
- <%- package source_file.basename -%>
10
+ <%- package model.name.underscore -%>
11
11
 
12
- <%- source_file.types.select(&:gen_converter?).each do |type| -%>
13
- <%- if type.payload -%>
12
+ <%- if payload-%>
14
13
  <%-
15
- import "#{config.go_package}/converters"
16
- import :gen, "#{config.go_package}/gen/#{type.name.underscore}"
17
- import "#{config.go_package}/model"
14
+ import "#{config.go_package}/converters"
15
+ import :gen, "#{config.go_package}/gen/#{model.name.underscore}"
16
+ import "#{config.go_package}/model"
18
17
  -%>
19
- func <%= type.name %>PayloadToModel(payload *gen.<%= type.payload_name %>) (*model.<%= type.name %>, error) {
20
- model := &model.<%= type.name %>{}
21
- if err := CopyFrom<%= type.name %>PayloadToModel(payload, model); err != nil {
18
+ func <%= model.name %>PayloadToModel(payload *gen.<%= payload.name %>) (*model.<%= model.name %>, error) {
19
+ m := &model.<%= model.name %>{}
20
+ if err := CopyFrom<%= model.name %>PayloadToModel(payload, m); err != nil {
22
21
  return nil, err
23
22
  }
24
- return model, nil
23
+ return m, nil
25
24
  }
26
25
 
27
- func CopyFrom<%= type.name %>PayloadToModel(payload *gen.<%= type.payload_name %>, model *model.<%= type.name %>) error {
26
+ func CopyFrom<%= model.name %>PayloadToModel(payload *gen.<%= payload.name %>, m *model.<%= model.name %>) error {
28
27
  if payload == nil {
29
28
  return converters.NoPayloadGiven
30
29
  }
31
- if model == nil {
30
+ if m == nil {
32
31
  return converters.NoModelGiven
33
32
  }
34
33
 
35
34
  <%-
36
- type.fields_including_id.each do |f|
37
- pf = type.payload.fields.detect{|pf| pf.name == f.swagger_name }
38
- if pf.nil?
35
+ assigned_field_names = []
36
+ model.fields.each do |mf|
37
+ pf_name = (mf.tags['payload'] || mf.name).downcase
38
+ pf = payload.fields.detect{|pf| pf.name.downcase == pf_name }
39
+ assigned_field_names.push(pf.name) if pf
40
+ if pf.nil?
39
41
  -%>
40
- // <%= f.name %> not found in payload fields
41
- <%-
42
- else
43
- simple, with_error, method_name = f.payload_assignment_options(pf)
44
- -%>
45
- <%- if simple -%>
46
- model.<%= f.name %> = payload.<%= f.goa_name %>
47
- <%- elsif !with_error -%>
48
- model.<%= f.name %> = converters.<%= method_calling_exp(method_name, "payload.#{f.goa_name}") %>
42
+ // <%= mf.name %> not found in <%= payload.name %> fields
43
+ <%- elsif mf.type.assignable_with?(pf.type) -%>
44
+ m.<%= mf.name %> = payload.<%= pf.name %>
45
+ <%- elsif mf.type.pointee_of?(pf.type) -%>
46
+ m.<%= mf.name %> = *payload.<%= pf.name %>
47
+ <%- elsif !pf.type.needs_error_to_convert_to?(mf.type) -%>
48
+ m.<%= mf.name %> = converters.<%= pf.type.method_part_name %>To<%= mf.type.method_part_name %>(payload.<%= pf.name %>)
49
49
  <%- else -%>
50
- if v, err := converters.<%= method_calling_exp(method_name, "payload.#{f.goa_name}") %>; err != nil {
50
+ if v, err := converters.<%= pf.type.method_part_name %>To<%= mf.type.method_part_name %>(payload.<%= pf.name %>); err != nil {
51
51
  return err
52
52
  } else {
53
- model.<%= f.name %> = v
53
+ m.<%= mf.name %> = v
54
54
  }
55
55
  <%- end -%>
56
56
  <%- end -%>
57
- <%- end -%>
58
- <%- type.payload.field_diffs(type.fields_including_id.map{|f| f.swagger_name}).each do |pf| -%>
59
- // No model field for payload field "<%= pf.name %>"
60
- <%- end -%>
57
+ <%-
58
+ payload.fields.each do |pf|
59
+ unless assigned_field_names.include?(pf.name)
60
+ -%>
61
+ // No model field in <%= model.name %> for payload field "<%= pf.name %>"
62
+ <%-
63
+ end
64
+ end
65
+ -%>
61
66
  return nil
62
67
  }
68
+ <%- end -%>
63
69
 
64
- <%- end -%>
65
- <%- if type.media_type -%>
66
- func <%= type.name %>ModelToMediaType(model *model.<%= type.name %>) (*gen.<%= type.media_type_name_for_go %>, error) {
67
- if model == nil {
70
+ <%- if result -%>
71
+ <%-
72
+ import "#{config.go_package}/converters"
73
+ import :gen, "#{config.go_package}/gen/#{model.name.underscore}"
74
+ import "#{config.go_package}/model"
75
+ -%>
76
+ func <%= model.name %>ModelToResult(m *model.<%= model.name %>) (*gen.<%= result.name %>, error) {
77
+ if m == nil {
68
78
  return nil, converters.NoModelGiven
69
79
  }
70
- r := &gen.<%= type.media_type_name_for_go %>{}
80
+ r := &gen.<%= result.name %>{}
71
81
 
72
82
  <%-
73
- type.fields_including_id.each do |f|
74
- mf = type.media_type.fields.detect{|mf| f.swagger_name == mf.name }
75
- if mf.nil?
83
+ assigned_field_names = []
84
+ model.fields.each do |mf|
85
+ rf_name = (mf.tags['result'] || mf.name).downcase
86
+ rf = result.fields.detect{|rf| rf.name.downcase == rf_name }
87
+ assigned_field_names.push(rf.name) if rf
88
+ if rf.nil?
76
89
  -%>
77
- // <%= f.name %> not found for media type field
78
- <%-
79
- else
80
- simple, with_error, method_name = f.media_type_assignment_options(mf)
81
- -%>
82
- <%- if simple -%>
83
- r.<%= f.goa_name %> = model.<%= f.name %>
84
- <%- elsif !with_error -%>
85
- r.<%= f.goa_name %> = converters.<%= method_calling_exp(method_name, "model.#{f.name}") %>
86
- <%- else -%>
87
- if val, err := converters.<%= method_calling_exp(method_name, "model.#{f.name}") %>; err != nil {
88
- return nil, err
90
+ // <%= mf.name %> not found in <%= result.name %> fields
91
+ <%- elsif rf.type.assignable_with?(mf.type) -%>
92
+ r.<%= rf.name %> = m.<%= mf.name %>
93
+ <%- elsif rf.type.pointer_of?(mf.type) -%>
94
+ r.<%= rf.name %> = &m.<%= mf.name %>
95
+ <%- elsif !mf.type.needs_error_to_convert_to?(rf.type) -%>
96
+ r.<%= rf.name %> = converters.<%= mf.type.method_part_name %>To<%= rf.type.method_part_name %>(m.<%= mf.name %>)
97
+ <%- else -%>
98
+ if v, err := converters.<%= mf.type.method_part_name %>To<%= rf.type.method_part_name %>(m.<%= mf.name %>); err != nil {
99
+ return err
89
100
  } else {
90
- r.<%= f.goa_name %> = val
101
+ r.<%= rf.name %> = v
91
102
  }
92
- <%- end
93
- end -%>
94
- <%- end -%>
95
- <%- type.media_type.field_diffs(type.fields_including_id.map{|f| f.swagger_name}).each do |mf| -%>
96
- // No model field for media type field "<%= mf.name %>"
103
+ <%- end -%>
97
104
  <%- end -%>
105
+ <%-
106
+ result.fields.each do |rf|
107
+ unless assigned_field_names.include?(rf.name)
108
+ -%>
109
+ // No model field in <%= model.name %> for result field "<%= rf.name %>"
110
+ <%-
111
+ end
112
+ end
113
+ -%>
98
114
  return r, nil
99
115
  }
100
-
101
- <%- end -%>
102
116
  <%- end -%>
@@ -0,0 +1,165 @@
1
+ <%- package 'main' -%>
2
+
3
+ import (
4
+ "encoding/json"
5
+ "fmt"
6
+ "os"
7
+ "reflect"
8
+ "regexp"
9
+ )
10
+
11
+ func process(objectMap map[string][]interface{}, ptn *regexp.Regexp) {
12
+ res := map[string][]*DataType{}
13
+
14
+ for key, objects := range objectMap {
15
+ types := []reflect.Type{}
16
+ for _, obj := range objects {
17
+ types = append(types, reflect.TypeOf(obj))
18
+ }
19
+
20
+ types = digTypes(types)
21
+
22
+ dataTypes := []*DataType{}
23
+ for _, t := range types {
24
+ dt := newDataType(t)
25
+ if ptn.MatchString(dt.PkgPath) {
26
+ dataTypes = append(dataTypes, dt)
27
+ }
28
+ }
29
+
30
+ res[key] = dataTypes
31
+ }
32
+
33
+ b, err := json.MarshalIndent(res, "", " ")
34
+ if err != nil {
35
+ fmt.Fprintf(os.Stderr, "Failed to json.MarshalIndent because of %v\n", err)
36
+ return
37
+ }
38
+ _, err = os.Stdout.Write(b)
39
+ if err != nil {
40
+ fmt.Fprintf(os.Stderr, "Failed to write because of %v\n", err)
41
+ return
42
+ }
43
+ }
44
+
45
+ type DataFieldType struct {
46
+ PkgPath string `json:"PkgPath,omitempty"`
47
+ Name string `json:"Name,omitempty"`
48
+ Kinds []string `json:"Kinds,omitempty"`
49
+ Representation string
50
+ }
51
+
52
+ type DataField struct {
53
+ Name string
54
+ Type *DataFieldType
55
+ RawTag string `json:"RawTag,omitempty"`
56
+ Tag map[string]string `json:"Tag,omitempty"`
57
+ Anonymous bool
58
+ }
59
+
60
+ type DataType struct {
61
+ Name string
62
+ PkgPath string
63
+ Size uintptr
64
+ Fields []*DataField
65
+ }
66
+
67
+ func digTypes(types []reflect.Type) []reflect.Type {
68
+ m := map[string]reflect.Type{}
69
+ for _, t := range types {
70
+ key := t.PkgPath() + "." + t.Name()
71
+ m[key] = t
72
+ }
73
+
74
+ for _, t := range types {
75
+ digType(m, t)
76
+ }
77
+
78
+ r := []reflect.Type{}
79
+ for _, t := range m {
80
+ r = append(r, t)
81
+ }
82
+ return r
83
+ }
84
+
85
+ func digType(m map[string]reflect.Type, t reflect.Type) {
86
+ switch t.Kind() {
87
+ case reflect.Struct:
88
+ digStruct(m, t)
89
+ case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
90
+ digType(m, t.Elem())
91
+ }
92
+ }
93
+
94
+ func digStruct(m map[string]reflect.Type, t reflect.Type) {
95
+ numField := t.NumField()
96
+ for i := 0; i < numField; i++ {
97
+ f := t.Field(i)
98
+ ft := f.Type
99
+ if ft.PkgPath() != "" {
100
+ key := ft.PkgPath() + "." + ft.Name()
101
+ _, ok := m[key]
102
+ if !ok {
103
+ m[key] = ft
104
+ switch ft.Kind() {
105
+ case reflect.Struct:
106
+ digType(m, ft)
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+
113
+ func newDataType(t reflect.Type) *DataType {
114
+ r := &DataType{
115
+ Name: t.Name(),
116
+ PkgPath: t.PkgPath(),
117
+ Size: t.Size(),
118
+ }
119
+ if t.Kind() != reflect.Struct {
120
+ return r
121
+ }
122
+
123
+ fields := []*DataField{}
124
+ numField := t.NumField()
125
+ for i := 0; i < numField; i++ {
126
+ f := t.Field(i)
127
+ ft := f.Type
128
+ fields = append(fields, &DataField{
129
+ Name: f.Name,
130
+ Anonymous: f.Anonymous,
131
+ Type: DataFieldTypeFromType(ft),
132
+ Tag: parseTag(string(f.Tag)),
133
+ RawTag: string(f.Tag),
134
+ })
135
+ }
136
+ r.Fields = fields
137
+ return r
138
+ }
139
+
140
+ func DataFieldTypeFromType(t reflect.Type) *DataFieldType {
141
+ switch t.Kind() {
142
+ case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
143
+ r := DataFieldTypeFromType(t.Elem())
144
+ r.Kinds = append(r.Kinds, t.Kind().String())
145
+ return r
146
+ default:
147
+ return &DataFieldType{
148
+ PkgPath: t.PkgPath(),
149
+ Name: t.Name(),
150
+ Kinds: []string{t.Kind().String()},
151
+ Representation: t.String(),
152
+ }
153
+ }
154
+ }
155
+
156
+ var TagParserRE = regexp.MustCompile(`\s*([^:\s]+?):"(.+?)"`)
157
+
158
+ func parseTag(src string) map[string]string {
159
+ parsed := TagParserRE.FindAllStringSubmatch(src, -1)
160
+ r := map[string]string{}
161
+ for _, parts := range parsed {
162
+ r[parts[1]] = parts[2]
163
+ }
164
+ return r
165
+ }
@@ -0,0 +1,28 @@
1
+ <%-
2
+ package 'main'
3
+
4
+ user_editable
5
+
6
+ import "regexp"
7
+ -%>
8
+
9
+ // Usage
10
+ // $ go run <%= config.structs_gen_dir %>/*.go
11
+
12
+ func main() {
13
+ ptn := regexp.MustCompile(`\A<%= config.go_package %>`)
14
+
15
+ objectMap := map[string][]interface{}{
16
+ "model": []interface{}{
17
+ // model.User{},
18
+ },
19
+ "payload": []interface{}{
20
+ // user.UserPayload{},
21
+ },
22
+ "result": []interface{}{
23
+ // user.User{},
24
+ },
25
+ }
26
+
27
+ process(objectMap, ptn)
28
+ }
@@ -1,3 +1,3 @@
1
1
  module GoaModelGen
2
- VERSION = "0.7.1"
2
+ VERSION = "0.8.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goa_model_gen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - akm
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-08 00:00:00.000000000 Z
11
+ date: 2019-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -147,6 +147,7 @@ files:
147
147
  - lib/goa_model_gen/config.rb
148
148
  - lib/goa_model_gen/field.rb
149
149
  - lib/goa_model_gen/generator.rb
150
+ - lib/goa_model_gen/go_struct.rb
150
151
  - lib/goa_model_gen/goa.rb
151
152
  - lib/goa_model_gen/golang_helper.rb
152
153
  - lib/goa_model_gen/loader.rb
@@ -160,6 +161,8 @@ files:
160
161
  - lib/goa_model_gen/templates/model_validation.go.erb
161
162
  - lib/goa_model_gen/templates/store.go.erb
162
163
  - lib/goa_model_gen/templates/store_validation.go.erb
164
+ - lib/goa_model_gen/templates/structs_base.go.erb
165
+ - lib/goa_model_gen/templates/structs_main.go.erb
163
166
  - lib/goa_model_gen/templates/validator.go.erb
164
167
  - lib/goa_model_gen/type.rb
165
168
  - lib/goa_model_gen/version.rb