Module: DataMetaProtobuf
- Defined in:
- lib/dataMetaProtobuf.rb
Overview
Constant Summary collapse
- VERSION =
Current version
'1.0.2'
- INDENT =
First level indent
' ' * 4
- L =
Since we are piping source in and spilling the result into the STDOUT, need logger for any other output.
Logger.new('dataMetaProtobuf.log', 0, 10_000_000)
- GEM_ROOT =
The root of the gem.
File.realpath(File.dirname(__FILE__) + '/../')
- TMPL_ROOT =
Location of templates.
File.join(GEM_ROOT, 'tmpl')
- PROTO_TYPES =
Mapping from a DataMeta DOM type to a matching renderer of Protobuf IDL.
{ DataMetaDom::BOOL => lambda{|dt| %q<bool>}, DataMetaDom::CHAR => lambda{|dt| %q<string>}, DataMetaDom::INT => lambda{ |dt| len = dt.length case when len <= 4; %q<int32> when len <= 8; %q<int64> else; raise "Invalid integer length #{len}" end }, DataMetaDom::FLOAT => lambda{|dt| len = dt.length case when len <= 4; %q<float> when len <= 8; %q<double> else; raise "Invalid float length #{len}" end }, DataMetaDom::RAW => lambda{|dt| %q<bytes>}, DataMetaDom::STRING => lambda{|dt| %q<string>}, =begin Unlike DataMeta DOM, Protobuf does not support temporal types such as date, time and datetime, therefore we export DataMeta +datetime+ as +string+. =end DataMetaDom::DATETIME => lambda{|dt| %q<string>}, # No support for these in this release: #NUMERIC => lambda{|t| "BigDecimal"} }
Class Method Summary collapse
-
.assertNamespace(fullName) ⇒ Object
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.
-
.genSchema(model) ⇒ Object
Generates the Protobuf IDL, returns the source.
-
.helpProtobufGen(file, errorText = nil) ⇒ Object
Shortcut to help for the Protobuf IDL generator.
-
.protoType(dataMetaType, model, rec) ⇒ Object
Converts DataMeta DOM type to Protobuf IDL type.
-
.renderEnum(model, enm, result) ⇒ Object
Render one single enum.
-
.renderRec(model, rec, result) ⇒ Object
Render a single record.
Class Method Details
.assertNamespace(fullName) ⇒ Object
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']
95 96 97 98 |
# File 'lib/dataMetaProtobuf.rb', line 95 def assertNamespace(fullName) ns, base = DataMetaDom::splitNameSpace(fullName) [DataMetaDom.validNs?(ns, base) ? ns : '', base] end |
.genSchema(model) ⇒ Object
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…
106 107 108 109 110 111 112 113 114 115 116 117 118 |
# 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 |
.helpProtobufGen(file, errorText = nil) ⇒ Object
Shortcut to help for the Protobuf IDL generator
177 178 179 |
# 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 |
.protoType(dataMetaType, model, rec) ⇒ Object
Converts DataMeta DOM type to Protobuf IDL type.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# 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 |
.renderEnum(model, enm, result) ⇒ Object
Render one single enum
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# 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 |
.renderRec(model, rec, result) ⇒ Object
Render a single record
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# 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 |