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,111 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/templates/dsl"
|
4
|
+
require "goon_model_gen/golang"
|
5
|
+
|
6
|
+
module GoonModelGen
|
7
|
+
class Generator
|
8
|
+
include Templates::DSL
|
9
|
+
|
10
|
+
attr_reader :file, :packages
|
11
|
+
attr_reader :templates_dir
|
12
|
+
|
13
|
+
attr_accessor :thor
|
14
|
+
attr_accessor :gofmt_disabled # false/true
|
15
|
+
attr_accessor :version_comment # false/true
|
16
|
+
attr_accessor :force, :skip # false/true
|
17
|
+
attr_accessor :overwrite_custom_file # false/true
|
18
|
+
|
19
|
+
DEFAULT_TEMPLATES_DIR = File.expand_path('../templates', __FILE__)
|
20
|
+
|
21
|
+
# @param file [Golang::File]
|
22
|
+
# @param templates_dir [String]
|
23
|
+
def initialize(file, packages, templates_dir: DEFAULT_TEMPLATES_DIR, thor: nil)
|
24
|
+
@file = file
|
25
|
+
@packages = packages
|
26
|
+
@templates_dir = templates_dir
|
27
|
+
@thor = thor
|
28
|
+
end
|
29
|
+
|
30
|
+
COLORS = {
|
31
|
+
blue: "\e[34m",
|
32
|
+
clear: "\e[0m",
|
33
|
+
}
|
34
|
+
|
35
|
+
def run(variables = {})
|
36
|
+
output_path = File.join(Golang.gopath, 'src', file.package.path, file.name)
|
37
|
+
|
38
|
+
if file.custom_suffix && File.exist?(output_path) && !overwrite_custom_file
|
39
|
+
$stderr.puts("%sKEEP%s %s" % [COLORS[:blue], COLORS[:clear], output_path])
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
content = execute(variables)
|
44
|
+
|
45
|
+
options = {skip: skip, force: force}
|
46
|
+
thor.create_file(output_path, content, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def execute(variables = {})
|
50
|
+
variables.each do |key, val|
|
51
|
+
define_singleton_method(key){ val }
|
52
|
+
end
|
53
|
+
|
54
|
+
texts = file.sentences.sort_by(&:template_path).map do |sentence|
|
55
|
+
template_path = File.join(templates_dir, sentence.template_path)
|
56
|
+
|
57
|
+
# local variables used in tempaltes
|
58
|
+
type = sentence.type
|
59
|
+
package = type.package
|
60
|
+
|
61
|
+
erb = ERB.new(File.read(template_path), nil, "-")
|
62
|
+
erb.filename = template_path
|
63
|
+
erb.result(binding).strip
|
64
|
+
end
|
65
|
+
|
66
|
+
r = [
|
67
|
+
header_comments,
|
68
|
+
"package %s" % file.package.name,
|
69
|
+
partitioned_imports(except: [file.package.path]),
|
70
|
+
texts.join("\n\n"),
|
71
|
+
].join("\n\n").strip << "\n"
|
72
|
+
|
73
|
+
r = gofmt(r) unless gofmt_disabled
|
74
|
+
r
|
75
|
+
end
|
76
|
+
|
77
|
+
def header_comments
|
78
|
+
r = []
|
79
|
+
if user_editable?
|
80
|
+
r << "You can edit this file. goa_model_gen doesn't overwrite this file."
|
81
|
+
else
|
82
|
+
r << "DO NOT EDIT this file."
|
83
|
+
end
|
84
|
+
|
85
|
+
if version_comment
|
86
|
+
r << "This code generated by goon_model_gen-#{GoonModelGen::VERSION}"
|
87
|
+
end
|
88
|
+
|
89
|
+
return r.map{|s| "// #{s}" }.join("\n")
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
def gofmt(content)
|
94
|
+
# https://docs.ruby-lang.org/ja/2.5.0/class/IO.html#S_POPEN
|
95
|
+
r = IO.popen(["gofmt"], "r+", err: :out) do |io|
|
96
|
+
io.puts(content)
|
97
|
+
io.close_write
|
98
|
+
io.read
|
99
|
+
end
|
100
|
+
return r unless r.empty?
|
101
|
+
raise "gofmt returned empty output:\n#{content}"
|
102
|
+
end
|
103
|
+
|
104
|
+
# @param cfg [Config]
|
105
|
+
def load_config(cfg)
|
106
|
+
[:gofmt_disabled, :version_comment].each do |key|
|
107
|
+
self.send("#{key}=", cfg.send(key))
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/package"
|
4
|
+
require "goon_model_gen/golang/builtin"
|
5
|
+
|
6
|
+
module GoonModelGen
|
7
|
+
module Golang
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def gopath
|
11
|
+
# Instead of $GOPATH
|
12
|
+
`go env GOPATH`.strip
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Package]
|
16
|
+
def builtin_package
|
17
|
+
Buildin.package
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/predeclared_type"
|
4
|
+
require "goon_model_gen/golang/package"
|
5
|
+
|
6
|
+
module GoonModelGen
|
7
|
+
module Golang
|
8
|
+
class Builtin < PredeclaredType
|
9
|
+
TYPE_NAMES =
|
10
|
+
%w[bool byte complex128 complex64
|
11
|
+
error float32 float64 int int16 int32 int64 int8
|
12
|
+
rune string uint uint16 uint32 uint64 uint8 uintptr]
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def package
|
16
|
+
@package ||= Package.new(nil).tap do |pkg|
|
17
|
+
instances.each do |i|
|
18
|
+
i.package = pkg
|
19
|
+
pkg.types.push(i)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def instances
|
25
|
+
@instances ||= TYPE_NAMES.map{|name| self.new(name) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/predeclared_type"
|
4
|
+
require "goon_model_gen/golang/package"
|
5
|
+
require "goon_model_gen/golang/packages"
|
6
|
+
require "goon_model_gen/golang/builtin"
|
7
|
+
|
8
|
+
module GoonModelGen
|
9
|
+
module Golang
|
10
|
+
class DatastoreSupported < PredeclaredType
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def datastore
|
15
|
+
@datastore ||= Package.new('google.golang.org/appengine/datastore').tap do |pkg|
|
16
|
+
pkg.add(self.new('ByteString'))
|
17
|
+
pkg.add(self.new('Key'))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def time
|
22
|
+
@time ||= Package.new('time').tap do |pkg|
|
23
|
+
pkg.add(self.new('Time'))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def appengine
|
28
|
+
@appengine ||= Package.new('google.golang.org/appengine').tap do |pkg|
|
29
|
+
pkg.add(self.new('BlobKey'))
|
30
|
+
pkg.add(self.new('GeoPoint'))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def packages
|
36
|
+
@packages ||= Packages.new.tap do |pkgs|
|
37
|
+
pkgs << Builtin.package
|
38
|
+
pkgs << datastore
|
39
|
+
pkgs << time
|
40
|
+
pkgs << appengine
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/type"
|
4
|
+
|
5
|
+
module GoonModelGen
|
6
|
+
module Golang
|
7
|
+
class Enum < Type
|
8
|
+
attr_reader :base_type_name, :map
|
9
|
+
attr_reader :base_type
|
10
|
+
|
11
|
+
# @param name [String]
|
12
|
+
# @param base_type_name [String]
|
13
|
+
# @param map [Hash<Object,String>]
|
14
|
+
def initialize(name, base_type_name, map)
|
15
|
+
super(name)
|
16
|
+
@base_type_name = base_type_name
|
17
|
+
@map = map
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param pkgs [Packages]
|
21
|
+
def resolve(pkgs)
|
22
|
+
@base_type = pkgs.type_for(base_type_name) || raise("#{base_type_name.inspect} not found")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
module GoonModelGen
|
4
|
+
module Golang
|
5
|
+
class Field
|
6
|
+
attr_reader :name, :type_name
|
7
|
+
attr_reader :tags # Hash<string,Array[string]> ex. for datastore, validate, json, etc...
|
8
|
+
attr_reader :goon_id # true/false
|
9
|
+
attr_reader :type
|
10
|
+
attr_accessor :struct
|
11
|
+
attr_accessor :prepare_method
|
12
|
+
|
13
|
+
def initialize(name, type_name, tags, goon_id: false)
|
14
|
+
@name, @type_name = name, type_name
|
15
|
+
@tags = tags || {}
|
16
|
+
@goon_id = goon_id
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param pkgs [Packages]
|
20
|
+
def resolve(pkgs)
|
21
|
+
@type = pkgs.type_for(type_name) || raise("#{type_name.inspect} not found for #{struct.qualified_name}.#{name}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def tags_string
|
25
|
+
tags.keys.sort.map do |key|
|
26
|
+
val = tags[key]
|
27
|
+
vals = val.is_a?(Array) ? val.join(',') : val.to_s
|
28
|
+
vals.empty? ? nil : "#{key}:\"#{vals}\""
|
29
|
+
end.compact.join(' ')
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param pkg [Package]
|
33
|
+
# @return [string]
|
34
|
+
def definition_in(pkg)
|
35
|
+
type_exp =
|
36
|
+
(type.package.path == pkg.path) ? type.name : type.qualified_name
|
37
|
+
"#{ name } #{ type_exp } `#{ tags_string }`"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/sentence"
|
4
|
+
|
5
|
+
module GoonModelGen
|
6
|
+
module Golang
|
7
|
+
class File
|
8
|
+
attr_reader :package, :name
|
9
|
+
attr_reader :sentences
|
10
|
+
attr_accessor :custom_suffix # false/true
|
11
|
+
|
12
|
+
# @param package [Package]
|
13
|
+
# @param name [string]
|
14
|
+
def initialize(package, name)
|
15
|
+
@package = package
|
16
|
+
@name = name
|
17
|
+
@sentences = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def new_sentence(template_path, type)
|
21
|
+
Sentence.new(template_path, type).tap do |s|
|
22
|
+
sentences.push(s)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/type"
|
4
|
+
|
5
|
+
module GoonModelGen
|
6
|
+
module Golang
|
7
|
+
class Modifier < Type
|
8
|
+
attr_reader :prefix, :target_name
|
9
|
+
attr_reader :target
|
10
|
+
def initialize(prefix, target)
|
11
|
+
@prefix = prefix
|
12
|
+
case target
|
13
|
+
when Type
|
14
|
+
@target = target
|
15
|
+
@target_name = target.name
|
16
|
+
else
|
17
|
+
@target = nil
|
18
|
+
@target_name = target.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def package
|
23
|
+
target.package
|
24
|
+
end
|
25
|
+
|
26
|
+
def name
|
27
|
+
prefix + target.name
|
28
|
+
end
|
29
|
+
|
30
|
+
def qualified_name
|
31
|
+
prefix + target.qualified_name
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param pkgs [Packages]
|
35
|
+
def resolve(pkgs)
|
36
|
+
return if target
|
37
|
+
@target = pkgs.type_for(target_name) || raise("#{target_name.inspect} not found")
|
38
|
+
end
|
39
|
+
|
40
|
+
PATTERN = /\A\*|\A\[\d*\]/
|
41
|
+
|
42
|
+
class << self
|
43
|
+
# @param s [String]
|
44
|
+
# @return [Proc]
|
45
|
+
def parse(s)
|
46
|
+
parts = parse_expression(s)
|
47
|
+
t = yield(parts.shift)
|
48
|
+
return nil unless t
|
49
|
+
parts.each do |part|
|
50
|
+
t = new(part, t)
|
51
|
+
end
|
52
|
+
t
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param s [String]
|
56
|
+
# @return [Array<String>]
|
57
|
+
def parse_expression(s)
|
58
|
+
m = s.match(PATTERN)
|
59
|
+
m.nil? ? [s] : parse_expression(s.sub(PATTERN, '')) + [m[0]]
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/type"
|
4
|
+
|
5
|
+
module GoonModelGen
|
6
|
+
module Golang
|
7
|
+
class NamedSlice < Type
|
8
|
+
attr_reader :base_type_name
|
9
|
+
attr_reader :base_type
|
10
|
+
|
11
|
+
# @param name [String]
|
12
|
+
# @param base_type_name [String]
|
13
|
+
def initialize(name, base_type_name)
|
14
|
+
super(name)
|
15
|
+
@base_type_name = base_type_name
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param pkgs [Packages]
|
19
|
+
def resolve(pkgs)
|
20
|
+
@base_type = pkgs.type_for(base_type_name) || raise("#{base_type_name.inspect} not found")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "goon_model_gen"
|
2
|
+
|
3
|
+
require "goon_model_gen/golang/struct"
|
4
|
+
require "goon_model_gen/golang/enum"
|
5
|
+
require "goon_model_gen/golang/named_slice"
|
6
|
+
require "goon_model_gen/golang/file"
|
7
|
+
|
8
|
+
module GoonModelGen
|
9
|
+
module Golang
|
10
|
+
class Package
|
11
|
+
attr_reader :path
|
12
|
+
attr_reader :types
|
13
|
+
attr_reader :files
|
14
|
+
|
15
|
+
# @param path [String]
|
16
|
+
def initialize(path)
|
17
|
+
@path = path
|
18
|
+
@types = []
|
19
|
+
@files = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def basename
|
23
|
+
@basename ||= path ? ::File.basename(path, '.*') : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def name
|
27
|
+
@name ||= basename ? basename.gsub(/[\-\_]/, '').downcase : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def add(type)
|
31
|
+
types.push(type)
|
32
|
+
type.package = self
|
33
|
+
end
|
34
|
+
|
35
|
+
def new_struct(name)
|
36
|
+
Struct.new(name).tap{|s| add(s) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param name [string]
|
40
|
+
# @param base_type [String]
|
41
|
+
# @param map [Hash<Object,Hash>] elements of enum from YAML
|
42
|
+
# @return [Enum]
|
43
|
+
def new_enum(name, base_type, map)
|
44
|
+
Enum.new(name, base_type, map).tap{|s| add(s) }
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param name [string]
|
48
|
+
# @param base_type_name [String]
|
49
|
+
# @return [Slice]
|
50
|
+
def new_named_slice(name, base_type_name)
|
51
|
+
NamedSlice.new(name, "[]#{base_type_name}").tap{|s| add(s) }
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param name [string]
|
55
|
+
# @return [File]
|
56
|
+
def find_or_new_file(name)
|
57
|
+
files.detect{|f| f.name == name} || new_file(name)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param name [string]
|
61
|
+
# @return [File]
|
62
|
+
def new_file(name)
|
63
|
+
File.new(self, name).tap do |f|
|
64
|
+
files.push(f)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Hash<String,Type>]
|
69
|
+
def name_to_type_map
|
70
|
+
@name_to_type_map ||= types.each_with_object({}) do |t,d|
|
71
|
+
d[t.name] = t
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param name [string]
|
76
|
+
# @param [Type]
|
77
|
+
def lookup(name)
|
78
|
+
name_to_type_map[name]
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|