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