stupidedi 1.1.0

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.
Files changed (500) hide show
  1. data/README.md +215 -0
  2. data/Rakefile +108 -0
  3. data/bin/edi-ed +71 -0
  4. data/bin/edi-pp +81 -0
  5. data/doc/Defining.md +0 -0
  6. data/doc/Generating.md +321 -0
  7. data/doc/LICENSE.md +0 -0
  8. data/doc/Navigating.md +645 -0
  9. data/doc/Parsing.md +0 -0
  10. data/doc/Serializing.md +7 -0
  11. data/doc/Tokenizing.md +0 -0
  12. data/doc/Validating.md +0 -0
  13. data/doc/design/Parser.md +0 -0
  14. data/doc/design/Reader.md +0 -0
  15. data/lib/ruby/array.rb +164 -0
  16. data/lib/ruby/blank.rb +67 -0
  17. data/lib/ruby/enumerable.rb +35 -0
  18. data/lib/ruby/exception.rb +33 -0
  19. data/lib/ruby/hash.rb +4 -0
  20. data/lib/ruby/instance_exec.rb +26 -0
  21. data/lib/ruby/module.rb +79 -0
  22. data/lib/ruby/object.rb +63 -0
  23. data/lib/ruby/string.rb +73 -0
  24. data/lib/ruby/symbol.rb +24 -0
  25. data/lib/ruby/to_d.rb +81 -0
  26. data/lib/ruby/to_date.rb +33 -0
  27. data/lib/ruby/to_time.rb +24 -0
  28. data/lib/ruby/try.rb +43 -0
  29. data/lib/stupidedi/blank_slate.rb +11 -0
  30. data/lib/stupidedi/builder/builder_dsl.rb +281 -0
  31. data/lib/stupidedi/builder/constraint_table.rb +418 -0
  32. data/lib/stupidedi/builder/generation.rb +112 -0
  33. data/lib/stupidedi/builder/instruction.rb +102 -0
  34. data/lib/stupidedi/builder/instruction_table.rb +204 -0
  35. data/lib/stupidedi/builder/navigation.rb +655 -0
  36. data/lib/stupidedi/builder/state_machine.rb +55 -0
  37. data/lib/stupidedi/builder/states/abstract_state.rb +332 -0
  38. data/lib/stupidedi/builder/states/failure_state.rb +69 -0
  39. data/lib/stupidedi/builder/states/functional_group_state.rb +97 -0
  40. data/lib/stupidedi/builder/states/initial_state.rb +63 -0
  41. data/lib/stupidedi/builder/states/interchange_state.rb +94 -0
  42. data/lib/stupidedi/builder/states/loop_state.rb +79 -0
  43. data/lib/stupidedi/builder/states/table_state.rb +96 -0
  44. data/lib/stupidedi/builder/states/transaction_set_state.rb +112 -0
  45. data/lib/stupidedi/builder/states/transmission_state.rb +59 -0
  46. data/lib/stupidedi/builder/tokenization.rb +196 -0
  47. data/lib/stupidedi/builder.rb +23 -0
  48. data/lib/stupidedi/color.rb +93 -0
  49. data/lib/stupidedi/config/code_list_config.rb +42 -0
  50. data/lib/stupidedi/config/editor_config.rb +51 -0
  51. data/lib/stupidedi/config/functional_group_config.rb +62 -0
  52. data/lib/stupidedi/config/interchange_config.rb +79 -0
  53. data/lib/stupidedi/config/transaction_set_config.rb +91 -0
  54. data/lib/stupidedi/config.rb +101 -0
  55. data/lib/stupidedi/editor/00501.rb +341 -0
  56. data/lib/stupidedi/editor/005010/N2.rb +0 -0
  57. data/lib/stupidedi/editor/005010/N3.rb +0 -0
  58. data/lib/stupidedi/editor/005010/N4.rb +63 -0
  59. data/lib/stupidedi/editor/005010/NM1.rb +0 -0
  60. data/lib/stupidedi/editor/005010.rb +469 -0
  61. data/lib/stupidedi/editor/X222-HC837.rb +195 -0
  62. data/lib/stupidedi/editor/abstract_ed.rb +36 -0
  63. data/lib/stupidedi/editor/claim_ack.rb +9 -0
  64. data/lib/stupidedi/editor/implementation_ack.rb +213 -0
  65. data/lib/stupidedi/editor/interchange_ack.rb +9 -0
  66. data/lib/stupidedi/editor/result.rb +100 -0
  67. data/lib/stupidedi/editor/result_set.rb +69 -0
  68. data/lib/stupidedi/editor/transaction_set_ed.rb +275 -0
  69. data/lib/stupidedi/editor/transmission_ed.rb +90 -0
  70. data/lib/stupidedi/editor.rb +37 -0
  71. data/lib/stupidedi/either.rb +287 -0
  72. data/lib/stupidedi/exceptions/invalid_element_error.rb +8 -0
  73. data/lib/stupidedi/exceptions/invalid_schema_error.rb +8 -0
  74. data/lib/stupidedi/exceptions/output_error.rb +8 -0
  75. data/lib/stupidedi/exceptions/parse_error.rb +8 -0
  76. data/lib/stupidedi/exceptions/stupidedi_error.rb +8 -0
  77. data/lib/stupidedi/exceptions/tokenize_error.rb +8 -0
  78. data/lib/stupidedi/exceptions/zipper_error.rb +8 -0
  79. data/lib/stupidedi/exceptions.rb +11 -0
  80. data/lib/stupidedi/guides/005010/X214-HN277.rb +409 -0
  81. data/lib/stupidedi/guides/005010/X221-HP835.rb +613 -0
  82. data/lib/stupidedi/guides/005010/X221A1-HP835.rb +613 -0
  83. data/lib/stupidedi/guides/005010/X222-HC837P.rb +2291 -0
  84. data/lib/stupidedi/guides/005010/X222A1-HC837P.rb +2297 -0
  85. data/lib/stupidedi/guides/005010/X231-FA999.rb +123 -0
  86. data/lib/stupidedi/guides/005010/X231A1-FA999.rb +119 -0
  87. data/lib/stupidedi/guides/005010/element_reqs.rb +38 -0
  88. data/lib/stupidedi/guides/005010/guide_builder.rb +180 -0
  89. data/lib/stupidedi/guides/005010/segment_reqs.rb +32 -0
  90. data/lib/stupidedi/guides/005010.rb +64 -0
  91. data/lib/stupidedi/guides.rb +5 -0
  92. data/lib/stupidedi/inspect.rb +26 -0
  93. data/lib/stupidedi/reader/input/abstract_input.rb +133 -0
  94. data/lib/stupidedi/reader/input/delegated_input.rb +111 -0
  95. data/lib/stupidedi/reader/input/file_input.rb +155 -0
  96. data/lib/stupidedi/reader/input.rb +30 -0
  97. data/lib/stupidedi/reader/position.rb +69 -0
  98. data/lib/stupidedi/reader/result.rb +168 -0
  99. data/lib/stupidedi/reader/segment_dict.rb +175 -0
  100. data/lib/stupidedi/reader/separators.rb +85 -0
  101. data/lib/stupidedi/reader/stream_reader.rb +172 -0
  102. data/lib/stupidedi/reader/token_reader.rb +466 -0
  103. data/lib/stupidedi/reader/tokens/component_element_tok.rb +56 -0
  104. data/lib/stupidedi/reader/tokens/composite_element_tok.rb +64 -0
  105. data/lib/stupidedi/reader/tokens/repeated_element_tok.rb +64 -0
  106. data/lib/stupidedi/reader/tokens/segment_tok.rb +51 -0
  107. data/lib/stupidedi/reader/tokens/simple_element_tok.rb +63 -0
  108. data/lib/stupidedi/reader.rb +121 -0
  109. data/lib/stupidedi/schema/abstract_def.rb +74 -0
  110. data/lib/stupidedi/schema/abstract_use.rb +73 -0
  111. data/lib/stupidedi/schema/code_list.rb +94 -0
  112. data/lib/stupidedi/schema/element_def.rb +173 -0
  113. data/lib/stupidedi/schema/element_req.rb +56 -0
  114. data/lib/stupidedi/schema/element_use.rb +251 -0
  115. data/lib/stupidedi/schema/functional_group_def.rb +114 -0
  116. data/lib/stupidedi/schema/interchange_def.rb +93 -0
  117. data/lib/stupidedi/schema/loop_def.rb +152 -0
  118. data/lib/stupidedi/schema/repeat_count.rb +85 -0
  119. data/lib/stupidedi/schema/segment_def.rb +108 -0
  120. data/lib/stupidedi/schema/segment_req.rb +43 -0
  121. data/lib/stupidedi/schema/segment_use.rb +98 -0
  122. data/lib/stupidedi/schema/syntax_note.rb +63 -0
  123. data/lib/stupidedi/schema/table_def.rb +139 -0
  124. data/lib/stupidedi/schema/transaction_set_def.rb +88 -0
  125. data/lib/stupidedi/schema.rb +28 -0
  126. data/lib/stupidedi/sets/absolute_set.rb +297 -0
  127. data/lib/stupidedi/sets/abstract_set.rb +174 -0
  128. data/lib/stupidedi/sets/null_set.rb +125 -0
  129. data/lib/stupidedi/sets/relative_complement.rb +137 -0
  130. data/lib/stupidedi/sets/relative_set.rb +269 -0
  131. data/lib/stupidedi/sets/universal_set.rb +104 -0
  132. data/lib/stupidedi/sets.rb +57 -0
  133. data/lib/stupidedi/tail_call.rb +109 -0
  134. data/lib/stupidedi/thread_local.rb +174 -0
  135. data/lib/stupidedi/values/abstract_element_val.rb +19 -0
  136. data/lib/stupidedi/values/abstract_val.rb +130 -0
  137. data/lib/stupidedi/values/composite_element_val.rb +95 -0
  138. data/lib/stupidedi/values/functional_group_val.rb +102 -0
  139. data/lib/stupidedi/values/interchange_val.rb +86 -0
  140. data/lib/stupidedi/values/invalid_envelope_val.rb +61 -0
  141. data/lib/stupidedi/values/invalid_segment_val.rb +78 -0
  142. data/lib/stupidedi/values/loop_val.rb +70 -0
  143. data/lib/stupidedi/values/repeated_element_val.rb +105 -0
  144. data/lib/stupidedi/values/segment_val.rb +104 -0
  145. data/lib/stupidedi/values/segment_val_group.rb +20 -0
  146. data/lib/stupidedi/values/simple_element_val.rb +80 -0
  147. data/lib/stupidedi/values/table_val.rb +66 -0
  148. data/lib/stupidedi/values/transaction_set_val.rb +66 -0
  149. data/lib/stupidedi/values/transmission_val.rb +52 -0
  150. data/lib/stupidedi/values.rb +21 -0
  151. data/lib/stupidedi/version.rb +3 -0
  152. data/lib/stupidedi/versions/functional_groups/004010/element_defs.rb +54 -0
  153. data/lib/stupidedi/versions/functional_groups/004010/element_reqs.rb +18 -0
  154. data/lib/stupidedi/versions/functional_groups/004010/element_types/date_val.rb +527 -0
  155. data/lib/stupidedi/versions/functional_groups/004010/element_types/fixnum_val.rb +335 -0
  156. data/lib/stupidedi/versions/functional_groups/004010/element_types/float_val.rb +299 -0
  157. data/lib/stupidedi/versions/functional_groups/004010/element_types/identifier_val.rb +287 -0
  158. data/lib/stupidedi/versions/functional_groups/004010/element_types/string_val.rb +338 -0
  159. data/lib/stupidedi/versions/functional_groups/004010/element_types/time_val.rb +309 -0
  160. data/lib/stupidedi/versions/functional_groups/004010/element_types.rb +124 -0
  161. data/lib/stupidedi/versions/functional_groups/004010/functional_group_def.rb +30 -0
  162. data/lib/stupidedi/versions/functional_groups/004010/segment_defs/GE.rb +20 -0
  163. data/lib/stupidedi/versions/functional_groups/004010/segment_defs/GS.rb +27 -0
  164. data/lib/stupidedi/versions/functional_groups/004010/segment_defs/SE.rb +20 -0
  165. data/lib/stupidedi/versions/functional_groups/004010/segment_defs/ST.rb +20 -0
  166. data/lib/stupidedi/versions/functional_groups/004010/segment_defs.rb +23 -0
  167. data/lib/stupidedi/versions/functional_groups/004010/segment_reqs.rb +18 -0
  168. data/lib/stupidedi/versions/functional_groups/004010/syntax_notes.rb +174 -0
  169. data/lib/stupidedi/versions/functional_groups/004010.rb +38 -0
  170. data/lib/stupidedi/versions/functional_groups/005010/element_defs.rb +1405 -0
  171. data/lib/stupidedi/versions/functional_groups/005010/element_reqs.rb +18 -0
  172. data/lib/stupidedi/versions/functional_groups/005010/element_types/date_val.rb +577 -0
  173. data/lib/stupidedi/versions/functional_groups/005010/element_types/fixnum_val.rb +322 -0
  174. data/lib/stupidedi/versions/functional_groups/005010/element_types/float_val.rb +354 -0
  175. data/lib/stupidedi/versions/functional_groups/005010/element_types/identifier_val.rb +368 -0
  176. data/lib/stupidedi/versions/functional_groups/005010/element_types/operators.rb +117 -0
  177. data/lib/stupidedi/versions/functional_groups/005010/element_types/string_val.rb +398 -0
  178. data/lib/stupidedi/versions/functional_groups/005010/element_types/time_val.rb +327 -0
  179. data/lib/stupidedi/versions/functional_groups/005010/element_types.rb +132 -0
  180. data/lib/stupidedi/versions/functional_groups/005010/functional_group_def.rb +30 -0
  181. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/AK1.rb +21 -0
  182. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/AK2.rb +21 -0
  183. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/AK9.rb +28 -0
  184. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/AMT.rb +21 -0
  185. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/BHT.rb +24 -0
  186. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/BPR.rb +49 -0
  187. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CAS.rb +56 -0
  188. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CL1.rb +22 -0
  189. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CLM.rb +41 -0
  190. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CLP.rb +34 -0
  191. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CN1.rb +24 -0
  192. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CR1.rb +32 -0
  193. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CR2.rb +35 -0
  194. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CR3.rb +25 -0
  195. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CRC.rb +26 -0
  196. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CTP.rb +36 -0
  197. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CTX.rb +24 -0
  198. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CUR.rb +57 -0
  199. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DMG.rb +34 -0
  200. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DN1.rb +22 -0
  201. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DN2.rb +24 -0
  202. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DTM.rb +24 -0
  203. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DTP.rb +21 -0
  204. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/FRM.rb +25 -0
  205. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/GE.rb +20 -0
  206. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/GS.rb +27 -0
  207. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/HCP.rb +39 -0
  208. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/HI.rb +31 -0
  209. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/HL.rb +22 -0
  210. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/IK3.rb +22 -0
  211. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/IK4.rb +22 -0
  212. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/IK5.rb +24 -0
  213. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/K3.rb +21 -0
  214. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/LIN.rb +69 -0
  215. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/LQ.rb +22 -0
  216. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/LX.rb +19 -0
  217. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/MEA.rb +39 -0
  218. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/MIA.rb +45 -0
  219. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/MOA.rb +28 -0
  220. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/N1.rb +24 -0
  221. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/N2.rb +20 -0
  222. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/N3.rb +20 -0
  223. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/N4.rb +30 -0
  224. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/NM1.rb +35 -0
  225. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/NTE.rb +20 -0
  226. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/OI.rb +24 -0
  227. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PAT.rb +31 -0
  228. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PER.rb +32 -0
  229. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PLB.rb +40 -0
  230. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PRV.rb +26 -0
  231. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PS1.rb +21 -0
  232. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PWK.rb +30 -0
  233. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/QTY.rb +25 -0
  234. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/RDM.rb +23 -0
  235. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/REF.rb +23 -0
  236. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SBR.rb +28 -0
  237. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SE.rb +20 -0
  238. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/ST.rb +21 -0
  239. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/STC.rb +30 -0
  240. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SV1.rb +44 -0
  241. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SV2.rb +29 -0
  242. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SV3.rb +30 -0
  243. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SV5.rb +29 -0
  244. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SVC.rb +26 -0
  245. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SVD.rb +24 -0
  246. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/TOO.rb +21 -0
  247. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/TRN.rb +22 -0
  248. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/TS2.rb +40 -0
  249. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/TS3.rb +45 -0
  250. data/lib/stupidedi/versions/functional_groups/005010/segment_defs.rb +227 -0
  251. data/lib/stupidedi/versions/functional_groups/005010/segment_reqs.rb +18 -0
  252. data/lib/stupidedi/versions/functional_groups/005010/syntax_notes.rb +165 -0
  253. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/FA999.rb +38 -0
  254. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HB271.rb +85 -0
  255. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HC837.rb +163 -0
  256. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HI278.rb +64 -0
  257. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HN277.rb +74 -0
  258. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HP835.rb +68 -0
  259. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HR276.rb +57 -0
  260. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HS270.rb +53 -0
  261. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/RA820.rb +240 -0
  262. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs.rb +68 -0
  263. data/lib/stupidedi/versions/functional_groups/005010.rb +38 -0
  264. data/lib/stupidedi/versions/functional_groups.rb +8 -0
  265. data/lib/stupidedi/versions/interchanges/00401/element_defs.rb +224 -0
  266. data/lib/stupidedi/versions/interchanges/00401/interchange_def.rb +45 -0
  267. data/lib/stupidedi/versions/interchanges/00401/segment_defs/IEA.rb +20 -0
  268. data/lib/stupidedi/versions/interchanges/00401/segment_defs/ISA.rb +34 -0
  269. data/lib/stupidedi/versions/interchanges/00401/segment_defs/TA1.rb +23 -0
  270. data/lib/stupidedi/versions/interchanges/00401/segment_defs.rb +28 -0
  271. data/lib/stupidedi/versions/interchanges/00401.rb +23 -0
  272. data/lib/stupidedi/versions/interchanges/00501/element_defs.rb +269 -0
  273. data/lib/stupidedi/versions/interchanges/00501/interchange_def.rb +47 -0
  274. data/lib/stupidedi/versions/interchanges/00501/segment_defs/IEA.rb +20 -0
  275. data/lib/stupidedi/versions/interchanges/00501/segment_defs/ISA.rb +34 -0
  276. data/lib/stupidedi/versions/interchanges/00501/segment_defs/ISB.rb +18 -0
  277. data/lib/stupidedi/versions/interchanges/00501/segment_defs/ISE.rb +18 -0
  278. data/lib/stupidedi/versions/interchanges/00501/segment_defs/TA1.rb +23 -0
  279. data/lib/stupidedi/versions/interchanges/00501/segment_defs/TA3.rb +18 -0
  280. data/lib/stupidedi/versions/interchanges/00501/segment_defs.rb +37 -0
  281. data/lib/stupidedi/versions/interchanges/00501.rb +23 -0
  282. data/lib/stupidedi/versions/interchanges.rb +8 -0
  283. data/lib/stupidedi/versions.rb +6 -0
  284. data/lib/stupidedi/writer/claredi.rb +142 -0
  285. data/lib/stupidedi/writer/default.rb +124 -0
  286. data/lib/stupidedi/writer.rb +6 -0
  287. data/lib/stupidedi/zipper/abstract_cursor.rb +351 -0
  288. data/lib/stupidedi/zipper/dangling_cursor.rb +103 -0
  289. data/lib/stupidedi/zipper/edited_cursor.rb +157 -0
  290. data/lib/stupidedi/zipper/memoized_cursor.rb +131 -0
  291. data/lib/stupidedi/zipper/path.rb +124 -0
  292. data/lib/stupidedi/zipper/root_cursor.rb +120 -0
  293. data/lib/stupidedi/zipper.rb +25 -0
  294. data/lib/stupidedi.rb +66 -0
  295. data/spec/examples/integration/generating.example +551 -0
  296. data/spec/examples/integration/navigating.example +214 -0
  297. data/spec/examples/integration/parsing.example +445 -0
  298. data/spec/examples/ruby/array.example +476 -0
  299. data/spec/examples/ruby/blank.example +62 -0
  300. data/spec/examples/ruby/count.example +68 -0
  301. data/spec/examples/ruby/object.example +99 -0
  302. data/spec/examples/ruby/string.example +111 -0
  303. data/spec/examples/ruby/symbol.example +117 -0
  304. data/spec/examples/ruby/to_d.example +90 -0
  305. data/spec/examples/ruby/try.example +50 -0
  306. data/spec/examples/stupidedi/either.example +375 -0
  307. data/spec/examples/stupidedi/reader/failure.example +68 -0
  308. data/spec/examples/stupidedi/reader/input/delegated_input.example +292 -0
  309. data/spec/examples/stupidedi/reader/separators.example +73 -0
  310. data/spec/examples/stupidedi/reader/stream_reader.example +48 -0
  311. data/spec/examples/stupidedi/reader/success.example +34 -0
  312. data/spec/examples/stupidedi/reader/token_reader.example +775 -0
  313. data/spec/examples/stupidedi/reader.example +168 -0
  314. data/spec/examples/stupidedi/sets/absolute_set.example +1577 -0
  315. data/spec/examples/stupidedi/sets/null_set.example +2 -0
  316. data/spec/examples/stupidedi/sets/relative_set.example +2 -0
  317. data/spec/examples/stupidedi/sets/universal_set.example +1 -0
  318. data/spec/examples/stupidedi/versions/005010/element_types/an.example +201 -0
  319. data/spec/examples/stupidedi/versions/005010/element_types/dt.example +258 -0
  320. data/spec/examples/stupidedi/versions/005010/element_types/id.example +192 -0
  321. data/spec/examples/stupidedi/versions/005010/element_types/nn.example +177 -0
  322. data/spec/examples/stupidedi/versions/005010/element_types/r.example +178 -0
  323. data/spec/examples/stupidedi/versions/005010/element_types/tm.example +2 -0
  324. data/spec/examples/stupidedi/zipper/abstract_cursor.example +417 -0
  325. data/spec/examples/stupidedi/zipper.example +9 -0
  326. data/spec/fixtures/X186-AG824/1-bad.txt +21 -0
  327. data/spec/fixtures/X186-AG824/1-good.txt +17 -0
  328. data/spec/fixtures/X186-AG824/2-bad.txt +26 -0
  329. data/spec/fixtures/X186-AG824/2-good.txt +21 -0
  330. data/spec/fixtures/X186-AG824/3-bad.txt +87 -0
  331. data/spec/fixtures/X186-AG824/3-good.txt +61 -0
  332. data/spec/fixtures/X212-HN277/1-bad.txt +54 -0
  333. data/spec/fixtures/X212-HN277/1-good.txt +46 -0
  334. data/spec/fixtures/X212-HN277/2-bad.txt +37 -0
  335. data/spec/fixtures/X212-HN277/2-good.txt +29 -0
  336. data/spec/fixtures/X212-HN277/3-bad.txt +22 -0
  337. data/spec/fixtures/X212-HN277/3-good.txt +17 -0
  338. data/spec/fixtures/X212-HN277/4-bad.txt +30 -0
  339. data/spec/fixtures/X212-HN277/4-good.txt +24 -0
  340. data/spec/fixtures/X212-HR276/1-bad.txt +53 -0
  341. data/spec/fixtures/X212-HR276/1-good.txt +46 -0
  342. data/spec/fixtures/X212-HR276/2-bad.txt +45 -0
  343. data/spec/fixtures/X212-HR276/2-good.txt +38 -0
  344. data/spec/fixtures/X212-HR276/3-bad.txt +32 -0
  345. data/spec/fixtures/X212-HR276/3-good.txt +26 -0
  346. data/spec/fixtures/X212-HR276/4-bad.txt +32 -0
  347. data/spec/fixtures/X212-HR276/4-good.txt +26 -0
  348. data/spec/fixtures/X214-HN277/1-bad.txt +58 -0
  349. data/spec/fixtures/X214-HN277/1-good.txt +47 -0
  350. data/spec/fixtures/X214-HN277/2-bad.txt +34 -0
  351. data/spec/fixtures/X214-HN277/2-good.txt +22 -0
  352. data/spec/fixtures/X214-HN277/3-bad.txt +64 -0
  353. data/spec/fixtures/X214-HN277/3-good.txt +54 -0
  354. data/spec/fixtures/X214-HN277/4-bad.txt +77 -0
  355. data/spec/fixtures/X214-HN277/4-good.txt +63 -0
  356. data/spec/fixtures/X216-HI278/1-bad.txt +42 -0
  357. data/spec/fixtures/X216-HI278/1-good.txt +27 -0
  358. data/spec/fixtures/X216-HI278/2-bad.txt +43 -0
  359. data/spec/fixtures/X216-HI278/2-good.txt +29 -0
  360. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-1.txt +24 -0
  361. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-1_Clean.txt +20 -0
  362. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-2.txt +46 -0
  363. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-2_Clean.txt +30 -0
  364. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-3.txt +38 -0
  365. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-3_Clean.txt +24 -0
  366. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-4a.txt +39 -0
  367. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-4a_Clean.txt +24 -0
  368. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-4b.txt +43 -0
  369. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-4b_Clean.txt +25 -0
  370. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-5.txt +63 -0
  371. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-5_Clean.txt +41 -0
  372. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-6.txt +36 -0
  373. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-6_Clean.txt +20 -0
  374. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-1r.txt +34 -0
  375. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-1r_Clean.txt +23 -0
  376. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-2r.txt +46 -0
  377. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-2r_Clean.txt +31 -0
  378. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-3r.txt +44 -0
  379. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-3r_Clean.txt +26 -0
  380. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-4ar_Clean.txt +28 -0
  381. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-4br_Clean.txt +35 -0
  382. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-5r.txt +60 -0
  383. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-5r_Clean.txt +42 -0
  384. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-6r.txt +40 -0
  385. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-6r_Clean.txt +24 -0
  386. data/spec/fixtures/X218-RA820/1-bad.txt +31 -0
  387. data/spec/fixtures/X218-RA820/1-good.txt +25 -0
  388. data/spec/fixtures/X218-RA820/2-bad.txt +37 -0
  389. data/spec/fixtures/X218-RA820/2-good.txt +29 -0
  390. data/spec/fixtures/X218-RA820/3-bad.txt +29 -0
  391. data/spec/fixtures/X218-RA820/3-good.txt +23 -0
  392. data/spec/fixtures/X218-RA820/4-bad.txt +36 -0
  393. data/spec/fixtures/X218-RA820/4-good.txt +27 -0
  394. data/spec/fixtures/X220-BE834/1-bad.txt +35 -0
  395. data/spec/fixtures/X220-BE834/1-good.txt +29 -0
  396. data/spec/fixtures/X220-BE834/10-bad.txt +26 -0
  397. data/spec/fixtures/X220-BE834/10-good.txt +19 -0
  398. data/spec/fixtures/X220-BE834/2-bad.txt +31 -0
  399. data/spec/fixtures/X220-BE834/2-good.txt +23 -0
  400. data/spec/fixtures/X220-BE834/3-bad.txt +36 -0
  401. data/spec/fixtures/X220-BE834/3-good.txt +26 -0
  402. data/spec/fixtures/X220-BE834/4-bad.txt +27 -0
  403. data/spec/fixtures/X220-BE834/4-good.txt +21 -0
  404. data/spec/fixtures/X220-BE834/5-bad.txt +26 -0
  405. data/spec/fixtures/X220-BE834/5-good.txt +17 -0
  406. data/spec/fixtures/X220-BE834/6-bad.txt +25 -0
  407. data/spec/fixtures/X220-BE834/6-good.txt +20 -0
  408. data/spec/fixtures/X220-BE834/7-bad.txt +25 -0
  409. data/spec/fixtures/X220-BE834/7-good.txt +20 -0
  410. data/spec/fixtures/X220-BE834/8-bad.txt +25 -0
  411. data/spec/fixtures/X220-BE834/8-good.txt +20 -0
  412. data/spec/fixtures/X220-BE834/9-bad.txt +27 -0
  413. data/spec/fixtures/X220-BE834/9-good.txt +21 -0
  414. data/spec/fixtures/X221-HP835/1-bad.txt +58 -0
  415. data/spec/fixtures/X221-HP835/1-good.txt +40 -0
  416. data/spec/fixtures/X221-HP835/2-bad.txt +51 -0
  417. data/spec/fixtures/X221-HP835/2-good.txt +40 -0
  418. data/spec/fixtures/X221-HP835/3a-bad.txt +78 -0
  419. data/spec/fixtures/X221-HP835/3a-good.txt +49 -0
  420. data/spec/fixtures/X221-HP835/3b-bad.txt +60 -0
  421. data/spec/fixtures/X221-HP835/3b-good.txt +32 -0
  422. data/spec/fixtures/X221-HP835/3c-bad.txt +55 -0
  423. data/spec/fixtures/X221-HP835/3c-good.txt +34 -0
  424. data/spec/fixtures/X222-HC837/1-bad.txt +60 -0
  425. data/spec/fixtures/X222-HC837/1-good.txt +53 -0
  426. data/spec/fixtures/X222-HC837/10a-bad.txt +52 -0
  427. data/spec/fixtures/X222-HC837/10a-good.txt +40 -0
  428. data/spec/fixtures/X222-HC837/10b-bad.txt +99 -0
  429. data/spec/fixtures/X222-HC837/10b-good.txt +80 -0
  430. data/spec/fixtures/X222-HC837/10c-bad.txt +105 -0
  431. data/spec/fixtures/X222-HC837/10c-good.txt +80 -0
  432. data/spec/fixtures/X222-HC837/11-bad.txt +69 -0
  433. data/spec/fixtures/X222-HC837/11-good.txt +45 -0
  434. data/spec/fixtures/X222-HC837/12-bad.txt +73 -0
  435. data/spec/fixtures/X222-HC837/12-good.txt +51 -0
  436. data/spec/fixtures/X222-HC837/13-bad.txt +64 -0
  437. data/spec/fixtures/X222-HC837/13-good.txt +46 -0
  438. data/spec/fixtures/X222-HC837/3a-bad.txt +83 -0
  439. data/spec/fixtures/X222-HC837/3a-good.txt +59 -0
  440. data/spec/fixtures/X222-HC837/3b-bad.txt +97 -0
  441. data/spec/fixtures/X222-HC837/3b-good.txt +70 -0
  442. data/spec/fixtures/X222-HC837/3c-bad.txt +95 -0
  443. data/spec/fixtures/X222-HC837/3c-good.txt +74 -0
  444. data/spec/fixtures/X222-HC837/4-bad.txt +67 -0
  445. data/spec/fixtures/X222-HC837/4-good.txt +48 -0
  446. data/spec/fixtures/X222-HC837/5-bad.txt +73 -0
  447. data/spec/fixtures/X222-HC837/5-good.txt +60 -0
  448. data/spec/fixtures/X222-HC837/6-bad.txt +50 -0
  449. data/spec/fixtures/X222-HC837/6-good.txt +39 -0
  450. data/spec/fixtures/X222-HC837/7-bad.txt +93 -0
  451. data/spec/fixtures/X222-HC837/7-good.txt +78 -0
  452. data/spec/fixtures/X222-HC837/8-bad.txt +64 -0
  453. data/spec/fixtures/X222-HC837/8-good.txt +52 -0
  454. data/spec/fixtures/X222-HC837/9-bad.txt +56 -0
  455. data/spec/fixtures/X222-HC837/9-good.txt +38 -0
  456. data/spec/fixtures/X223-HC837/1-bad.txt +66 -0
  457. data/spec/fixtures/X223-HC837/1-good.txt +53 -0
  458. data/spec/fixtures/X223-HC837/2-bad.txt +69 -0
  459. data/spec/fixtures/X223-HC837/2-good.txt +60 -0
  460. data/spec/fixtures/X223-HC837/3-bad.txt +89 -0
  461. data/spec/fixtures/X223-HC837/3-good.txt +61 -0
  462. data/spec/fixtures/X223-HC837/4-bad.txt +60 -0
  463. data/spec/fixtures/X223-HC837/4-good.txt +40 -0
  464. data/spec/fixtures/X223-HC837/5-bad.txt +75 -0
  465. data/spec/fixtures/X223-HC837/5-good.txt +58 -0
  466. data/spec/fixtures/X224-HC837/1-bad.txt +54 -0
  467. data/spec/fixtures/X224-HC837/1-good.txt +44 -0
  468. data/spec/fixtures/X224-HC837/2a-bad.txt +52 -0
  469. data/spec/fixtures/X224-HC837/2a-good.txt +42 -0
  470. data/spec/fixtures/X224-HC837/2b-bad.txt +67 -0
  471. data/spec/fixtures/X224-HC837/2b-good.txt +52 -0
  472. data/spec/fixtures/X224-HC837/3-bad.txt +67 -0
  473. data/spec/fixtures/X224-HC837/3-good.txt +51 -0
  474. data/spec/fixtures/X224-HC837/4-bad.txt +49 -0
  475. data/spec/fixtures/X224-HC837/4-good.txt +40 -0
  476. data/spec/fixtures/X230-FA997/1-bad.txt +19 -0
  477. data/spec/fixtures/X230-FA997/1-good.txt +16 -0
  478. data/spec/fixtures/X231-FA999/1-bad.txt +20 -0
  479. data/spec/fixtures/X231-FA999/1-good.txt +20 -0
  480. data/spec/fixtures/X279-HB271/1-bad.txt +36 -0
  481. data/spec/fixtures/X279-HB271/1-good.txt +30 -0
  482. data/spec/fixtures/X279-HB271/2-bad.txt +22 -0
  483. data/spec/fixtures/X279-HB271/2-good.txt +16 -0
  484. data/spec/fixtures/X279-HB271/3-bad.txt +44 -0
  485. data/spec/fixtures/X279-HB271/3-good.txt +36 -0
  486. data/spec/fixtures/X279-HS270/1-bad.txt +29 -0
  487. data/spec/fixtures/X279-HS270/1-good.txt +23 -0
  488. data/spec/fixtures/X279-HS270/2-bad.txt +32 -0
  489. data/spec/fixtures/X279-HS270/2-good.txt +25 -0
  490. data/spec/spec_helper.rb +34 -0
  491. data/spec/support/fixtures.rb +26 -0
  492. data/spec/support/matchers/either_matchers.rb +26 -0
  493. data/spec/support/matchers/navigation_matchers.rb +247 -0
  494. data/spec/support/node.rb +41 -0
  495. data/spec/support/quickcheck/characters.rb +28 -0
  496. data/spec/support/quickcheck/property.rb +105 -0
  497. data/spec/support/quickcheck/serialized_edi.rb +399 -0
  498. data/spec/support/quickcheck.rb +302 -0
  499. data/spec/support/rcov.rb +34 -0
  500. metadata +577 -0
@@ -0,0 +1,418 @@
1
+ module Stupidedi
2
+ module Builder
3
+
4
+ #
5
+ # The {ConstraintTable} is a data structure that contains one or more
6
+ # {Instruction} values for the same segment identifier. Each concrete
7
+ # subclass implements different strategies for narrowing down the
8
+ # {Instruction} list.
9
+ #
10
+ # Reducing the number of valid {Instruction} values is important because
11
+ # executing more than one {Instruction} creates a non-deterministic state --
12
+ # more than one valid parse tree exists -- which slows the parser. Most
13
+ # often there is only one valid {Instruction} but the parser cannot
14
+ # (efficiently or at all) narrow the tree down without evaluating the
15
+ # constraints declared by each {Instruction}'s {Schema::SegmentUse}, which
16
+ # is done here.
17
+ #
18
+ class ConstraintTable
19
+
20
+ # @return [Array<Instruction>]
21
+ abstract :matches, :args => %w(segment_tok)
22
+
23
+ #
24
+ # Performs no filtering of the {Instruction} list. This is used when there
25
+ # already is a single {Instruction} or when a {Reader::SegmentTok} doesn't
26
+ # provide any more information to filter the list.
27
+ #
28
+ class Stub < ConstraintTable
29
+ def initialize(instructions)
30
+ @instructions = instructions
31
+ end
32
+
33
+ # @return [Array<Instruction>]
34
+ def matches(segment_tok, strict)
35
+ @instructions
36
+ end
37
+ end
38
+
39
+ #
40
+ # Chooses the {Instruction} that pops the fewest number of states. For
41
+ # example, in the X222 837P an HL segment signals the start of a new
42
+ # 2000 loop, but may or may not begin a new Table 2 -- the specifications
43
+ # aren't actually clear. This rule will avoid creating a new Table 2 if
44
+ # possible, and instead create a new 2000 loop under the current Table 2.
45
+ #
46
+ class DepthBased < ConstraintTable
47
+ def initialize(instructions)
48
+ @instructions = instructions
49
+ end
50
+
51
+ # @return [Array<Instruction>]
52
+ def matches(segment_tok, strict)
53
+ @__matches ||= begin
54
+ deepest = @instructions.head
55
+
56
+ @instructions.tail.each do |i|
57
+ if i.pop_count < deepest.pop_count
58
+ deepest = i
59
+ end
60
+ end
61
+
62
+ deepest.cons
63
+ end
64
+ end
65
+ end
66
+
67
+ #
68
+ # Chooses the subset of {Instruction} values based on the distinguishing
69
+ # values allowed by each {Schema::SegmentUse}. For instance, there are
70
+ # often several loops that begin with `NM1`, which are distinguished by
71
+ # the qualifier in element `NM101`.
72
+ #
73
+ class ValueBased < ConstraintTable
74
+ def initialize(instructions)
75
+ @instructions = instructions
76
+ end
77
+
78
+ # @return [Array<Instruction>]
79
+ def matches(segment_tok, strict)
80
+ invalid = true # Were all possibly distinguishing elements invalid?
81
+ present = false # Were any possibly distinguishing elements present?
82
+
83
+ @__basis ||= basis(deepest(@instructions))
84
+ @__basis.head.each do |(n, m), map|
85
+ value = deconstruct(segment_tok.element_toks, n, m)
86
+
87
+ case value
88
+ when nil, :not_used, :default
89
+ # ignore
90
+ else
91
+ singleton = map.at(value)
92
+ present = true
93
+
94
+ unless singleton.nil?
95
+ return singleton
96
+ else
97
+ if strict
98
+ designator = "#{segment_tok.id}#{'%02d' % (n + 1)}"
99
+ designator << "-%02d" % m unless m.nil?
100
+
101
+ raise ArgumentError,
102
+ "#{value.inspect} is not allowed in #{designator}"
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ # If we reach this line, none of the present elements could, on its
109
+ # own, narrow the search space to a single Instruction. We now test
110
+ # the combination of elements to iteratively narrow the search space
111
+ space = @instructions
112
+
113
+ # @todo: These filters should be ordered by probable effectiveness,
114
+ # so we narrow the search space by the largest amount in the fewest
115
+ # number of steps.
116
+ @__basis.last.each do |(n, m), map|
117
+ value = deconstruct(segment_tok.element_toks, n, m)
118
+
119
+ unless value.nil?
120
+ subset = map.at(value)
121
+ present = true
122
+
123
+ unless subset.blank?
124
+ invalid = false
125
+ space &= subset
126
+
127
+ if space.length <= 1
128
+ return space
129
+ end
130
+ else
131
+ if strict
132
+ designator = "#{segment_tok.id}#{'%02d' % n}"
133
+ designator << "-%02d" % m unless m.nil?
134
+
135
+ raise ArgumentError,
136
+ "#{value.inspect} is not allowed in #{designator}"
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ if invalid and present
143
+ []
144
+ else
145
+ space
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ # Resolve conflicts between instructions that have identical SegmentUse
152
+ # values. For each SegmentUse, this chooses the Instruction that pops
153
+ # the fewest number of states.
154
+ #
155
+ # @return [Array<Instruction>]
156
+ def deepest(instructions)
157
+ deepest = Hash.new
158
+
159
+ instructions.each do |i|
160
+ key = i.segment_use.object_id
161
+
162
+ if deepest.defined_at?(key)
163
+ if deepest.at(key).pop_count > i.pop_count
164
+ deepest[key] = i
165
+ end
166
+ else
167
+ deepest[key] = i
168
+ end
169
+ end
170
+
171
+ deepest.values
172
+ end
173
+
174
+ # @return [Array(Array<(Integer, Integer, Map)>, Array<(Integer, Integer, Map)>)]
175
+ def basis(instructions)
176
+ disjoint_elements = []
177
+ distinct_elements = []
178
+
179
+ # The first SegmentUse is used to represent the structure that must
180
+ # be shared by the others: number of elements and type of elements
181
+ element_uses = instructions.head.segment_use.definition.element_uses
182
+
183
+ # Iterate over each element across all SegmentUses (think columns)
184
+ # NM1*[IL]*[ ]*..*..*..*..*..*[ ]*..*..*{..}*..
185
+ # NM1*[40]*[ ]*..*..*..*..*..*[ ]*..*..*{..}*..
186
+ element_uses.length.times do |n|
187
+ if element_uses.at(n).composite?
188
+ ms = 0 .. element_uses.at(n).definition.component_uses.length - 1
189
+ else
190
+ ms = [nil]
191
+ end
192
+
193
+ # If this is a composite element, we iterate over each component.
194
+ # Otherwise this loop iterates once with the index {m} set to nil.
195
+ ms.each do |m|
196
+ last = nil # the last subset we examined
197
+ total = Sets.empty # the union of all examined subsets
198
+
199
+ distinct = false
200
+ disjoint = true
201
+
202
+ instructions.each do |i|
203
+ element_use = i.segment_use.definition.element_uses.at(n)
204
+
205
+ unless m.nil?
206
+ element_use = element_use.definition.component_uses.at(m)
207
+ end
208
+
209
+ allowed_vals = element_use.allowed_values
210
+
211
+ # We want to know if every instruction's set of allowed values
212
+ # is disjoint (with one another). Instead of comparing each set
213
+ # with every other set, which takes (N-1)! comparisons, we can
214
+ # do it in N steps.
215
+ disjoint &&= allowed_vals.disjoint?(total)
216
+
217
+ # We also want to know if one instruction's set of allowed vals
218
+ # contains elements that aren't present in at least one other
219
+ # set. The opposite condition is easy to test: all sets contain
220
+ # the same elements (are equal). So we can similarly, check this
221
+ # condition in N steps rather than (N-1)!
222
+ distinct ||= allowed_vals != last unless last.nil?
223
+
224
+ total = allowed_vals.union(total)
225
+ last = allowed_vals
226
+ end
227
+
228
+ # puts "#{n}.#{m}: disjoint(#{disjoint}) distinct(#{distinct})"
229
+
230
+ if disjoint
231
+ # Since each instruction's set of allowed values is disjoint, we
232
+ # can build a function/hash that returns the single instruction,
233
+ # given one of the values. When given a value outside the set of
234
+ # all (combined) values, it returns nil.
235
+ disjoint_elements << [[n, m], build_disjoint(total, n, m, instructions)]
236
+ elsif distinct
237
+ # Not all instructions have the same set of allowed values. So
238
+ # we can build a function/hash that accepts one of the values
239
+ # and returns the subset of the instructions where that value
240
+ # can occur. This might be some, none, or all of the original
241
+ # instructions, so clearly this provides less information than
242
+ # if each allowed value set was disjoint.
243
+
244
+ # Currently disabled (and untested) because it doesn't look like
245
+ # any of the HIPAA schemas would use this -- so testing it would
246
+ # be a pain.
247
+ #
248
+ distinct_elements << [[n, m], build_distinct(total, n, m, instructions)]
249
+ end
250
+ end
251
+ end
252
+
253
+ [disjoint_elements, distinct_elements]
254
+ end
255
+
256
+ # @return [Hash<String, Array<Instruction>>]
257
+ def build_disjoint(total, n, m, instructions)
258
+ if total.finite?
259
+ # The sum of all allowed value sets is finite, so we know that each
260
+ # individual allowed value set is finite (we can iterate over it).
261
+ map = Hash.new
262
+
263
+ instructions.each do |i|
264
+ element_use = i.segment_use.definition.element_uses.at(n)
265
+
266
+ unless m.nil?
267
+ element_use = element_use.definition.component_uses.at(m)
268
+ end
269
+
270
+ allowed_vals = element_use.allowed_values
271
+ allowed_vals.each{|v| map[v] = i.cons }
272
+ end
273
+
274
+ map
275
+ else
276
+ # At least one of allowed value sets is infinite. This happens when
277
+ # it is RelativeComplement, which declares the values that are *not*
278
+ # allowed in the set.
279
+ map = Hash.new{|h,k| h[k] = instructions }
280
+
281
+ instructions.each do |i|
282
+ element_use = i.segment_use.definition.element_uses.at(n)
283
+ unless m.nil?
284
+ element_use = element_use.definition.component_uses.at(m)
285
+ end
286
+
287
+ allowed_vals = element_use.allowed_values
288
+
289
+ unless allowed_vals.finite?
290
+ allowed_vals.complement.each{|v| map[v] -= i }
291
+ end
292
+ end
293
+
294
+ # Clear the default_proc so accesses don't change the Hash
295
+ map.default = instructions
296
+ map
297
+ end
298
+ end
299
+
300
+ # @return [Hash<String, Array<Instruction>>]
301
+ def build_distinct(total, n, m, instructions)
302
+ if total.finite?
303
+ # The sum of all allowed value sets is finite, so we know that each
304
+ # individual allowed value set is finite (we can iterate over it).
305
+ map = Hash.new{|h,k| h[k] = [] }
306
+
307
+ instructions.each do |i|
308
+ element_use = i.segment_use.definition.element_uses.at(n)
309
+
310
+ unless m.nil?
311
+ element_use = element_use.definition.component_uses.at(m)
312
+ end
313
+
314
+ allowed_vals = element_use.allowed_values
315
+ allowed_vals.each{|v| map[v] << i }
316
+ end
317
+
318
+ # Clear the default_proc so accesses don't change the Hash
319
+ map.default = []
320
+ map
321
+ else
322
+ # At least one of allowed value sets is infinite. This happens when
323
+ # it is RelativeComplement, which declares the values that are *not*
324
+ # allowed in the set.
325
+ map = Hash.new{|h,k| h[k] = instructions }
326
+
327
+ instructions.each do |i|
328
+ element_use = i.segment_use.definition.element_uses.at(n)
329
+
330
+ unless m.nil?
331
+ element_use = element_use.definition.component_uses.at(m)
332
+ end
333
+
334
+ allowed_vals = element_use.allowed_values
335
+
336
+ unless allowed_vals.finite?
337
+ allowed_vals.complement.each{|v| map[v] -= i }
338
+ end
339
+ end
340
+
341
+ # Clear the default_proc so accesses don't change the Hash
342
+ map.default = instructions
343
+ map
344
+ end
345
+ end
346
+
347
+ # Return the value of the `m`-th elemnt, or if `n` is not nil, return
348
+ # the value of the `n`-th component from the `n`-th element. When the
349
+ # value is blank, the function returns `nil`.
350
+ #
351
+ # @param [Array<Reader::SimpleElementTok, Reader::CompositeElementTok>] element_toks
352
+ # @param [Integer] m
353
+ # @param [Integer, nil] n
354
+ #
355
+ # @return [String, nil]
356
+ def deconstruct(element_toks, m, n)
357
+ element_tok = element_toks.at(m)
358
+ element_tok = element_tok.element_toks.at(0) if element_tok.try(:repeated?)
359
+
360
+ if element_tok.blank?
361
+ nil
362
+ elsif n.nil?
363
+ element_tok.value
364
+ else
365
+ element_tok = element_tok.component_toks.at(n)
366
+
367
+ if element_tok.blank?
368
+ nil
369
+ else
370
+ element_tok.value
371
+ end
372
+ end
373
+ end
374
+ end
375
+
376
+ end
377
+
378
+ class << ConstraintTable
379
+ # @group Constructors
380
+ #########################################################################
381
+
382
+ # Given a list of {Instruction} values for the same segment identifier,
383
+ # this method constructs the appropriate concrete subclass of
384
+ # {ConstraintTable}.
385
+ #
386
+ # @param [Array<Instruction>] instructions
387
+ # @return [ConstraintTable]
388
+ def build(instructions)
389
+ if instructions.length <= 1
390
+ ConstraintTable::Stub.new(instructions)
391
+ elsif instructions.any?{|i| i.segment_use.nil? } and
392
+ not instructions.all?{|i| i.segment_use.nil? }
393
+ # When one of the instructions has a nil segment_use, it means
394
+ # the SegmentUse is determined when pushing the new state. There
395
+ # isn't a way to know the segment constraints from here.
396
+ ConstraintTable::Stub.new(instructions)
397
+ else
398
+ segment_uses = instructions.map{|i| i.segment_use }
399
+
400
+ if segment_uses.map{|u| u.object_id }.uniq.length <= 1
401
+ # The same SegmentUse may appear more than once, because the
402
+ # segment can be placed at different levels in the tree. If
403
+ # all the instructions have the same SegmentUse, they also have
404
+ # the same element constraints so we can't use them to narrow
405
+ # down the instruction list.
406
+ ConstraintTable::DepthBased.new(instructions)
407
+ else
408
+ ConstraintTable::ValueBased.new(instructions)
409
+ end
410
+ end
411
+ end
412
+
413
+ # @endgroup
414
+ #########################################################################
415
+ end
416
+
417
+ end
418
+ end
@@ -0,0 +1,112 @@
1
+ module Stupidedi
2
+ module Builder
3
+
4
+ module Generation
5
+
6
+ # @return [(StateMachine, Either<Reader::TokenReader>)]
7
+ def read(reader)
8
+ machine = self
9
+ reader = reader.read_segment
10
+
11
+ while reader.defined?
12
+ reader = reader.flatmap do |segment_tok, reader|
13
+ machine, reader =
14
+ machine.insert(segment_tok, reader)
15
+
16
+ reader.read_segment
17
+ end
18
+ end
19
+
20
+ return machine, reader
21
+ end
22
+
23
+ # @return [(StateMachine, Reader::TokenReader)]
24
+ def insert(segment_tok, reader)
25
+ active = []
26
+
27
+ @active.each do |zipper|
28
+ state = zipper.node
29
+ instructions = state.instructions.matches(segment_tok)
30
+
31
+ if instructions.empty?
32
+ active << zipper.append(FailureState.mksegment(segment_tok, state))
33
+ next
34
+ end
35
+
36
+ instructions.each do |op|
37
+ if op.push.nil?
38
+ table = zipper.node.instructions
39
+ value = zipper.node.zipper
40
+ state = zipper
41
+
42
+ op.pop_count.times do
43
+ value = value.up
44
+ state = state.up
45
+ end
46
+
47
+ # Create a new AbstractState node that has a new InstructionTable
48
+ # and also points to a new AbstractVal tree (with the new segment)
49
+ segment = AbstractState.mksegment(segment_tok, op.segment_use)
50
+ successor = state.append(state.node.copy(
51
+ :zipper => value.append(segment),
52
+ :instructions => table.pop(op.pop_count).drop(op.drop_count)))
53
+
54
+ unless op.pop_count.zero? or reader.stream?
55
+ # More general than checking if segment_tok is an ISE/GE segment
56
+ unless reader.separators.eql?(successor.node.separators) \
57
+ and reader.segment_dict.eql?(successor.node.segment_dict)
58
+ reader = reader.copy \
59
+ :separators => successor.node.separators,
60
+ :segment_dict => successor.node.segment_dict
61
+ end
62
+ end
63
+ else
64
+ table = zipper.node.instructions
65
+ value = zipper.node.zipper
66
+ state = zipper
67
+
68
+ op.pop_count.times do
69
+ value = value.up
70
+ state = state.up
71
+ end
72
+
73
+ parent = state.node.copy \
74
+ :zipper => value,
75
+ :children => [],
76
+ :separators => reader.separators,
77
+ :segment_dict => reader.segment_dict,
78
+ :instructions => table.pop(op.pop_count).drop(op.drop_count)
79
+
80
+ state = state.append(parent) unless state.root?
81
+
82
+ successor = op.push.push(state, parent, segment_tok, op.segment_use, @config)
83
+
84
+ # More general than checking if segment_tok is an ISA/GS segment
85
+ unless reader.separators.eql?(successor.node.separators) \
86
+ and reader.segment_dict.eql?(successor.node.segment_dict)
87
+ reader = reader.copy \
88
+ :separators => successor.node.separators,
89
+ :segment_dict => successor.node.segment_dict
90
+ end
91
+ end
92
+
93
+ active << successor
94
+ end
95
+ end
96
+
97
+ return StateMachine.new(@config, active), reader
98
+ end
99
+
100
+ # @return [StateMachine]
101
+ def replace(segment_tok, reader)
102
+ # @todo
103
+ end
104
+
105
+ # @return [StateMachine]
106
+ def remove
107
+ # @todo
108
+ end
109
+
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,102 @@
1
+ module Stupidedi
2
+ module Builder
3
+
4
+ class Instruction
5
+ include Inspect
6
+
7
+ # The segment identifier to which this {Instruction} applies
8
+ #
9
+ # @return [Symbol]
10
+ attr_reader :segment_id
11
+
12
+ # The segment use contains helpful information about the context of the
13
+ # segment within a definition tree (eg the parent structure's definition).
14
+ # It also enumerates the allowed values for segment qualifiers, which is
15
+ # used to minimize non-determinism.
16
+ #
17
+ # @return [Schema::SegmentUse]
18
+ attr_reader :segment_use
19
+
20
+ # This indicates the number of levels to ascend and terminate within the
21
+ # tree before storing the segment.
22
+ #
23
+ # @return [Integer]
24
+ attr_reader :pop_count
25
+
26
+ # This controls the allowed order in which structures may occur, by
27
+ # indicating the number of instructions to remove from the beginning of
28
+ # the instruction table.
29
+ #
30
+ # Repeatable structures have a value that ensures that their instruction
31
+ # remains in the successor table.
32
+ #
33
+ # Sibling structures that have the same position (as defined by their
34
+ # {Schema::SegmentUse}) will have equal drop_count values such that all of
35
+ # the sibling instructions remain in the successor table when any one of
36
+ # them is executed.
37
+ #
38
+ # @return [Integer]
39
+ attr_reader :drop_count
40
+
41
+ # This indicates that a child node should be added to the tree, which
42
+ # will then contain the segment.
43
+ #
44
+ # When a segment indicates the start of a child structure, the class
45
+ # indicated by this attribute is expected to respond to `push` by
46
+ # creating a new {AbstractState}.
47
+ #
48
+ # @return [Zipper::AbstractCursor]
49
+ attr_reader :push
50
+
51
+ def initialize(segment_id, segment_use, pop, drop, push)
52
+ @segment_id, @segment_use, @pop_count, @drop_count, @push =
53
+ segment_id || segment_use.definition.id, segment_use, pop, drop, push
54
+ end
55
+
56
+ # @return [Instruction]
57
+ def copy(changes = {})
58
+ Instruction.new \
59
+ changes.fetch(:segment_id, @segment_id),
60
+ changes.fetch(:segment_use, @segment_use),
61
+ changes.fetch(:pop_count, @pop_count),
62
+ changes.fetch(:drop_count, @drop_count),
63
+ changes.fetch(:push, @push)
64
+ end
65
+
66
+ # @return [void]
67
+ def pretty_print(q)
68
+ id = '% 3s' % @segment_id.to_s
69
+
70
+ unless @segment_use.nil?
71
+ width = 18
72
+ name = @segment_use.definition.name
73
+
74
+ # Truncate the segment name to `width` characters
75
+ if name.length > width - 2
76
+ id << ": #{name.slice(0, width - 2)}.."
77
+ else
78
+ id << ": #{name.ljust(width)}"
79
+ end
80
+ end
81
+
82
+ q.text "Instruction[#{'% 3s' % id}]"
83
+
84
+ q.group(6, "(", ")") do
85
+ q.breakable ""
86
+
87
+ q.text "pop: #{@pop_count},"
88
+ q.breakable
89
+
90
+ q.text "drop: #{@drop_count}"
91
+
92
+ unless @push.nil?
93
+ q.text ","
94
+ q.breakable
95
+ q.text "push: #{@push.try{|c| c.name.split('::').last}}"
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+ end