meta-record 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 20cb8eea318a55b539b48eca34a554755cb624a6944180cd7dc611591f4db39d
4
+ data.tar.gz: 36933fe0fde7d856c30b6c6a50b1c0d1aa8bf2fa660989a54844398eeac3606f
5
+ SHA512:
6
+ metadata.gz: e43594ecafa0f39f5a11f8450ec9c2a2fd5dddf2a3ffd9208dec9cd62402d3c436acdc9b260d1bd668da6a7a7a170f139bb5f76032d611fc56ffc894dbf83b57
7
+ data.tar.gz: 1668284a722f57efcecfc0ea220c3103e1dd1b52358881f96823347444165c7828755b0a175b6b31425db8be6ade028afc3ea55616f8d607abd0b3b1fd34c63d
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'metarecord/runner'
4
+
5
+ include MetaRecordRunner
6
+
7
+ Dir["config/metarecord.rb"].each do |file|
8
+ require "#{Dir.pwd}/#{file}"
9
+ end
10
+
11
+ @base_path = ""
12
+ @output = ""
13
+ @input = []
14
+ @generators = []
15
+ @tmpdir = ".tmp"
16
+
17
+ OptionParser.new do |opts|
18
+ opts.on "-o PATH", "--output-path=PATH" do |v| @output = v end
19
+ opts.on "-b PATH", "--base-path=PATH" do |v| @base_path = v end
20
+ opts.on "-i PATH", "--source-path=PATH" do |v| @input = v.split(",") end
21
+ opts.on "-g GENERATORS", "--use=GENERATORS" do |v| @generators = v.split(",") end
22
+ opts.on "-z PATH", "--tmp-dir=PATH" do |v| @tmpdir = v end
23
+ opts.on "-l", "--list-generators" do
24
+ root = Gem::Specification.find_by_name("meta-record").gem_dir + "/lib/metarecord/generators/"
25
+ list = Dir[root + "**/*"]
26
+ .select {|file| file =~ /.*_generator\.rb$/}
27
+ .collect{|file| file.gsub(root, '')}
28
+ .collect{|file| file.gsub /(.*)_generator.rb$/, '\1'}
29
+ puts (list.join "\n")
30
+ exit
31
+ end
32
+ opts.on "-h" "--help" do
33
+ puts opts
34
+ exit
35
+ end
36
+ end.parse!
37
+
38
+ def check_options
39
+ if @output.nil?
40
+ puts "/!\\ Output path not specified"
41
+ elsif @input.empty?
42
+ puts "/!\\ You must provide at least one source directory"
43
+ elsif @generators.empty?
44
+ puts "/!\\ You nust specify at least one generator to use"
45
+ else
46
+ return true
47
+ end
48
+ return false
49
+ end
50
+
51
+ exit -1 unless check_options
52
+
53
+ run_all
@@ -0,0 +1,22 @@
1
+ require 'metarecord/runner'
2
+
3
+ Dir["config/metarecord.rb"].each do |file|
4
+ require "#{Dir.pwd}/#{file}"
5
+ end
6
+
7
+ module ::Guard
8
+ class MetaRecord < Plugin
9
+ include MetaRecordRunner
10
+
11
+ def initialize options = {}
12
+ super
13
+ @base_path = options[:base_path]
14
+ @input = options[:input]
15
+ @output = options[:output]
16
+ @generators = options[:generators]
17
+ @odb_connection = options[:odb_connection]
18
+ @input = [@input] if @input.class != Array
19
+ @tmpdir = ".tmp"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,197 @@
1
+ class String
2
+ def underscore
3
+ self.gsub(/::/, '/').
4
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
5
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
6
+ tr("-", "_").
7
+ downcase
8
+ end
9
+
10
+ def camelcase
11
+ return self if self !~ /_/ && self =~ /[A-Z]+.*/
12
+ split(/_|\//).map{|e| e.capitalize}.join
13
+ end
14
+ end
15
+
16
+ require 'pathname'
17
+ require 'json'
18
+
19
+ class GeneratorBase
20
+ def self.is_file_based? ; true ; end
21
+
22
+ class << self
23
+ attr_accessor :odb_connection
24
+
25
+ def prepare inputs_dir, output_dir, base_path
26
+ @base_path = base_path
27
+ @output_dir = output_dir
28
+ Includes.reset
29
+ Model.reset
30
+ inputs_dir.each do |input_dir|
31
+ load_all_models input_dir
32
+ end
33
+ end
34
+
35
+ def use generator_class
36
+ if generator_class.is_file_based?
37
+ _use_by_files generator_class
38
+ else
39
+ _use_by_models generator_class
40
+ end
41
+ end
42
+
43
+ def _use_by_models generator_class
44
+ Model.list.each do |model|
45
+ generator = generator_class.new
46
+ next unless generator.should_generate_for(model)
47
+ data = { bodies: [generator.generate_for(model)] }
48
+ data[:headers] = [generator.get_headers] if generator.methods.include? :get_headers
49
+ source = generator_class.make_file model[:filename], data
50
+ dirname = File.dirname model[:filename]
51
+ dirname.gsub! /^#{@base_path}/, '' unless @base_path.nil?
52
+ filepath = "#{@output_dir}/" + dirname
53
+ filename = model[:name].underscore + generator_class.extension
54
+ `mkdir -p #{filepath}`
55
+ File.open "#{filepath}/#{filename}", 'w' do |f|
56
+ f.write source
57
+ end
58
+ end
59
+ end
60
+
61
+ def _use_by_files generator_class
62
+ files = {}
63
+ Model.list.each do |model|
64
+ generator = generator_class.new
65
+ next unless generator.should_generate_for(model)
66
+ files[model[:filename]] ||= {}
67
+ filedata = files[model[:filename]]
68
+ filedata[:headers] ||= []
69
+ filedata[:bodies] ||= []
70
+ filedata[:bodies] << generator.generate_for(model)
71
+ if generator.methods.include? :get_headers
72
+ filedata[:headers] << generator.get_headers
73
+ end
74
+ end
75
+ files.each do |key,value|
76
+ source = generator_class.make_file key, value
77
+ path = generator_class.sourcefile_to_destfile key
78
+ path.gsub! /^#{@base_path}/, '' unless @base_path.nil?
79
+ `mkdir -p #{@output_dir}/#{File.dirname path}`
80
+ File.open "#{@output_dir}/#{path}", 'w' do |f|
81
+ f.write source
82
+ end
83
+ end
84
+ end
85
+
86
+ def sourcefile_to_destfile sourcefile
87
+ sourcepath = Pathname.new(sourcefile)
88
+ extension = sourcepath.extname
89
+ sourcefile[0...-extension.length] + self.extension
90
+ end
91
+ end
92
+
93
+ def should_generate_for object
94
+ true
95
+ end
96
+
97
+ def should_generate_from_manifest
98
+ false
99
+ end
100
+
101
+ def reset
102
+ @tab_size = 2
103
+ @indent = 0
104
+ @src = ""
105
+ end
106
+
107
+ def indent &block
108
+ @indent += 1
109
+ block.call
110
+ @indent -= 1
111
+ end
112
+
113
+ def unindent &block
114
+ @indent -= 1
115
+ block.call
116
+ @indent += 1
117
+ end
118
+
119
+ def make_block delimiters = '{}', &block
120
+ _append delimiters[0] if delimiters.size > 0
121
+ indent block
122
+ _append delimiters[1] if delimiters.size > 1
123
+ end
124
+
125
+ def _append str, opts = {}
126
+ @src += " " * (@indent * @tab_size)
127
+ @src += str
128
+ @src += "\n" unless opts[:no_line_return]
129
+ end
130
+
131
+ def ptr_type type
132
+ "std::shared_ptr<#{type}>"
133
+ end
134
+
135
+ def get_value value
136
+ if value.class == Symbol
137
+ value.to_s
138
+ else
139
+ value.inspect
140
+ end
141
+ end
142
+
143
+ def get_type type
144
+ type = "::#{type}" unless type.start_with? "::"
145
+ type += " " if type[type.size - 1] == ">"
146
+ type
147
+ end
148
+
149
+ def get_singular_name name
150
+ if not (name =~ /ies$/).nil?
151
+ name[0...name.size-3] + "y"
152
+ elsif (name =~ /(s|x)es$/).nil?
153
+ name[0...name.size-1]
154
+ else
155
+ name[0...name.size-2]
156
+ end
157
+ end
158
+
159
+ def get_pluralized_name name
160
+ if not (name =~ /holiday/i).nil?
161
+ name + "s"
162
+ elsif not (name =~ /y$/).nil?
163
+ name[0...name.size-1] + "ies"
164
+ elsif not (name =~ /(s|x)$/).nil?
165
+ name + "es"
166
+ else
167
+ name + "s"
168
+ end
169
+ end
170
+
171
+ def get_classname object
172
+ "#{METARECORD_NAMESPACE}::#{object[:name]}"
173
+ end
174
+
175
+ def id_type
176
+ if defined? METARECORD_ID_TYPE
177
+ METARECORD_ID_TYPE
178
+ else
179
+ "ODB::id_type"
180
+ end
181
+ end
182
+
183
+ def null_id
184
+ if defined? METARECORD_NULL_ID
185
+ METARECORD_NULL_ID
186
+ else
187
+ "ODB_NULL_ID"
188
+ end
189
+ end
190
+
191
+ def visibility name ;; end
192
+ def resource_name name ;; end
193
+ def order_by name, flow = nil ;; end
194
+ def property type, name, options = {} ;; end
195
+ def has_one type, name, options = {} ;; end
196
+ def has_many type, name, options = {} ;; end
197
+ end
@@ -0,0 +1,150 @@
1
+ require 'metarecord/model'
2
+ require 'metarecord/generator_base'
3
+
4
+ class AureliaGenerator < GeneratorBase
5
+ def reset
6
+ super
7
+ @state = nil
8
+ @relations = {}
9
+ @fields = []
10
+ end
11
+
12
+ def generate_for object
13
+ reset
14
+ @class_name = object[:name] + "Data"
15
+ generate_class object
16
+ generate_global_scope object
17
+ generate_fields object
18
+ @src
19
+ end
20
+
21
+ def generate_global_scope object
22
+ @state = :global_scope
23
+ self.instance_eval &object[:block]
24
+ end
25
+
26
+ def generate_class object
27
+ _append "export class #{@class_name} extends Model {"
28
+ @indent += 1
29
+ _append "constructor() {"
30
+ _append " super();"
31
+ _append "}"
32
+
33
+ @state = :class_scope
34
+ self.instance_eval &object[:block]
35
+ @indent -= 1
36
+ _append "}\n"
37
+ end
38
+
39
+ def generate_fields object
40
+ @state = :field_scope
41
+ _append "#{@class_name}.fields = ["
42
+ @indent += 1
43
+ @fields = []
44
+ self.instance_eval &object[:block]
45
+ @indent -= 1
46
+ @src += "\n"
47
+ _append "];"
48
+ _append "Fields.inject(#{@class_name}.fields);"
49
+ _append "#{@class_name}.fields._mapFields();"
50
+ end
51
+
52
+ def order_by name
53
+ if @state == :global_scope
54
+ _append "#{@class_name}.defaultOrderBy = \"#{name}\""
55
+ end
56
+ end
57
+
58
+ def property type, name, options = {}
59
+ return if not options[:client].nil? and options[:client][:ignore] == true
60
+ if @state == :field_scope
61
+ type = cppToJsType type
62
+ unless options[:client].nil?
63
+ type = options[:client][:type] unless options[:client][:type].nil?
64
+ end
65
+ @src += ",\n" if @fields.count > 0
66
+ field = { name: name, type: type }
67
+ field[:default] = options[:default] if not options[:default].nil?
68
+ if not options[:validate].nil?
69
+ field[:min] = options[:validate][:min] unless options[:validate][:min].nil?
70
+ field[:max] = options[:validate][:max] unless options[:validate][:max].nil?
71
+ field[:required] = options[:validate][:required] unless options[:validate][:required].nil?
72
+ end
73
+ @fields << field
74
+ _append field.to_json, no_line_return: true
75
+ end
76
+ end
77
+
78
+ def has_one type, name, options = {}
79
+ return if options[:client] == false
80
+ type = type.split("::").last
81
+ if @state == :field_scope
82
+ @src += ",\n" if @fields.count > 0
83
+
84
+ field = { name: "#{name}_id", type: type, label: name }
85
+ if not options[:validate].nil?
86
+ field[:required] = options[:validate][:required] unless options[:validate][:required].nil?
87
+ end
88
+ @fields << field
89
+ _append field.to_json, no_line_return: true
90
+ end
91
+ end
92
+
93
+ def has_many type, name, options = {}
94
+ return if options[:client] == false
95
+ type = type.split("::").last
96
+ if @state == :field_scope
97
+ @src += ",\n" if @fields.count > 0
98
+ @fields << ({
99
+ name: "#{get_singular_name name}_ids",
100
+ type: "array[#{type}]",
101
+ label: name
102
+ })
103
+ _append @fields.last.to_json, no_line_return: true
104
+ end
105
+ end
106
+
107
+ def resource_name name
108
+ if @state == :global_scope
109
+ _append "#{@class_name}.scope = \"#{name}\";"
110
+ end
111
+ end
112
+
113
+ def cppToJsType type
114
+ case type
115
+ when 'std::string' then 'string'
116
+ when 'std::time_t' then 'timestamp'
117
+ when 'unsigned long' then 'integer'
118
+ when 'unsigned short' then 'integer'
119
+ when 'unsigned char' then 'integer'
120
+ when 'unsigned int' then 'integer'
121
+ when 'long' then 'integer'
122
+ when 'short' then 'integer'
123
+ when 'char' then 'integer'
124
+ when 'int' then 'integer'
125
+ when 'DataTree' then 'object'
126
+ when 'LocaleString' then 'locale-string'
127
+ else type
128
+ end
129
+ end
130
+
131
+ class << self
132
+ def extension ; ".js" ; end
133
+
134
+ def is_file_based? ; false ; end
135
+
136
+ def model_import_path
137
+ if defined? METARECORD_AURELIA_MODEL_IMPORT
138
+ METARECORD_AURELIA_MODEL_IMPORT
139
+ else
140
+ "aurelia-metarecord"
141
+ end
142
+ end
143
+
144
+ def make_file filename, data
145
+ src = "import {Model} from '#{model_import_path}';\n"
146
+ src += "import {Fields} from 'aurelia-metarecord';\n\n"
147
+ src + (data[:bodies].join "\n")
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,108 @@
1
+ require 'metarecord/model'
2
+ require 'metarecord/generator_base'
3
+
4
+ class CometArchiveGenerator < GeneratorBase
5
+ def self.is_file_based? ; false ; end
6
+
7
+ def reset
8
+ @src = ""
9
+ @declarations = []
10
+ super
11
+ end
12
+
13
+ def should_generate_for_object
14
+ (not object[:header].nil?) && (not object[:classname].nil?)
15
+ end
16
+
17
+ def generate_for object
18
+ reset
19
+ _append "#ifndef #{self.class.client_define}"
20
+ _append "# include <crails/renderer.hpp>"
21
+ _append "#endif"
22
+ _append "#include <crails/archive.hpp>"
23
+ _append "#include \"#{object[:header]}\"\n"
24
+ _append "void #{object[:classname]}::serialize(IArchive& archive)"
25
+ _append "{"
26
+ @src += " archive & id"
27
+ self.instance_eval &object[:block]
28
+ @src += ";\n"
29
+ _append "}\n"
30
+
31
+ _append "void #{object[:classname]}::serialize(OArchive& archive)"
32
+ _append "{"
33
+ @src += " archive & id"
34
+ self.instance_eval &object[:block]
35
+ @src += ";\n"
36
+ _append "}"
37
+
38
+ generate_archive_views object
39
+ end
40
+
41
+ def generate_archive_views object
42
+ @src += "\n"
43
+ ptr_type = "#{object[:classname]}*"
44
+ funcname_prefix = "render_#{object[:classname].gsub(/^::/,'').underscore}"
45
+ funcname = "#{funcname_prefix}_show_archive"
46
+ _append "#ifndef #{self.class.client_define}"
47
+ _append "std::string #{funcname}(const Crails::Renderer* renderer, Crails::SharedVars& vars)"
48
+ _append "{"
49
+ @indent += 1
50
+ _append "auto* model = Crails::cast<#{ptr_type}>(vars, \"model\");"
51
+ _append "OArchive archive;\n"
52
+ _append "model->serialize(archive);"
53
+ _append "return archive.as_string();"
54
+ @indent -= 1
55
+ _append "}\n"
56
+
57
+ funcname = "#{funcname_prefix}_index_archive"
58
+ _append "std::string #{funcname}(const Crails::Renderer* renderer, Crails::SharedVars& vars)"
59
+ _append "{"
60
+ @indent += 1
61
+ _append "auto* models = Crails::cast<std::vector<#{object[:classname]}>*>(vars, \"models\");"
62
+ _append "OArchive archive;"
63
+ _append "unsigned long size = models->size();\n"
64
+ _append "archive & size;"
65
+ _append "for (auto& model : *models)"
66
+ _append " model.serialize(archive);"
67
+ _append "return archive.as_string();"
68
+ @indent -= 1
69
+ _append "}"
70
+ _append "#endif"
71
+ end
72
+
73
+ def property type, name, options = {}
74
+ @src += " & #{name}"
75
+ end
76
+
77
+ def has_one type, name, options = {}
78
+ if options[:joined] != false
79
+ puts "WARNING: unsupported joined has_one in metarecord/generators/comet/archive_generator"
80
+ else
81
+ @src += " & #{name}_id"
82
+ end
83
+ end
84
+
85
+ def has_many type, name, options = {}
86
+ singular_name = get_singular_name name
87
+ if options[:joined] != false
88
+ puts "WARNING: unsupported joined has_many in metarecord/generators/comet/archive_generator"
89
+ else
90
+ @src += " & #{singular_name}_ids"
91
+ end
92
+ end
93
+
94
+ class << self
95
+ def client_define
96
+ "__COMET_CLIENT__"
97
+ end
98
+
99
+ def extension ; ".archive.cpp" ; end
100
+
101
+ def make_file filename, data
102
+ source = ""
103
+ source += (collect_includes_for filename).join("\n")
104
+ source += "\n" + (data[:bodies].join "\n")
105
+ source
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,77 @@
1
+ require 'metarecord/generators/crails/data_generator'
2
+
3
+ class CometDataGenerator < CrailsDataGenerator
4
+ def generate_class_head object
5
+ _append_macro "#ifndef #{self.class.client_define}"
6
+ super object
7
+ _append_macro "#else"
8
+ _append "struct #{object[:name]} : public #{self.class.client_super_class}"
9
+ _append_macro "#endif"
10
+ end
11
+
12
+ def prepare_order_by
13
+ _append_macro "#ifndef #{self.class.client_define}"
14
+ super
15
+ _append_macro "#endif"
16
+ end
17
+
18
+ def edit_resource_declaration
19
+ with_visibility :protected do
20
+ _append_macro "#ifdef #{self.class.client_define}"
21
+ _append "#{id_type} id = #{null_id};"
22
+ _append_macro "#endif"
23
+ end
24
+ _append_macro "#ifdef #{self.class.client_define}"
25
+ _append "#{id_type} get_id() const { return id; }"
26
+ _append "void set_id(#{id_type} value) { id = value; }"
27
+ _append "void from_json(Data data);"
28
+ _append "virtual std::vector<std::string> find_missing_parameters(Data) const;"
29
+ _append "virtual void edit(Data);"
30
+ _append "virtual std::string to_json() const;"
31
+ _append "virtual bool is_valid();"
32
+ _append_macro "#else"
33
+ super
34
+ _append_macro "#endif"
35
+ _append ""
36
+ end
37
+
38
+ def resource_name name
39
+ super name
40
+ _append_macro "#ifdef #{self.class.client_define}"
41
+ _append "std::string get_resource_name() const { return scope; }"
42
+ _append_macro "#endif"
43
+ end
44
+
45
+ def has_many_fetch list_type, name, options
46
+ with_visibility :public do
47
+ _append_macro "#ifdef #{self.class.client_define}"
48
+ _append "Comet::Promise fetch_#{name}();"
49
+ _append_macro "#else"
50
+ _append "void fetch_#{name}();"
51
+ _append_macro "#endif"
52
+ end
53
+ end
54
+
55
+ class << self
56
+ def client_define
57
+ "__COMET_CLIENT__"
58
+ end
59
+
60
+ def client_super_class
61
+ "MODELS_CLIENT_SUPER_CLASS"
62
+ end
63
+
64
+ def generate_includes
65
+ <<CPP
66
+ #{super}
67
+ #ifdef #{client_define}
68
+ # include <crails/comet/mvc/model.hpp>
69
+ # include <comet/promise.hpp>
70
+ # ifndef #{client_super_class}
71
+ # define #{client_super_class} Comet::JsonModel
72
+ # endif
73
+ #endif
74
+ CPP
75
+ end
76
+ end
77
+ end