X12 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/CHANGELOG +13 -0
  2. data/COPYING +502 -0
  3. data/README +309 -0
  4. data/Rakefile +157 -0
  5. data/TODO +6 -0
  6. data/doc/classes/X12.html +174 -0
  7. data/doc/classes/X12/Base.html +677 -0
  8. data/doc/classes/X12/Composite.html +156 -0
  9. data/doc/classes/X12/Empty.html +186 -0
  10. data/doc/classes/X12/Field.html +339 -0
  11. data/doc/classes/X12/Loop.html +202 -0
  12. data/doc/classes/X12/Parser.html +306 -0
  13. data/doc/classes/X12/Segment.html +277 -0
  14. data/doc/classes/X12/Table.html +198 -0
  15. data/doc/created.rid +1 -0
  16. data/doc/files/CHANGELOG.html +108 -0
  17. data/doc/files/README.html +474 -0
  18. data/doc/files/TODO.html +95 -0
  19. data/doc/files/lib/X12/Base_rb.html +83 -0
  20. data/doc/files/lib/X12/Composite_rb.html +83 -0
  21. data/doc/files/lib/X12/Empty_rb.html +83 -0
  22. data/doc/files/lib/X12/Field_rb.html +83 -0
  23. data/doc/files/lib/X12/Loop_rb.html +83 -0
  24. data/doc/files/lib/X12/Parser_rb.html +83 -0
  25. data/doc/files/lib/X12/Segment_rb.html +83 -0
  26. data/doc/files/lib/X12/Table_rb.html +83 -0
  27. data/doc/files/lib/X12_rb.html +100 -0
  28. data/doc/fr_class_index.html +35 -0
  29. data/doc/fr_file_index.html +38 -0
  30. data/doc/fr_method_index.html +62 -0
  31. data/doc/index.html +27 -0
  32. data/doc/rdoc-style.css +208 -0
  33. data/example/factory.rb +92 -0
  34. data/example/parse.rb +56 -0
  35. data/lib/X12.rb +50 -0
  36. data/lib/X12/Base.rb +192 -0
  37. data/lib/X12/Composite.rb +37 -0
  38. data/lib/X12/Empty.rb +43 -0
  39. data/lib/X12/Field.rb +81 -0
  40. data/lib/X12/Loop.rb +74 -0
  41. data/lib/X12/Parser.rb +98 -0
  42. data/lib/X12/Segment.rb +92 -0
  43. data/lib/X12/Table.rb +44 -0
  44. data/lib/X12/x12syntax.treetop +256 -0
  45. data/misc/997.d12 +885 -0
  46. data/misc/rdoc_template.rb +697 -0
  47. data/test/tc_factory_997.rb +130 -0
  48. data/test/tc_parse_997.rb +146 -0
  49. data/test/ts_x12.rb +27 -0
  50. metadata +108 -0
@@ -0,0 +1 @@
1
+ Thu, 13 Nov 2008 13:53:19 -0600
@@ -0,0 +1,108 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: CHANGELOG</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <!-- banner header -->
50
+
51
+ <div id="bodyContent">
52
+
53
+
54
+
55
+ <div id="contextContent">
56
+
57
+ <div id="description">
58
+ <h1>CHANGELOG</h1>
59
+ <p>
60
+ $Id: CHANGELOG 35 2008-11-13 18:33:44Z ikk $
61
+ </p>
62
+ <h2>11/15/08 - Release 0.0.5, first public one</h2>
63
+ <ul>
64
+ <li>Added comments.
65
+
66
+ </li>
67
+ <li>Added examples.
68
+
69
+ </li>
70
+ <li>Wrote README
71
+
72
+ </li>
73
+ </ul>
74
+ <h2>4/10/08 - Release 0.0.1</h2>
75
+ <ul>
76
+ <li>Internal release for testing
77
+
78
+ </li>
79
+ </ul>
80
+
81
+ </div>
82
+
83
+
84
+ </div>
85
+
86
+
87
+ </div>
88
+
89
+
90
+ <!-- if includes -->
91
+
92
+ <div id="section">
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+ <!-- if method_list -->
102
+
103
+
104
+ </div>
105
+
106
+
107
+ </body>
108
+ </html>
@@ -0,0 +1,474 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: README</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <!-- banner header -->
50
+
51
+ <div id="bodyContent">
52
+
53
+
54
+
55
+ <div id="contextContent">
56
+
57
+ <div id="description">
58
+ <h1>X12Parser - a library to manipulate <a href="../classes/X12.html">X12</a> structures using native Ruby syntax</h1>
59
+ <p>
60
+ $Id: README 40 2008-11-13 19:51:31Z ikk $
61
+ </p>
62
+ <p>
63
+ <b>WARNING</b> <tt>The project is in development. Contributors are
64
+ welcome.</tt>
65
+ </p>
66
+ <p>
67
+ Project home is at <a
68
+ href="http://rubyforge.org/projects/x12parser">rubyforge.org/projects/x12parser</a>/.
69
+ Please note, this is a different project from <a
70
+ href="http://rubyforge.org/projects/x12-parser/">Chris Parker's port</a> of
71
+ <a
72
+ href="http://search.cpan.org/~prasad/X12-0.09/lib/X12/Parser.pm">X12::Parser
73
+ Perl module</a>.
74
+ </p>
75
+ <h2>The goal</h2>
76
+ <p>
77
+ The idea is to access <a href="../classes/X12.html">X12</a> messages
78
+ directly from Ruby, i.e., using a syntax like
79
+ </p>
80
+ <pre>
81
+ message.L1000.L1010[1].AK4.DataElementReferenceNumber
82
+ </pre>
83
+ <p>
84
+ This syntax can be used to get and set any field of an <a
85
+ href="../classes/X12.html">X12</a> message and it makes <a
86
+ href="../classes/X12.html">X12</a> parsing much more straightforward and
87
+ self-documenting.
88
+ </p>
89
+ <h2>The problem</h2>
90
+ <p>
91
+ <a href="../classes/X12.html">X12</a> is a set of &quot;standards&quot;
92
+ possessing all the elegance of an elephant designed by committee, and quite
93
+ literally so, see <a href="http://www.x12.org">www.x12.org</a>. <a
94
+ href="../classes/X12.html">X12</a> defines rough syntax for specifying text
95
+ messages, but each of more than 300 specifications defines its own message
96
+ structure. While messages themselves are easy to parse with a simple
97
+ tokenizer, their semantics is heavily dependent on the domain. For example,
98
+ this is <a href="../classes/X12.html">X12</a>/997 message conveying
99
+ &quot;Functional Acknowledgment&quot;:
100
+ </p>
101
+ <pre>
102
+ ST*997*2878~AK1*HS*293328532~AK2*270*307272179~AK3*NM1*8*L1010_0*8~
103
+ AK4*0:0*66*1~AK4*0:1*66*1~AK4*0:2*66*1~AK3*NM1*8*L1010_1*8~AK4*1:0*
104
+ 66*1~AK4*1:1*66*1~AK3*NM1*8*L1010_2*8~AK4*2:0*66*1~AK5*R*5~AK9*R*1*
105
+ 1*0~SE*8*2878~
106
+ </pre>
107
+ <p>
108
+ I.e., <a href="../classes/X12.html">X12</a> defines an alphabet and
109
+ somewhat of a dictionary - not a grammar or semantics for each particular
110
+ data interchange conversation. Because of many entrenched implementations
111
+ and government mandates, the <a href="../classes/X12.html">X12</a> is not
112
+ going to die anytime soon, unfortunately.
113
+ </p>
114
+ <p>
115
+ The message above can be easily represented in Ruby as a nested array:
116
+ </p>
117
+ <pre>
118
+ m = [
119
+ ['ST', '997', '2878'],
120
+ ['AK1', 'HS', '293328532'],
121
+ ['AK2', '270', '307272179'],
122
+ ['AK3', 'NM1', '8', 'L1010_0', '8'],
123
+ ['AK4', '0:0', '66', '1'],
124
+ ['AK4', '0:1', '66', '1'],
125
+ ['AK4', '0:2', '66', '1'],
126
+ ['AK3', 'NM1', '8', 'L1010_1', '8'],
127
+ ['AK4', '1:0', '66', '1'],
128
+ ['AK4', '1:1', '66', '1'],
129
+ ['AK3', 'NM1', '8', 'L1010_2', '8'],
130
+ ['AK4', '2:0', '66', '1'],
131
+ ['AK5', 'R', '5'],
132
+ ['AK9', 'R', '1', '1', '0'],
133
+ ['SE', '8', '2878'],
134
+ ]
135
+ </pre>
136
+ <p>
137
+ but it will not help any since, say, segment &#8216;AK4&#8217; is
138
+ ambiguously defined and its meaning not at all obvious until the
139
+ message&#8216;s structure is interpreted and correct &#8216;AK4&#8217;
140
+ segment is found.
141
+ </p>
142
+ <h2>The solution</h2>
143
+ <h3>Message structure</h3>
144
+ <p>
145
+ Each participant in EDI has to know the structure of the data coming across
146
+ the wire - <a href="../classes/X12.html">X12</a> or no <a
147
+ href="../classes/X12.html">X12</a>. The <a
148
+ href="../classes/X12.html">X12</a> structures are defined in so-called
149
+ Implementation Guides - thick books with all the data pieces spelled out.
150
+ There is no other choice, but to invent a computer-readable definition
151
+ language that will codify these books. For example, the <a
152
+ href="../classes/X12.html">X12</a>/997 message can be defined as
153
+ </p>
154
+ <pre>
155
+ loop 997 1:1
156
+ {
157
+ segment ST 1:1
158
+ segment AK1 1:1
159
+ loop L1000 0:999999
160
+ {
161
+ segment AK2 0:1
162
+ loop L1010 0:999999
163
+ {
164
+ segment AK3 0:1
165
+ segment AK4 0:99
166
+ } # L1010
167
+ segment AK5 1:1
168
+ } # L1000
169
+ segment AK9 1:1
170
+ segment SE 1:1
171
+ } # 997
172
+ </pre>
173
+ <p>
174
+ Namely, the 997 is a &#8216;loop&#8217; containing segments ST (only one -
175
+ &#8216;1:1&#8217;), AK1 (also only one), another loop L1000 (zero or many
176
+ repeats), segments AK9 and SE. The loop L1000 can contain a segment AK2
177
+ (optional - &#8216;0:1&#8217;) and another loop L1010 (zero or many), and
178
+ so on.
179
+ </p>
180
+ <p>
181
+ The segments&#8217; structure can be further defined as, for example,
182
+ </p>
183
+ <pre>
184
+ segment AK2 {
185
+ TransactionSetIdentifierCode S R 3-3 Tbl143
186
+ TransactionSetControlNumber S R 4-9
187
+ } # AK2
188
+ </pre>
189
+ <p>
190
+ wihch defines a segment AK2 as having to fields:
191
+ TransactionSetIdentifierCode and TransactionSetControlNumber. The field
192
+ TransactionSetIdentifierCode is defined as having a type of string
193
+ (&#8216;S&#8217;), begin required (&#8216;R&#8217;), having length of
194
+ minimum 3 and maximum 3 characters (&#8216;3-3&#8217;), and being validated
195
+ against a table Tbl143. The validation table is defined as
196
+ </p>
197
+ <pre>
198
+ table Tbl143 {
199
+ 100 Insurance Plan Description
200
+ 101 Name and Address Lists
201
+ ...
202
+ 997 Functional Acknowledgment
203
+ 998 Set Cancellation
204
+ } # Tbl143
205
+ </pre>
206
+ <p>
207
+ where required values are first tokens on each line, i.e., 100, 101,
208
+ &#8230;, 997, 998.
209
+ </p>
210
+ <p>
211
+ This message is fully flashed out in an example &#8216;misc/997.d12&#8217;
212
+ file, copied from the ASC X12N 276/277 (004010X093) &quot;Health Care Claim
213
+ Status Request and Response&quot; National Electronic Data Interchange
214
+ Transaction Set Implementation Guide.
215
+ </p>
216
+ <p>
217
+ Now expressions like
218
+ </p>
219
+ <pre>
220
+ message.L1000.L1010[1].AK4.DataElementReferenceNumber
221
+ </pre>
222
+ <p>
223
+ start making sense of sorts, overall <a
224
+ href="../classes/X12.html">X12</a>&#8216;s idiocy notwithstanding -
225
+ it&#8216;s a field called &#8216;DataElementReferenceNumber&#8217; of a
226
+ first of possibly many segments &#8216;AK4&#8217; found in the second
227
+ repeat of the loop &#8216;L1010&#8217; inside the enclosing loop
228
+ &#8216;L1000&#8217;. The meaning of the value &#8216;66&#8217; found in
229
+ this field is still in the eye of the beholder, but, at least its location
230
+ is clearly identified in the message.
231
+ </p>
232
+ <h3><a href="../classes/X12.html">X12</a> Structure Definition Language (d12)</h3>
233
+ <p>
234
+ The syntax of the <a href="../classes/X12.html">X12</a> structure
235
+ definition language should be apparent from the &#8216;997.d12&#8217; file
236
+ enclosed with the package. The strict definition is formalized in
237
+ &#8216;lib/X12/x12syntax.treetop&#8217; file.
238
+ </p>
239
+ <h3>Parsing</h3>
240
+ <p>
241
+ Here is how to parse an <a href="../classes/X12.html">X12</a>/997 message
242
+ (the source is in example/parse.rb):
243
+ </p>
244
+ <pre>
245
+ require 'x12'
246
+
247
+ # Read message definition and create an actual parser
248
+ # by compiling .d12 file
249
+ parser = X12::Parser.new('misc/997.d12')
250
+
251
+ # Define a test message to parse
252
+ m997='ST*997*2878~AK1*HS*293328532~AK2*270*307272179~'\
253
+ 'AK3*NM1*8*L1010_0*8~AK4*0:0*66*1~AK4*0:1*66*1~AK4*0:2*'\
254
+ '66*1~AK3*NM1*8*L1010_1*8~AK4*1:0*66*1~AK4*1:1*66*1~AK3*'\
255
+ 'NM1*8*L1010_2*8~AK4*2:0*66*1~AK5*R*5~AK9*R*1*1*0~SE*8*2878~'
256
+
257
+ # Parse the message
258
+ r = parser.parse('997', m997)
259
+
260
+ # Access components of the message as desired
261
+
262
+ # Whole ST segment: -&gt; ST*997*2878~
263
+ puts r.ST
264
+
265
+ # One filed, Group Control Number of AK1 -&gt; 293328532
266
+ puts r.AK1.GroupControlNumber
267
+
268
+ # Individual loop, namely, third L1010 sub-loop of
269
+ # L1000 loop: -&gt; AK3*NM1*8*L1010_2*8~AK4*2:0*66*1~
270
+ puts r.L1000.L1010[2]
271
+
272
+ # First encounter of Data Element Reference Number of the
273
+ # first L1010 sub-loop of L1000 loop -&gt; 66
274
+ puts r.L1000.L1010.AK4.DataElementReferenceNumber
275
+
276
+ # Number of L1010 sub-loops in L1000 loop -&gt; 3
277
+ puts r.L1000.L1010.size
278
+ </pre>
279
+ <h3>Generating</h3>
280
+ <p>
281
+ Here is how to perform a reverse operation and generate a well-formed 997
282
+ message (the source is in example/factory.rb):
283
+ </p>
284
+ <pre>
285
+ require 'x12'
286
+
287
+ # Read message definition and create an actual parser
288
+ # by compiling .d12 file
289
+ parser = X12::Parser.new('misc/997.d12')
290
+
291
+ # Make a new 997 message
292
+ r = parser.factory('997')
293
+
294
+ #
295
+ # Set various fields as desired
296
+ #
297
+
298
+ # Set fields directly
299
+ r.ST.TransactionSetIdentifierCode = 997
300
+ r.ST.TransactionSetControlNumber = '2878'
301
+
302
+ # Set fields inside a segment (AK1 in this case)
303
+ r.AK1 { |ak1|
304
+ ak1.FunctionalIdentifierCode = 'HS'
305
+ ak1.GroupControlNumber = 293328532
306
+ }
307
+
308
+ # Set fields deeply inside a segment inside
309
+ # nested loops (L1000/L1010/AK4 in this case)
310
+ r.L1000.L1010.AK4.DataElementSyntaxErrorCode = 55
311
+ r.L1000.AK2.TransactionSetIdentifierCode = 270
312
+
313
+ # Set nested loops
314
+ r.L1000.L1010 {|l|
315
+ l.AK3 {|s|
316
+ s.SegmentIdCode = 'NM1'
317
+ s.LoopIdentifierCode = 'L1000D'
318
+ }
319
+ l.AK4 {|s|
320
+ s.CopyOfBadDataElement = 'Bad element'
321
+ }
322
+ }
323
+
324
+ # Add loop repeats
325
+ r.L1000.repeat {|l1000|
326
+ (0..1).each {|loop_repeat| # Two repeats of the loop L1010
327
+ l1000.L1010.repeat {|l1010|
328
+ l1010.AK3 {|s|
329
+ s.SegmentIdCode = 'DMG'
330
+ s.SegmentPositionInTransactionSet = 0
331
+ s.LoopIdentifierCode = 'L1010'
332
+ s.SegmentSyntaxErrorCode = 22
333
+ } if loop_repeat == 0 # AK3 only in the first repeat of L1010
334
+ (0..1).each {|ak4_repeat| # Two repeats of the segment AK4
335
+ l1010.AK4.repeat {|s|
336
+ s.PositionInSegment = loop_repeat
337
+ s.DataElementSyntaxErrorCode = ak4_repeat
338
+ } # s
339
+ } # ak4_repeat
340
+ } # l1010
341
+ } # loop_repeat
342
+
343
+ l1000.AK5{|a|
344
+ a.TransactionSetAcknowledgmentCode = 666
345
+ a.TransactionSetSyntaxErrorCode4 = 999
346
+ } # a
347
+ } # l1000
348
+
349
+ # Print the message as a string -&gt; ST*997*2878~AK1*HS*293328532~
350
+ # AK2*270*~AK3*NM1**L1000D~AK4***55*Bad element~AK5*~AK3*DMG*0*
351
+ # L1010*22~AK4*0**0~AK4*0**1~AK4*1**0~AK4*1**1~AK5*666****999~
352
+ # AK9****~SE**~
353
+ puts r.render
354
+ </pre>
355
+ <h2>Download</h2>
356
+ <p>
357
+ The latest <a href="../classes/X12.html">X12</a> library version can be
358
+ downloaded from <a
359
+ href="http://rubyforge.org/frs/?group_id=7297">rubyforge.org/frs/?group_id=7297</a>
360
+ </p>
361
+ <h2>Installation</h2>
362
+ <p>
363
+ You can install <a href="../classes/X12.html">X12</a> library with the
364
+ following command.
365
+ </p>
366
+ <pre>
367
+ % gem install X12
368
+ </pre>
369
+ <p>
370
+ If you install directly from the <a href="../classes/X12.html">X12</a>*.gem
371
+ file, it requires these packages to be installed first:
372
+ </p>
373
+ <ul>
374
+ <li><a href="http://rubyforge.org/projects/treetop/">Treetop</a>
375
+
376
+ </li>
377
+ <li><a href="http://rubyforge.org/projects/polyglot/">Polyglot</a>
378
+
379
+ </li>
380
+ </ul>
381
+ <h2>License</h2>
382
+ <p>
383
+ <a href="../classes/X12.html">X12</a> library is released under the Lesser
384
+ GPL license, see <a
385
+ href="http://www.gnu.org/licenses/lgpl.txt">www.gnu.org/licenses/lgpl.txt</a>
386
+ </p>
387
+ <h2>Major deficiencies</h2>
388
+ <ul>
389
+ <li>Validation is not implemented.
390
+
391
+ </li>
392
+ <li>Field types and sizes are ignored.
393
+
394
+ </li>
395
+ <li>No access methods for composites&#8217; fields.
396
+
397
+ </li>
398
+ </ul>
399
+ <h2>Wish list</h2>
400
+ <ul>
401
+ <li>.d12 files should have an &#8216;include&#8217; facility, so data
402
+ definitions can be reused for different messages.
403
+
404
+ </li>
405
+ <li>It would be nice to codify all popular <a
406
+ href="../classes/X12.html">X12</a> messages in .d12 format.
407
+
408
+ </li>
409
+ </ul>
410
+ <h2>Support</h2>
411
+ <p>
412
+ Please use the following:
413
+ </p>
414
+ <ul>
415
+ <li>forums on Rubyforge for general discussions, <a
416
+ href="http://rubyforge.org/forum/?group_id=7297">rubyforge.org/forum/?group_id=7297</a>
417
+
418
+ </li>
419
+ <li>trackers to submit bugs or feature requests, <a
420
+ href="http://rubyforge.org/tracker/?group_id=7297">rubyforge.org/tracker/?group_id=7297</a>
421
+
422
+ </li>
423
+ <li>to contact the author, send mail to prelude rubyforge org
424
+
425
+ </li>
426
+ </ul>
427
+ <h2>Acknowledgments</h2>
428
+ <p>
429
+ The authors of the project were inspired by the following works:
430
+ </p>
431
+ <ol>
432
+ <li>The Perl <a href="../classes/X12.html">X12</a> parser by Prasad
433
+ Poruporuthan, <a
434
+ href="http://search.cpan.org/~prasad/X12-0.09/lib/X12/Parser.pm">search.cpan.org/~prasad/X12-0.09/lib/X12/Parser.pm</a>
435
+
436
+ </li>
437
+ <li>The Ruby port of the above by Chris Parker, <a
438
+ href="http://rubyforge.org/projects/x12-parser">rubyforge.org/projects/x12-parser</a>/
439
+
440
+ </li>
441
+ <li>Treetop Ruby parser, <a
442
+ href="http://treetop.rubyforge.org">treetop.rubyforge.org</a>
443
+
444
+ </li>
445
+ </ol>
446
+
447
+ </div>
448
+
449
+
450
+ </div>
451
+
452
+
453
+ </div>
454
+
455
+
456
+ <!-- if includes -->
457
+
458
+ <div id="section">
459
+
460
+
461
+
462
+
463
+
464
+
465
+
466
+
467
+ <!-- if method_list -->
468
+
469
+
470
+ </div>
471
+
472
+
473
+ </body>
474
+ </html>