PageRenderTime 83ms CodeModel.GetById 35ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/generate_spec.rb

https://bitbucket.org/hacman/quickfix
Ruby | 401 lines | 383 code | 17 blank | 1 comment | 25 complexity | 66a393c48cdebb211c8cb8f3413c5b76 MD5 | raw file
  1# -*- coding: utf-8 -*-
  2require "rexml/document"
  3
  4class DataDictionary
  5  def initialize( major, minor, sp )
  6    filesp = ""
  7    
  8    if( sp != 0 )
  9      filesp = "SP" + sp.to_s
 10    end
 11    
 12    filename = "FIX#{major}#{minor}#{filesp}.xml"
 13    @f = File.new( filename, File::CREAT|File::TRUNC|File::RDWR )
 14    @major = major
 15    @minor = minor
 16    @sp = sp
 17
 18    directory = "FIX.#{major}.#{minor}"
 19    if( sp != 0 )
 20      directory = directory + "SP#{sp}"
 21    end
 22    directory += "/Base"
 23
 24    @fieldsDoc = REXML::Document.new( File.new( "#{directory}/Fields.xml" ) )
 25    @enumsDoc = REXML::Document.new( File.new( "#{directory}/Enums.xml" ) )
 26    @msgContentsDoc = REXML::Document.new( File.new("#{directory}/MsgContents.xml") )
 27    @msgTypeDoc = REXML::Document.new( File.new("#{directory}/MsgType.xml") )
 28    @componentsDoc =  REXML::Document.new( File.new("#{directory}/Components.xml") )
 29    
 30    @specDoc = REXML::Document.new()
 31    
 32    @tagToField = Hash.new
 33    @tagToEnum = Hash.new
 34    @msgIdToMsgType = Hash.new
 35    @msgIdToMsgContents = Hash.new
 36    @msgIdToTags = Hash.new
 37    @componentNameToMsgId = Hash.new
 38
 39    puts filename
 40    parseDictionary
 41    printDictionary
 42  end
 43
 44  def tagShouldBeSkipped( tag )
 45    return true if tag == 101
 46    return true if tag == 261
 47    return true if tag == 809
 48  end
 49
 50  def tagShouldNotPrint( tag )
 51  end
 52  
 53  def enumsShouldBeSkipped( tag )
 54    return true if tagShouldBeSkipped( tag )
 55    return true if tag == 264
 56  end
 57  
 58  def addEnumsToTag( tag )
 59    enumArray = Array.new
 60    
 61    if( tag == 156 )
 62      enumArray.push( ["M","MULTIPLY"] )
 63      enumArray.push( ["D","DIVIDE"] )
 64    else
 65      return
 66    end
 67    
 68    @tagToEnum[ tag ] = enumArray
 69  end
 70  
 71  def toFieldName( fieldName, type )
 72    fieldName = fieldName.split(" (")[0].split("(")[0].strip.gsub(' ', '')
 73    fieldName.gsub!("UnitofMeasure", "UnitOfMeasure")
 74    fieldName = "#{fieldName}#{type.capitalize}" if fieldName == "HaltReason"
 75    return fieldName
 76  end
 77  
 78  def toMessageName( messageName )
 79    messageName = messageName.split("(")[0].delete("& -/’_")
 80    return "NewOrderSingle" if messageName == "OrderSingle"
 81    return "NewOrderList" if messageName == "OrderList"
 82    return "DontKnowTrade" if messageName == "DontKnowTradeDK"
 83    return messageName
 84  end
 85  
 86  def toDescription( description )
 87    return "" if description == nil
 88    old = description.clone
 89    description.upcase!
 90    description = description.split("(")[0]
 91    return "" if description == nil
 92    description.strip!
 93    description.gsub!('"', '')
 94    description.gsub!('+ ', '+')
 95    description.gsub!(',', '_')
 96    description.gsub!(' ', '_')
 97    description.gsub!('-', '_')
 98    description.gsub!('–', '')
 99    description.gsub!('/', '_')
100    description.gsub!('+', ' PLUS ')
101    description.gsub!("'", '')
102    description.gsub!("", '')
103    description.gsub!("", '')
104    description.gsub!("&", '')
105    description.gsub!('<', '')
106    description.gsub!('>', '')
107    description.gsub!('[', '')
108    description.gsub!(']', '')
109    description.gsub!('=', '')
110    description.gsub!('"', '')
111    description.gsub!('.', '')
112    description.gsub!(':', '')
113    description.gsub!(';', '')
114    description.gsub!('%', '')
115    description.gsub!('*', '')
116    description.gsub!('_', ' ')
117    description.strip!
118    description.gsub!(' ', '_')
119    description = description.split("___")[0]
120    description.squeeze!("_") if description != nil
121    description.gsub!('NOT_ASSIGNED_', '') if description != nil
122    return "FULL_REFRESH" if description == "FULL_REFERSH"
123    return "INCREMENTAL_REFRESH" if description == "INCREMENTAL_REFRES"
124    return description
125  end
126
127  def toType( type )
128    type = type.gsub('-', '')
129    return "NUMINGROUP" if type == "NUMINGRP"
130    return "LOCALMKTDATE" if type == "LOCALMMKTDATE"
131    return "QTY" if type == "QUANTITY"
132    return type
133  end
134  
135  def parseFields
136    @fieldsDoc.elements["dataroot"].elements.each("Fields") { |fieldsElement|
137      tag = fieldsElement.elements["Tag"].text.to_i
138      type = fieldsElement.elements["Type"].text
139      next if type == nil
140      type.upcase!
141      
142      next if tagShouldBeSkipped( tag )
143      addEnumsToTag( tag )
144      
145      fieldHash = Hash.new
146      fieldHash[ "type" ] = toType( type )
147      fieldName = toFieldName(fieldsElement.elements["FieldName"].text, type)
148      fieldHash[ "fieldName" ] = fieldName
149      
150      @tagToField[ tag ] = fieldHash
151    }
152  end
153
154  def parseEnums
155    enums = Hash.new
156    @enumsDoc.elements["dataroot"].elements.each("Enums") { |enumsElement|
157      tag = enumsElement.elements["Tag"].text.to_i
158      next if enumsShouldBeSkipped( tag )
159      
160      enum = enumsElement.elements["Enum"].text
161      next if enum.upcase == "(NOT SPECIFIED)"
162      
163      description = toDescription(enumsElement.elements["Description"].text)
164      description = toDescription(enum) if description == nil
165      next if description == nil
166      
167      if( tag != 206 )
168        if( !enums.has_key?(tag) )
169          enums[tag] = Array.new
170        end
171        
172        enumArray = enums[tag]
173        enumArray.push( [enum,description] )
174        @tagToEnum[ tag ] = enumArray
175      end
176    }
177  end
178
179  def parseMsgType
180    @msgTypeDoc.elements["dataroot"].elements.each("MsgType") { |msgTypeElement|
181      msgId = msgTypeElement.elements["MsgID"].text.to_i
182      msgType = msgTypeElement.elements["MsgType"].text
183      messageName = toMessageName(msgTypeElement.elements["MessageName"].text)
184      componentType = msgTypeElement.elements["ComponentType"].text
185      category = msgTypeElement.elements["Category"].text
186      
187      category = category == "Session" ? "admin" : "app"
188      
189      msgTypeHash = Hash.new
190      msgTypeHash[ "msgtype" ] = msgType
191      msgTypeHash[ "name" ] = messageName
192      msgTypeHash[ "msgcat" ] = category
193      @msgIdToMsgType[ msgId ] = msgTypeHash
194    }
195  end
196
197  def parseMsgContents
198    @msgContentsDoc.elements["dataroot"].elements.each("MsgContents") { |msgContentsElement|
199      tagsInMsg = []
200      msgId = msgContentsElement.elements["MsgID"].text.to_i
201      tagText = msgContentsElement.elements["TagText"].text
202      next if tagText == "StandardHeader"
203      next if tagText == "StandardTrailer"
204      tag = tagText.to_i
205      indent = msgContentsElement.elements["Indent"].text.to_i
206      required = msgContentsElement.elements["Reqd"].text.to_i == 1 ? "Y" : "N"
207      position = msgContentsElement.elements["Position"].text.to_i
208      
209      if( tag == 1017 && msgId != 1005 )
210        next
211      end
212
213      if( !@msgIdToMsgContents.has_key?(msgId) )
214        @msgIdToTags[ msgId ] = Hash.new
215        @msgIdToMsgContents[msgId] = Array.new
216      end
217      
218      msgContentsArray = @msgIdToMsgContents[msgId]
219      
220      if( tag == 0 )
221        msgContentsArray.push( [tagText, tagText, indent, required] )
222        @msgIdToMsgContents[ msgId ] = msgContentsArray
223        next
224      end
225
226      next if !@tagToField.has_key?(tag)
227      name = @tagToField[ tag ]["fieldName"]
228
229      if( !@msgIdToTags[ msgId ].has_key?(tag) )
230        @msgIdToTags[ msgId ][ tag ] = tag
231        msgContentsArray.push( [tag,name,indent,required] )
232      end
233
234      @msgIdToMsgContents[ msgId ] = msgContentsArray
235    }
236  end
237  
238  def parseComponents
239    @componentsDoc.elements["dataroot"].elements.each("Components") { |componentsElement|
240      msgId = componentsElement.elements["MsgID"].text.to_i
241      name = componentsElement.elements["ComponentName"].text
242      @componentNameToMsgId[ name ] = msgId
243    }	
244  end
245  
246  def parseDictionary
247    parseFields
248    parseEnums
249    parseMsgType
250    parseMsgContents
251    parseComponents
252  end
253  
254  def printVersion
255    return @specDoc.add_element( "fix", { "type" => "FIX", "major" => @major.to_s, "minor" => @minor.to_s, "servicepack" => @sp.to_s } )
256  end
257  
258  def printFields
259    @fieldsElement = @fixElement.add_element( "fields" )
260    @tagToField.sort.each { |tag, fieldHash|
261      next if fieldHash == nil
262      next if tagShouldNotPrint( tag )
263      type = fieldHash[ "type" ]
264      fieldName = fieldHash[ "fieldName" ]
265      fieldElement = @fieldsElement.add_element( "field", { "number" => tag.to_s, "name" => fieldName, "type" => type } )
266      printEnums( fieldElement, tag )
267    }
268  end
269
270  def printEnums( fieldElement, tag )
271    return if !@tagToEnum.has_key?( tag )
272    
273    enumArray = @tagToEnum[ tag ]
274    
275    isBool = false
276    if( enumArray.size == 2 )
277      isBool = enumArray[0][0] == "Y" || enumArray[0][0] == "N"
278      isBool = enumArray[1][0] == "Y" || enumArray[1][0] == "N"
279    end
280    
281    descriptions = Hash.new
282    enumArray.each_index { |index|
283      description = enumArray[index][1]
284      if( !descriptions.has_key?(description) )
285        descriptions[description] = 1
286      else
287        descriptions[description] = descriptions[description] + 1
288      end
289    }
290    
291    enumArray.each_index { |index|
292      enum = enumArray[index][0]
293      description = enumArray[index][1]
294      
295      if( descriptions[description] > 1 )
296        description = description + "_" + enum
297      end
298      next if description == nil
299      description = "YES" if isBool && enum == "Y"
300      description = "NO" if isBool && enum == "N"
301      fieldElement.add_element( "value", { "enum" => enum, "description" => description } )
302    }
303  end
304  
305  def printComponents
306    componentsElement = @fixElement.add_element( "components" )
307    @componentNameToMsgId.each { |name, msgId|
308      next if name == "StandardHeader"
309      next if name == "StandardTrailer"
310      msgContentsArray = @msgIdToMsgContents[msgId]
311      componentElement = componentsElement.add_element( "component", { "name" => name } )
312      printMsgContents( msgContentsArray, componentElement ) 
313    }
314  end
315
316  def printMessages
317    messagesElement = @fixElement.add_element( "messages" )
318    @msgIdToMsgType.sort.each { |msgId, msgTypeHash|
319      next if msgTypeHash == nil
320      name = msgTypeHash[ "name" ]
321      msgtype = msgTypeHash[ "msgtype" ]
322      msgcat = msgTypeHash[ "msgcat" ]
323      
324      if( @major >= 5 && msgcat == "admin" )
325        next
326      end
327      
328      msgContentsArray = @msgIdToMsgContents[msgId]
329      
330      messageElement = messagesElement.add_element( "message", { "name" => name, "msgtype" => msgtype, "msgcat" => msgcat } )
331
332      next if msgContentsArray == nil
333      printMsgContents( msgContentsArray, messageElement )	
334    }
335  end
336  
337  def printMsgContents( msgContentsArray, messageElement )
338    queue = Array.new
339    queue.push( messageElement )
340    nextIndent = 0
341    lastIndent = 0
342    messageName = messageElement.attributes["name"]
343    msgContentsArray.each_index { |index|
344      tag = msgContentsArray[index][0]
345      name = msgContentsArray[index][1]
346      indent = msgContentsArray[index][2]
347      required = msgContentsArray[index][3]
348      nextIndent = msgContentsArray[index+1][2] if msgContentsArray[index+1] != nil
349
350      if(@major == 5 && messageName == "InstrumentLeg" && name == "LegPrice")
351        next
352      end
353
354      if( indent < lastIndent )
355        queue.pop
356      end
357      
358      if( nextIndent > indent )
359        groupElement = queue.last.add_element( "group", "name" => name, "required" => required )
360        queue.push( groupElement )
361        lastIndent = indent
362        next
363      end
364      
365      if(tag.class == String)
366        componentElement = queue.last.add_element( "component", "name" => name, "required" => required )
367      else
368        fieldElement = queue.last.add_element( "field", "name" => name, "required" => required )
369      end
370      lastIndent = indent
371    }
372  end
373  
374  def printHeader
375    headerElement = @fixElement.add_element( "header" )
376    return if @major >= 5
377    msgContentsArray = @msgIdToMsgContents[@componentNameToMsgId["StandardHeader"]]
378    printMsgContents( msgContentsArray, headerElement ) 
379  end
380  
381  def printTrailer
382    trailerElement = @fixElement.add_element( "trailer" )
383    return if @major >= 5
384    msgContentsArray = @msgIdToMsgContents[@componentNameToMsgId["StandardTrailer"]]
385    printMsgContents( msgContentsArray, trailerElement ) 
386  end
387  
388  def printDictionary
389    @fixElement = printVersion
390    printHeader
391    printMessages
392    printTrailer
393    printComponents
394    printFields
395    @specDoc.write( @f, 1, false, true )
396  end
397end
398
399(0..4).each { |i| DataDictionary.new( 4, i, 0 ) }
400(0..2).each { |i| DataDictionary.new( 5, 0, i ) }
401DataDictionary.new( 5, 0, 0 )