meta-record 1.0.1

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 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