goon_model_gen 0.1.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 +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +44 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/goon_model_gen +10 -0
- data/goon_model_gen.gemspec +41 -0
- data/lib/goon_model_gen.rb +6 -0
- data/lib/goon_model_gen/cli.rb +79 -0
- data/lib/goon_model_gen/config.rb +83 -0
- data/lib/goon_model_gen/generator.rb +111 -0
- data/lib/goon_model_gen/golang.rb +22 -0
- data/lib/goon_model_gen/golang/builtin.rb +31 -0
- data/lib/goon_model_gen/golang/datastore_supported.rb +48 -0
- data/lib/goon_model_gen/golang/enum.rb +26 -0
- data/lib/goon_model_gen/golang/field.rb +41 -0
- data/lib/goon_model_gen/golang/file.rb +27 -0
- data/lib/goon_model_gen/golang/modifier.rb +65 -0
- data/lib/goon_model_gen/golang/named_slice.rb +24 -0
- data/lib/goon_model_gen/golang/package.rb +83 -0
- data/lib/goon_model_gen/golang/packages.rb +64 -0
- data/lib/goon_model_gen/golang/predeclared_type.rb +16 -0
- data/lib/goon_model_gen/golang/sentence.rb +17 -0
- data/lib/goon_model_gen/golang/struct.rb +38 -0
- data/lib/goon_model_gen/golang/type.rb +29 -0
- data/lib/goon_model_gen/model_builder.rb +137 -0
- data/lib/goon_model_gen/source/context.rb +17 -0
- data/lib/goon_model_gen/source/contextual.rb +9 -0
- data/lib/goon_model_gen/source/enum.rb +20 -0
- data/lib/goon_model_gen/source/field.rb +41 -0
- data/lib/goon_model_gen/source/file.rb +58 -0
- data/lib/goon_model_gen/source/loader.rb +71 -0
- data/lib/goon_model_gen/source/named_slice.rb +18 -0
- data/lib/goon_model_gen/source/struct.rb +26 -0
- data/lib/goon_model_gen/source/type.rb +21 -0
- data/lib/goon_model_gen/templates/dsl.rb +60 -0
- data/lib/goon_model_gen/templates/model/enum/01_base.go.erb +7 -0
- data/lib/goon_model_gen/templates/model/enum/02_All.go.erb +5 -0
- data/lib/goon_model_gen/templates/model/enum/02_Map.go.erb +5 -0
- data/lib/goon_model_gen/templates/model/enum/03_String.go.erb +3 -0
- data/lib/goon_model_gen/templates/model/enum/04_NameToValue.go.erb +5 -0
- data/lib/goon_model_gen/templates/model/enum/05_StringTo.go.erb +19 -0
- data/lib/goon_model_gen/templates/model/enum/06_ToString.go.erb +3 -0
- data/lib/goon_model_gen/templates/model/enum/07_Valid.go.erb +4 -0
- data/lib/goon_model_gen/templates/model/goon/01_struct.go.erb +6 -0
- data/lib/goon_model_gen/templates/model/goon/02_Assign.go.erb +16 -0
- data/lib/goon_model_gen/templates/model/goon/03_PrepareToCreate.go.erb +16 -0
- data/lib/goon_model_gen/templates/model/goon/04_PrepareToUpdate.go.erb +8 -0
- data/lib/goon_model_gen/templates/model/goon/05_PrepareFields.go.erb +8 -0
- data/lib/goon_model_gen/templates/model/goon/06_IsPersisted.go.erb +3 -0
- data/lib/goon_model_gen/templates/model/slice/01_base.go.erb +1 -0
- data/lib/goon_model_gen/templates/model/struct/01_struct.go.erb +6 -0
- data/lib/goon_model_gen/version.rb +3 -0
- metadata +189 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/modifier"
|
4
|
+
|
5
|
+
require "active_support/core_ext/string"
|
6
|
+
|
7
|
+
module GoonModelGen
|
8
|
+
module Golang
|
9
|
+
class Packages < Array
|
10
|
+
|
11
|
+
def name_to_type_map
|
12
|
+
each_with_object({}) do |pkg, d|
|
13
|
+
d.update(pkg.name_to_type_map)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def dup
|
18
|
+
Packages.new.add(*self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(*packages)
|
22
|
+
packages.each do |i|
|
23
|
+
self << i
|
24
|
+
end
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def detect_by(basename)
|
29
|
+
detect{|pkg| pkg.basename == basename}
|
30
|
+
end
|
31
|
+
|
32
|
+
def resolve_type_names(extra_packages = [])
|
33
|
+
candidates = dup.add(*extra_packages)
|
34
|
+
map(&:types).flatten.each do |t|
|
35
|
+
t.resolve(candidates)
|
36
|
+
end
|
37
|
+
return self
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param type_name [string]
|
41
|
+
# @param [Type]
|
42
|
+
def lookup(type_name)
|
43
|
+
if type_name.include?('.')
|
44
|
+
pkg_name, name = type_name.split('.', 2)
|
45
|
+
pkg = detect_by(pkg_name)
|
46
|
+
return pkg ? pkg.lookup(name) : nil
|
47
|
+
else
|
48
|
+
each do |pkg|
|
49
|
+
t = pkg.lookup(type_name)
|
50
|
+
return t if t
|
51
|
+
end
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def type_for(expression)
|
57
|
+
return nil if expression.blank?
|
58
|
+
Modifier.parse(expression) do |name|
|
59
|
+
lookup(name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
module GoonModelGen
|
4
|
+
module Golang
|
5
|
+
class Sentence
|
6
|
+
attr_reader :template_path
|
7
|
+
attr_reader :type
|
8
|
+
|
9
|
+
# @param template_path [string]
|
10
|
+
# @param type [Type]
|
11
|
+
def initialize(template_path, type)
|
12
|
+
@template_path = template_path
|
13
|
+
@type = type
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/type"
|
4
|
+
require "goon_model_gen/golang/field"
|
5
|
+
|
6
|
+
module GoonModelGen
|
7
|
+
module Golang
|
8
|
+
class Struct < Type
|
9
|
+
attr_accessor :ref_name
|
10
|
+
|
11
|
+
def fields
|
12
|
+
@fields ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param name [string]
|
16
|
+
# @param t [Type]
|
17
|
+
# @param tags [Hash<String,Array<String>>]
|
18
|
+
def new_field(name, t, tags, options = {})
|
19
|
+
Field.new(name, t, tags, options).tap do |f|
|
20
|
+
f.struct = self
|
21
|
+
fields.push(f)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def id_field
|
26
|
+
fields.detect(&:goon_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param pkgs [Packages]
|
30
|
+
def resolve(pkgs)
|
31
|
+
fields.each do |f|
|
32
|
+
f.resolve(pkgs)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
module GoonModelGen
|
4
|
+
module Golang
|
5
|
+
class Type
|
6
|
+
attr_reader :name
|
7
|
+
attr_accessor :package
|
8
|
+
|
9
|
+
# @param name [string]
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param pkgs [Packages]
|
15
|
+
def resolve(pkgs)
|
16
|
+
raise NotImplementedError, "#{self.type.name} doesn't implement resolve method"
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [string]
|
20
|
+
def qualified_name
|
21
|
+
if package && package.name
|
22
|
+
"#{package.name}.#{name}"
|
23
|
+
else
|
24
|
+
name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/source/context"
|
4
|
+
require "goon_model_gen/source/struct"
|
5
|
+
require "goon_model_gen/source/enum"
|
6
|
+
require "goon_model_gen/source/named_slice"
|
7
|
+
|
8
|
+
|
9
|
+
require "goon_model_gen/golang/package"
|
10
|
+
require "goon_model_gen/golang/packages"
|
11
|
+
require "goon_model_gen/golang/datastore_supported"
|
12
|
+
|
13
|
+
require "active_support/core_ext/string"
|
14
|
+
|
15
|
+
module GoonModelGen
|
16
|
+
class ModelBuilder
|
17
|
+
attr_reader :base_package_path
|
18
|
+
|
19
|
+
def initialize(base_package_path)
|
20
|
+
@base_package_path = base_package_path
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# @param context [Source::Context]
|
25
|
+
# @return [Golang::Packages]
|
26
|
+
def build(context)
|
27
|
+
Golang::Packages.new.tap do |r|
|
28
|
+
build_sentences = []
|
29
|
+
context.files.each do |f|
|
30
|
+
package_path = File.join(base_package_path, f.basename)
|
31
|
+
pkg, procs = build_package(package_path, f.types)
|
32
|
+
r << pkg
|
33
|
+
build_sentences.concat(procs)
|
34
|
+
end
|
35
|
+
r.resolve_type_names(Golang::DatastoreSupported.packages)
|
36
|
+
build_sentences.each(&:call)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param package_path [String]
|
41
|
+
# @param types [Array<Source::Type>]
|
42
|
+
# @return [Golang::Package, Array<Proc>]
|
43
|
+
def build_package(package_path, types)
|
44
|
+
procs = []
|
45
|
+
pkg = Golang::Package.new(package_path).tap do |pkg|
|
46
|
+
types.each do |t|
|
47
|
+
case t
|
48
|
+
when Source::Struct then
|
49
|
+
go_type = build_struct(t, pkg)
|
50
|
+
template = (t.id_name && t.id_type) ? "model/goon" : "model/struct"
|
51
|
+
procs << Proc.new{ build_sentences(template, t, go_type) }
|
52
|
+
when Source::Enum then
|
53
|
+
go_type = pkg.new_enum(t.name, t.base_type, t.map)
|
54
|
+
procs << Proc.new{ build_sentences("model/enum", t, go_type) }
|
55
|
+
when Source::NamedSlice then
|
56
|
+
go_type = pkg.new_named_slice(t.name, t.base_type_name)
|
57
|
+
procs << Proc.new{ build_sentences("model/slice", t, go_type) }
|
58
|
+
else
|
59
|
+
raise "Unsupported type #{t.class.name} #{t.inspect}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
return pkg, procs
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param t [Source::Struct]
|
67
|
+
# @param pkg [Golang::Package]
|
68
|
+
# @return [Golang::Struct]
|
69
|
+
def build_struct(t, pkg)
|
70
|
+
pkg.new_struct(t.name).tap do |s|
|
71
|
+
s.ref_name = t.ref_name
|
72
|
+
if t.id_name && t.id_type
|
73
|
+
tags = {
|
74
|
+
'goon' => ['id'],
|
75
|
+
'datastore' => ['-'],
|
76
|
+
'json' => [t.id_name.underscore],
|
77
|
+
}
|
78
|
+
s.new_field(t.id_name, t.id_type, tags, goon_id: true)
|
79
|
+
end
|
80
|
+
t.fields.each do |f|
|
81
|
+
s.new_field(f.name, f.type_name, f.build_tags)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# @param template_base [string]
|
88
|
+
# @param t [Source::Struct]
|
89
|
+
# @param go_type [Golang::Type]
|
90
|
+
def build_sentences(template_base, t, go_type)
|
91
|
+
m2t = method_to_template_for(template_base)
|
92
|
+
t.generators ||= default_generators_for(template_base)
|
93
|
+
t.generators.each do |name, suffix|
|
94
|
+
next if !suffix
|
95
|
+
template = m2t[name]
|
96
|
+
parts = [t.name.underscore]
|
97
|
+
custom_suffix = false
|
98
|
+
if suffix.is_a?(String)
|
99
|
+
parts << suffix
|
100
|
+
custom_suffix = true
|
101
|
+
end
|
102
|
+
filename = parts.join('_') << '.go'
|
103
|
+
go_type.package.find_or_new_file(filename).tap do |file|
|
104
|
+
file.custom_suffix = custom_suffix
|
105
|
+
file.new_sentence(File.join(template_base, template), go_type)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def default_generators_for(template_base)
|
111
|
+
method_to_template_for(template_base).keys.
|
112
|
+
each_with_object({}){|name, d| d[name] = true }
|
113
|
+
end
|
114
|
+
|
115
|
+
def method_to_template_map
|
116
|
+
@method_to_template_map ||= {}
|
117
|
+
end
|
118
|
+
|
119
|
+
def method_to_template_for(template_base)
|
120
|
+
method_to_template_map[template_base] ||=
|
121
|
+
begin
|
122
|
+
templates_for(template_base).each_with_object({}) do |filename, d|
|
123
|
+
m = filename.sub(/\A\d+\_/, '').sub(/\.go\.erb\z/, '')
|
124
|
+
d[m] = filename
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def templates_for(template_base)
|
130
|
+
base_dir = File.join(File.expand_path('../templates', __FILE__), template_base)
|
131
|
+
Dir.chdir(base_dir) do
|
132
|
+
Dir.glob('*.go.erb')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/source/type"
|
4
|
+
|
5
|
+
module GoonModelGen
|
6
|
+
module Source
|
7
|
+
class Enum < Type
|
8
|
+
attr_reader :base_type, :map
|
9
|
+
|
10
|
+
# @param name [String]
|
11
|
+
# @param base_type [String]
|
12
|
+
# @param map [Hash<Object,String>]
|
13
|
+
def initialize(name, base_type, map)
|
14
|
+
super(name)
|
15
|
+
@base_type = base_type
|
16
|
+
@map = map
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/source/contextual"
|
4
|
+
|
5
|
+
module GoonModelGen
|
6
|
+
module Source
|
7
|
+
class Field
|
8
|
+
include Contextual
|
9
|
+
|
10
|
+
attr_reader :name, :type_name
|
11
|
+
attr_reader :required
|
12
|
+
attr_reader :unique
|
13
|
+
attr_reader :tags # Hash<string,Array[string]> ex. for datastore, validate, json, etc...
|
14
|
+
|
15
|
+
# @param name [String]
|
16
|
+
# @param attrs [Hash<string,Object>]
|
17
|
+
def initialize(name, attrs)
|
18
|
+
@name = name
|
19
|
+
@type_name = attrs['type']
|
20
|
+
@required = attrs['required']
|
21
|
+
@unique = attrs['unique']
|
22
|
+
@tags = attrs['tags']
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_tags
|
26
|
+
r = {}
|
27
|
+
(tags || {}).each do |key, val|
|
28
|
+
r[key] = val.is_a?(Array) ? val.dup : [val]
|
29
|
+
end
|
30
|
+
r['json'] ||= [name.underscore]
|
31
|
+
if required
|
32
|
+
r['validate'] ||= []
|
33
|
+
r['validate'] << 'required'
|
34
|
+
else
|
35
|
+
r['json'] << 'omitempty'
|
36
|
+
end
|
37
|
+
return r
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/source/contextual"
|
4
|
+
require "goon_model_gen/source/struct"
|
5
|
+
require "goon_model_gen/source/enum"
|
6
|
+
require "goon_model_gen/source/named_slice"
|
7
|
+
|
8
|
+
module GoonModelGen
|
9
|
+
module Source
|
10
|
+
class File
|
11
|
+
include Contextual
|
12
|
+
|
13
|
+
attr_reader :path
|
14
|
+
attr_reader :types
|
15
|
+
|
16
|
+
# @param path [string]
|
17
|
+
def initialize(path)
|
18
|
+
@path = path
|
19
|
+
@types = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def basename
|
23
|
+
::File.basename(path, '.*')
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param name [string]
|
27
|
+
# @return [Struct]
|
28
|
+
def new_struct(name)
|
29
|
+
Struct.new(name).tap do |s|
|
30
|
+
s.context = self.context
|
31
|
+
types.push(s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param name [string]
|
36
|
+
# @param base_type [String]
|
37
|
+
# @param map [Hash<Object,Hash>] elements of enum from YAML
|
38
|
+
# @return [Enum]
|
39
|
+
def new_enum(name, base_type, map)
|
40
|
+
Enum.new(name, base_type, map).tap do |t|
|
41
|
+
t.context = self.context
|
42
|
+
types.push(t)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param name [string]
|
47
|
+
# @param base_type_name [string]
|
48
|
+
# @return [Slice]
|
49
|
+
def new_named_slice(name, base_type_name)
|
50
|
+
NamedSlice.new(name, base_type_name).tap do |s|
|
51
|
+
s.context = self.context
|
52
|
+
types.push(s)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|