module DataMetaProtobuf
For command line details either check the new method's source or the README, the usage section.
Constants
- GEM_ROOT
The root of the gem.
- INDENT
First level indent
- L
Since we are piping source in and spilling the result into the STDOUT, need logger for any other output.
- PROTO_TYPES
Mapping from a DataMeta DOM type to a matching renderer of Protobuf IDL.
- TMPL_ROOT
Location of templates.
- VERSION
Current version
Public Class Methods
Splits the full name of a class into the namespace and the base, returns an array of the namespace (empty string if there is no namespace on the name) and the base name.
Examples:
-
'BaseNameAlone'
->['', 'BaseNameAlone']
-
'one.package.another.pack.FinallyTheName'
->['one.package.another.pack', 'FinallyTheName']
# File lib/dataMetaProtobuf.rb, line 95 def assertNamespace(fullName) ns, base = DataMetaDom::splitNameSpace(fullName) [DataMetaDom.validNs?(ns, base) ? ns : '', base] end
Generates the Protobuf IDL, returns the source.
We decided against using the template and use simple string concatenation instead; because the way Protobuf IDL is designed, it's easier to do the string concat. For example, rendering a message in a message in a messageā¦
# File lib/dataMetaProtobuf.rb, line 106 def genSchema(model) result = %< // This Protobuf schema is generated by DataMeta exporter. syntax = "proto3"; package #{model.sources[model.sources.doneKeys[0]].namespace}; > model.enums.values.each { |e| renderEnum model, e, result } model.records.values.each { |r| renderRec model, r, result } result << "\n" result end
Shortcut to help for the Protobuf IDL generator
# File lib/dataMetaProtobuf.rb, line 177 def helpProtobufGen(file, errorText=nil) DataMetaDom::help(file, %<DataMeta DOM Protobuf IDL Generation ver #{VERSION}>, '<DataMeta DOM source file>', errorText) end
Converts DataMeta DOM type to Protobuf IDL type.
# File lib/dataMetaProtobuf.rb, line 72 def protoType(dataMetaType, model, rec) ty = dataMetaType.type if model.records[ty] nameSpace, base = assertNamespace(ty) base elsif model.enums[ty] nameSpace, base = assertNamespace(ty) base else renderer = PROTO_TYPES[dataMetaType.type] raise "Unsupported type #{dataMetaType}" unless renderer renderer.call(dataMetaType) end end
Render one single enum
# File lib/dataMetaProtobuf.rb, line 151 def renderEnum(model, enm, result) nameSpace, base = assertNamespace(enm.name) L.info("Rendering enum #{enm.name} of the type #{enm.class}") case enm when DataMetaDom::Enum values = enm.keys.map{|k| enm[k]} # sorted by ordinals to preserve the original order pbInt = 0 result << %< enum #{base} { > values.each{|v| result << "#{INDENT}#{v} = #{pbInt};\n" pbInt += 1 } result << %q<} > when DataMetaDom::Mapping # taken care of in renderDer else raise ArgumentError, %<Unsupported enum type "#{enm.class}" for the name "#{enm.name}"> end end
Render a single record
# File lib/dataMetaProtobuf.rb, line 121 def renderRec(model, rec, result) nameSpace, base = assertNamespace(rec.name) L.info("Rendering record #{rec.name}") result << %< message #{base} { > pbInt = 1 rec.fields.each_key { | fldId| fld = rec.fields[fldId] ty = fld.dataType.type if fld.aggr && !fld.map? result << "#{INDENT}repeated #{protoType(fld.dataType, model, rec)} #{fldId} = #{pbInt};\n" elsif fld.map? raise ArgumentError, %<Field "#{fldId}" of the rec "#{base}": for Protobuf, map can not be optional, it must be required> unless fld.isRequired result << "#{INDENT}map<#{protoType(fld.dataType, model, rec)}, #{protoType(fld.trgType, model, rec)}> #{fldId} = #{pbInt};\n" elsif model.enums[ty] && model.enums[ty].is_a?(DataMetaDom::Mapping) raise ArgumentError, %<Field "#{fldId}" of the rec "#{base}": for Protobuf, map can not be optional, it must be required> unless fld.isRequired result << "#{INDENT}map<#{protoType(model.enums[ty].fromT, model, rec)}, #{protoType(model.enums[ty].toT, model, rec)}> #{fldId} = #{pbInt};\n" elsif fld.isRequired result << "#{INDENT}#{protoType(fld.dataType, model, rec)} #{fldId} = #{pbInt};\n" else result << "#{INDENT}repeated #{protoType(fld.dataType, model, rec)} #{fldId} = #{pbInt};\n" end pbInt += 1 } result << %q<} > end
Private Instance Methods
Splits the full name of a class into the namespace and the base, returns an array of the namespace (empty string if there is no namespace on the name) and the base name.
Examples:
-
'BaseNameAlone'
->['', 'BaseNameAlone']
-
'one.package.another.pack.FinallyTheName'
->['one.package.another.pack', 'FinallyTheName']
# File lib/dataMetaProtobuf.rb, line 95 def assertNamespace(fullName) ns, base = DataMetaDom::splitNameSpace(fullName) [DataMetaDom.validNs?(ns, base) ? ns : '', base] end
Generates the Protobuf IDL, returns the source.
We decided against using the template and use simple string concatenation instead; because the way Protobuf IDL is designed, it's easier to do the string concat. For example, rendering a message in a message in a messageā¦
# File lib/dataMetaProtobuf.rb, line 106 def genSchema(model) result = %< // This Protobuf schema is generated by DataMeta exporter. syntax = "proto3"; package #{model.sources[model.sources.doneKeys[0]].namespace}; > model.enums.values.each { |e| renderEnum model, e, result } model.records.values.each { |r| renderRec model, r, result } result << "\n" result end
Shortcut to help for the Protobuf IDL generator
# File lib/dataMetaProtobuf.rb, line 177 def helpProtobufGen(file, errorText=nil) DataMetaDom::help(file, %<DataMeta DOM Protobuf IDL Generation ver #{VERSION}>, '<DataMeta DOM source file>', errorText) end
Converts DataMeta DOM type to Protobuf IDL type.
# File lib/dataMetaProtobuf.rb, line 72 def protoType(dataMetaType, model, rec) ty = dataMetaType.type if model.records[ty] nameSpace, base = assertNamespace(ty) base elsif model.enums[ty] nameSpace, base = assertNamespace(ty) base else renderer = PROTO_TYPES[dataMetaType.type] raise "Unsupported type #{dataMetaType}" unless renderer renderer.call(dataMetaType) end end
Render one single enum
# File lib/dataMetaProtobuf.rb, line 151 def renderEnum(model, enm, result) nameSpace, base = assertNamespace(enm.name) L.info("Rendering enum #{enm.name} of the type #{enm.class}") case enm when DataMetaDom::Enum values = enm.keys.map{|k| enm[k]} # sorted by ordinals to preserve the original order pbInt = 0 result << %< enum #{base} { > values.each{|v| result << "#{INDENT}#{v} = #{pbInt};\n" pbInt += 1 } result << %q<} > when DataMetaDom::Mapping # taken care of in renderDer else raise ArgumentError, %<Unsupported enum type "#{enm.class}" for the name "#{enm.name}"> end end
Render a single record
# File lib/dataMetaProtobuf.rb, line 121 def renderRec(model, rec, result) nameSpace, base = assertNamespace(rec.name) L.info("Rendering record #{rec.name}") result << %< message #{base} { > pbInt = 1 rec.fields.each_key { | fldId| fld = rec.fields[fldId] ty = fld.dataType.type if fld.aggr && !fld.map? result << "#{INDENT}repeated #{protoType(fld.dataType, model, rec)} #{fldId} = #{pbInt};\n" elsif fld.map? raise ArgumentError, %<Field "#{fldId}" of the rec "#{base}": for Protobuf, map can not be optional, it must be required> unless fld.isRequired result << "#{INDENT}map<#{protoType(fld.dataType, model, rec)}, #{protoType(fld.trgType, model, rec)}> #{fldId} = #{pbInt};\n" elsif model.enums[ty] && model.enums[ty].is_a?(DataMetaDom::Mapping) raise ArgumentError, %<Field "#{fldId}" of the rec "#{base}": for Protobuf, map can not be optional, it must be required> unless fld.isRequired result << "#{INDENT}map<#{protoType(model.enums[ty].fromT, model, rec)}, #{protoType(model.enums[ty].toT, model, rec)}> #{fldId} = #{pbInt};\n" elsif fld.isRequired result << "#{INDENT}#{protoType(fld.dataType, model, rec)} #{fldId} = #{pbInt};\n" else result << "#{INDENT}repeated #{protoType(fld.dataType, model, rec)} #{fldId} = #{pbInt};\n" end pbInt += 1 } result << %q<} > end