X12 0.0.5
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.
- data/CHANGELOG +13 -0
- data/COPYING +502 -0
- data/README +309 -0
- data/Rakefile +157 -0
- data/TODO +6 -0
- data/doc/classes/X12.html +174 -0
- data/doc/classes/X12/Base.html +677 -0
- data/doc/classes/X12/Composite.html +156 -0
- data/doc/classes/X12/Empty.html +186 -0
- data/doc/classes/X12/Field.html +339 -0
- data/doc/classes/X12/Loop.html +202 -0
- data/doc/classes/X12/Parser.html +306 -0
- data/doc/classes/X12/Segment.html +277 -0
- data/doc/classes/X12/Table.html +198 -0
- data/doc/created.rid +1 -0
- data/doc/files/CHANGELOG.html +108 -0
- data/doc/files/README.html +474 -0
- data/doc/files/TODO.html +95 -0
- data/doc/files/lib/X12/Base_rb.html +83 -0
- data/doc/files/lib/X12/Composite_rb.html +83 -0
- data/doc/files/lib/X12/Empty_rb.html +83 -0
- data/doc/files/lib/X12/Field_rb.html +83 -0
- data/doc/files/lib/X12/Loop_rb.html +83 -0
- data/doc/files/lib/X12/Parser_rb.html +83 -0
- data/doc/files/lib/X12/Segment_rb.html +83 -0
- data/doc/files/lib/X12/Table_rb.html +83 -0
- data/doc/files/lib/X12_rb.html +100 -0
- data/doc/fr_class_index.html +35 -0
- data/doc/fr_file_index.html +38 -0
- data/doc/fr_method_index.html +62 -0
- data/doc/index.html +27 -0
- data/doc/rdoc-style.css +208 -0
- data/example/factory.rb +92 -0
- data/example/parse.rb +56 -0
- data/lib/X12.rb +50 -0
- data/lib/X12/Base.rb +192 -0
- data/lib/X12/Composite.rb +37 -0
- data/lib/X12/Empty.rb +43 -0
- data/lib/X12/Field.rb +81 -0
- data/lib/X12/Loop.rb +74 -0
- data/lib/X12/Parser.rb +98 -0
- data/lib/X12/Segment.rb +92 -0
- data/lib/X12/Table.rb +44 -0
- data/lib/X12/x12syntax.treetop +256 -0
- data/misc/997.d12 +885 -0
- data/misc/rdoc_template.rb +697 -0
- data/test/tc_factory_997.rb +130 -0
- data/test/tc_parse_997.rb +146 -0
- data/test/ts_x12.rb +27 -0
- metadata +108 -0
data/doc/index.html
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
|
5
|
+
|
6
|
+
<!--
|
7
|
+
|
8
|
+
X12 -- an X12 parsing library
|
9
|
+
|
10
|
+
-->
|
11
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
12
|
+
<head>
|
13
|
+
<title>X12 -- an X12 parsing library</title>
|
14
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
15
|
+
</head>
|
16
|
+
|
17
|
+
<frameset cols="20%,*">
|
18
|
+
<frameset rows="15%,35%,50%">
|
19
|
+
<frame src="fr_file_index.html" title="Files" name="Files">
|
20
|
+
<frame src="fr_class_index.html" name="Classes">
|
21
|
+
<frame src="fr_method_index.html" name="Methods">
|
22
|
+
</frameset>
|
23
|
+
<frameset>
|
24
|
+
<frame src="files/README.html" name="docwin">
|
25
|
+
</frameset>
|
26
|
+
</frameset>
|
27
|
+
</html>
|
data/doc/rdoc-style.css
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
body {
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
4
|
+
font-size: 90%;
|
5
|
+
margin: 0;
|
6
|
+
margin-left: 40px;
|
7
|
+
padding: 0;
|
8
|
+
background: #efefef;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
12
|
+
h1 { font-size: 150%; }
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
14
|
+
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
16
|
+
a:hover { background: #039; color: #eef; }
|
17
|
+
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
19
|
+
td > a {
|
20
|
+
background: transparent;
|
21
|
+
color: #039;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* and inside a section title */
|
26
|
+
.section-title > a {
|
27
|
+
background: transparent;
|
28
|
+
color: #eee;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* === Structural elements =================================== */
|
33
|
+
|
34
|
+
div#index {
|
35
|
+
margin: 0;
|
36
|
+
margin-left: -40px;
|
37
|
+
padding: 0;
|
38
|
+
font-size: 90%;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div#index a {
|
43
|
+
margin-left: 0.7em;
|
44
|
+
}
|
45
|
+
|
46
|
+
div#index .section-bar {
|
47
|
+
margin-left: 0px;
|
48
|
+
padding-left: 0.7em;
|
49
|
+
background: #ccc;
|
50
|
+
font-size: small;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
div#classHeader, div#fileHeader {
|
55
|
+
width: auto;
|
56
|
+
color: white;
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
58
|
+
margin: 0;
|
59
|
+
margin-left: -40px;
|
60
|
+
border-bottom: 3px solid #006;
|
61
|
+
}
|
62
|
+
|
63
|
+
div#classHeader a, div#fileHeader a {
|
64
|
+
background: inherit;
|
65
|
+
color: white;
|
66
|
+
}
|
67
|
+
|
68
|
+
div#classHeader td, div#fileHeader td {
|
69
|
+
background: inherit;
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
div#fileHeader {
|
75
|
+
background: #057;
|
76
|
+
}
|
77
|
+
|
78
|
+
div#classHeader {
|
79
|
+
background: #048;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
.class-name-in-header {
|
84
|
+
font-size: 180%;
|
85
|
+
font-weight: bold;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
div#bodyContent {
|
90
|
+
padding: 0 0 0 0;
|
91
|
+
}
|
92
|
+
|
93
|
+
div#description {
|
94
|
+
padding: 0.5em 0.5em;
|
95
|
+
border: 1px dotted #999;
|
96
|
+
margin-left: -40px;
|
97
|
+
}
|
98
|
+
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
100
|
+
color: #125;;
|
101
|
+
background: transparent;
|
102
|
+
}
|
103
|
+
|
104
|
+
div#validator-badges {
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
div#validator-badges img { border: 0; }
|
108
|
+
|
109
|
+
div#copyright {
|
110
|
+
color: #333;
|
111
|
+
background: #efefef;
|
112
|
+
font: 0.75em sans-serif;
|
113
|
+
margin-top: 5em;
|
114
|
+
margin-bottom: 0;
|
115
|
+
padding: 0.5em 2em;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/* === Classes =================================== */
|
120
|
+
|
121
|
+
table.header-table {
|
122
|
+
color: white;
|
123
|
+
font-size: small;
|
124
|
+
}
|
125
|
+
|
126
|
+
.type-note {
|
127
|
+
font-size: small;
|
128
|
+
color: #DEDEDE;
|
129
|
+
}
|
130
|
+
|
131
|
+
.xxsection-bar {
|
132
|
+
background: #eee;
|
133
|
+
color: #333;
|
134
|
+
padding: 3px;
|
135
|
+
}
|
136
|
+
|
137
|
+
.section-bar {
|
138
|
+
color: #333;
|
139
|
+
border-bottom: 1px solid #999;
|
140
|
+
margin-left: -20px;
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
.section-title {
|
145
|
+
background: #79a;
|
146
|
+
color: #eee;
|
147
|
+
padding: 3px;
|
148
|
+
margin-top: 2em;
|
149
|
+
margin-left: -30px;
|
150
|
+
border: 1px solid #999;
|
151
|
+
}
|
152
|
+
|
153
|
+
.top-aligned-row { vertical-align: top }
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
155
|
+
|
156
|
+
/* --- Context section classes ----------------------- */
|
157
|
+
|
158
|
+
.context-row { }
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
162
|
+
|
163
|
+
/* --- Method classes -------------------------- */
|
164
|
+
.method-detail {
|
165
|
+
background: #efefef;
|
166
|
+
padding: 0;
|
167
|
+
margin-top: 0.5em;
|
168
|
+
margin-bottom: 1em;
|
169
|
+
border: 1px dotted #ccc;
|
170
|
+
}
|
171
|
+
.method-heading {
|
172
|
+
color: black;
|
173
|
+
background: #ccc;
|
174
|
+
border-bottom: 1px solid #666;
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
176
|
+
}
|
177
|
+
.method-signature { color: black; background: inherit; }
|
178
|
+
.method-name { font-weight: bold; }
|
179
|
+
.method-args { font-style: italic; }
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
181
|
+
|
182
|
+
/* --- Source code sections -------------------- */
|
183
|
+
|
184
|
+
a.source-toggle { font-size: 90%; }
|
185
|
+
div.method-source-code {
|
186
|
+
background: #888888;
|
187
|
+
color: #ffdead;
|
188
|
+
margin: 1em;
|
189
|
+
padding: 0.5em;
|
190
|
+
border: 1px dashed #999;
|
191
|
+
overflow: hidden;
|
192
|
+
}
|
193
|
+
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
195
|
+
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
197
|
+
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
199
|
+
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
data/example/factory.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of the X12Parser library that provides tools to
|
3
|
+
# manipulate X12 messages using Ruby native syntax.
|
4
|
+
#
|
5
|
+
# http://x12parser.rubyforge.org
|
6
|
+
#
|
7
|
+
# Copyright (C) 2008 APP Design, Inc.
|
8
|
+
#
|
9
|
+
# This library is free software; you can redistribute it and/or
|
10
|
+
# modify it under the terms of the GNU Lesser General Public
|
11
|
+
# License as published by the Free Software Foundation; either
|
12
|
+
# version 2.1 of the License, or (at your option) any later version.
|
13
|
+
#
|
14
|
+
# This library is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17
|
+
# Lesser General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Lesser General Public
|
20
|
+
# License along with this library; if not, write to the Free Software
|
21
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
22
|
+
#++
|
23
|
+
#
|
24
|
+
require 'x12'
|
25
|
+
|
26
|
+
# Read message definition and create an actual parser
|
27
|
+
# by compiling .d12 file
|
28
|
+
parser = X12::Parser.new('misc/997.d12')
|
29
|
+
|
30
|
+
# Make a new 997 message
|
31
|
+
r = parser.factory('997')
|
32
|
+
|
33
|
+
#
|
34
|
+
# Set various fields as desired
|
35
|
+
#
|
36
|
+
|
37
|
+
# Set fields directly
|
38
|
+
r.ST.TransactionSetIdentifierCode = 997
|
39
|
+
r.ST.TransactionSetControlNumber = '2878'
|
40
|
+
|
41
|
+
# Set fields inside a segment (AK1 in this case)
|
42
|
+
r.AK1 { |ak1|
|
43
|
+
ak1.FunctionalIdentifierCode = 'HS'
|
44
|
+
ak1.GroupControlNumber = 293328532
|
45
|
+
}
|
46
|
+
|
47
|
+
# Set fields deeply inside a segment inside
|
48
|
+
# nested loops (L1000/L1010/AK4 in this case)
|
49
|
+
r.L1000.L1010.AK4.DataElementSyntaxErrorCode = 55
|
50
|
+
r.L1000.AK2.TransactionSetIdentifierCode = 270
|
51
|
+
|
52
|
+
# Set nested loops
|
53
|
+
r.L1000.L1010 {|l|
|
54
|
+
l.AK3 {|s|
|
55
|
+
s.SegmentIdCode = 'NM1'
|
56
|
+
s.LoopIdentifierCode = 'L1000D'
|
57
|
+
}
|
58
|
+
l.AK4 {|s|
|
59
|
+
s.CopyOfBadDataElement = 'Bad element'
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
# Add loop repeats
|
64
|
+
r.L1000.repeat {|l1000|
|
65
|
+
(0..1).each {|loop_repeat| # Two repeats of the loop L1010
|
66
|
+
l1000.L1010.repeat {|l1010|
|
67
|
+
l1010.AK3 {|s|
|
68
|
+
s.SegmentIdCode = 'DMG'
|
69
|
+
s.SegmentPositionInTransactionSet = 0
|
70
|
+
s.LoopIdentifierCode = 'L1010'
|
71
|
+
s.SegmentSyntaxErrorCode = 22
|
72
|
+
} if loop_repeat == 0 # AK3 only in the first repeat of L1010
|
73
|
+
(0..1).each {|ak4_repeat| # Two repeats of the segment AK4
|
74
|
+
l1010.AK4.repeat {|s|
|
75
|
+
s.PositionInSegment = loop_repeat
|
76
|
+
s.DataElementSyntaxErrorCode = ak4_repeat
|
77
|
+
} # s
|
78
|
+
} # ak4_repeat
|
79
|
+
} # l1010
|
80
|
+
} # loop_repeat
|
81
|
+
|
82
|
+
l1000.AK5{|a|
|
83
|
+
a.TransactionSetAcknowledgmentCode = 666
|
84
|
+
a.TransactionSetSyntaxErrorCode4 = 999
|
85
|
+
} # a
|
86
|
+
} # l1000
|
87
|
+
|
88
|
+
# Print the message as a string -> ST*997*2878~AK1*HS*293328532~
|
89
|
+
# AK2*270*~AK3*NM1**L1000D~AK4***55*Bad element~AK5*~AK3*DMG*0*
|
90
|
+
# L1010*22~AK4*0**0~AK4*0**1~AK4*1**0~AK4*1**1~AK5*666****999~
|
91
|
+
# AK9****~SE**~
|
92
|
+
puts r.render
|
data/example/parse.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of the X12Parser library that provides tools to
|
3
|
+
# manipulate X12 messages using Ruby native syntax.
|
4
|
+
#
|
5
|
+
# http://x12parser.rubyforge.org
|
6
|
+
#
|
7
|
+
# Copyright (C) 2008 APP Design, Inc.
|
8
|
+
#
|
9
|
+
# This library is free software; you can redistribute it and/or
|
10
|
+
# modify it under the terms of the GNU Lesser General Public
|
11
|
+
# License as published by the Free Software Foundation; either
|
12
|
+
# version 2.1 of the License, or (at your option) any later version.
|
13
|
+
#
|
14
|
+
# This library is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17
|
+
# Lesser General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Lesser General Public
|
20
|
+
# License along with this library; if not, write to the Free Software
|
21
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
22
|
+
#++
|
23
|
+
#
|
24
|
+
require 'x12'
|
25
|
+
|
26
|
+
# Read message definition and create an actual parser
|
27
|
+
# by compiling .d12 file
|
28
|
+
parser = X12::Parser.new('misc/997.d12')
|
29
|
+
|
30
|
+
# Define a test message to parse
|
31
|
+
m997='ST*997*2878~AK1*HS*293328532~AK2*270*307272179~'\
|
32
|
+
'AK3*NM1*8*L1010_0*8~AK4*0:0*66*1~AK4*0:1*66*1~AK4*0:2*'\
|
33
|
+
'66*1~AK3*NM1*8*L1010_1*8~AK4*1:0*66*1~AK4*1:1*66*1~AK3*'\
|
34
|
+
'NM1*8*L1010_2*8~AK4*2:0*66*1~AK5*R*5~AK9*R*1*1*0~SE*8*2878~'
|
35
|
+
|
36
|
+
# Parse the message
|
37
|
+
r = parser.parse('997', m997)
|
38
|
+
|
39
|
+
# Access components of the message as desired
|
40
|
+
|
41
|
+
# Whole ST segment: -> ST*997*2878~
|
42
|
+
puts r.ST
|
43
|
+
|
44
|
+
# One filed, Group Control Number of AK1 -> 293328532
|
45
|
+
puts r.AK1.GroupControlNumber
|
46
|
+
|
47
|
+
# Individual loop, namely, third L1010 subloop of
|
48
|
+
# L1000 loop: -> AK3*NM1*8*L1010_2*8~AK4*2:0*66*1~
|
49
|
+
puts r.L1000.L1010[2]
|
50
|
+
|
51
|
+
# First encounter of Data Element Reference Number of the
|
52
|
+
# first L1010 sub-loop of L1000 loop -> 66
|
53
|
+
puts r.L1000.L1010.AK4.DataElementReferenceNumber
|
54
|
+
|
55
|
+
# Number of L1010 sub-loops in L1000 loop -> 3
|
56
|
+
puts r.L1000.L1010.size
|
data/lib/X12.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of the X12Parser library that provides tools to
|
3
|
+
# manipulate X12 messages using Ruby native syntax.
|
4
|
+
#
|
5
|
+
# http://x12parser.rubyforge.org
|
6
|
+
#
|
7
|
+
# Copyright (C) 2008 APP Design, Inc.
|
8
|
+
#
|
9
|
+
# This library is free software; you can redistribute it and/or
|
10
|
+
# modify it under the terms of the GNU Lesser General Public
|
11
|
+
# License as published by the Free Software Foundation; either
|
12
|
+
# version 2.1 of the License, or (at your option) any later version.
|
13
|
+
#
|
14
|
+
# This library is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17
|
+
# Lesser General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Lesser General Public
|
20
|
+
# License along with this library; if not, write to the Free Software
|
21
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
22
|
+
#++
|
23
|
+
#
|
24
|
+
$:.unshift(File.dirname(__FILE__))
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'treetop'
|
28
|
+
|
29
|
+
require 'X12/base'
|
30
|
+
require 'X12/empty'
|
31
|
+
require 'X12/field'
|
32
|
+
require 'X12/composite'
|
33
|
+
require 'X12/segment'
|
34
|
+
require 'X12/table'
|
35
|
+
require 'X12/loop'
|
36
|
+
require 'X12/parser'
|
37
|
+
|
38
|
+
# This relies on the polyglot package to compile and load x12syntax.treetop
|
39
|
+
require 'x12/x12syntax'
|
40
|
+
|
41
|
+
# $Id: X12.rb 35 2008-11-13 18:33:44Z ikk $
|
42
|
+
#
|
43
|
+
# Package implementing direct manipulation of X12 structures using Ruby syntax.
|
44
|
+
|
45
|
+
module X12
|
46
|
+
|
47
|
+
VERSION = '0.0.5'
|
48
|
+
EMPTY = Empty.new()
|
49
|
+
|
50
|
+
end
|
data/lib/X12/Base.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of the X12Parser library that provides tools to
|
3
|
+
# manipulate X12 messages using Ruby native syntax.
|
4
|
+
#
|
5
|
+
# http://x12parser.rubyforge.org
|
6
|
+
#
|
7
|
+
# Copyright (C) 2008 APP Design, Inc.
|
8
|
+
#
|
9
|
+
# This library is free software; you can redistribute it and/or
|
10
|
+
# modify it under the terms of the GNU Lesser General Public
|
11
|
+
# License as published by the Free Software Foundation; either
|
12
|
+
# version 2.1 of the License, or (at your option) any later version.
|
13
|
+
#
|
14
|
+
# This library is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17
|
+
# Lesser General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Lesser General Public
|
20
|
+
# License along with this library; if not, write to the Free Software
|
21
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
22
|
+
#++
|
23
|
+
#
|
24
|
+
module X12
|
25
|
+
|
26
|
+
# $Id: Base.rb 35 2008-11-13 18:33:44Z ikk $
|
27
|
+
#
|
28
|
+
# Base class for Segment, Composite, and Loop. Contains setable
|
29
|
+
# segment_separator, field_separator, and composite_separator fields.
|
30
|
+
|
31
|
+
class Base
|
32
|
+
|
33
|
+
attr_reader :name, :repeats
|
34
|
+
attr_reader :segment_separator, :field_separator, :composite_separator, :next_repeat, :parsed_str, :nodes
|
35
|
+
attr_writer :segment_separator, :field_separator, :composite_separator, :next_repeat, :parsed_str, :nodes
|
36
|
+
|
37
|
+
# Creates a new base element with a given name, array of sub-elements, and array of repeats if any.
|
38
|
+
def initialize(name, arr, repeats = nil)
|
39
|
+
@nodes = arr
|
40
|
+
@name = name
|
41
|
+
@repeats = repeats
|
42
|
+
@next_repeat = nil # Next repeat of the same element, if any
|
43
|
+
@parsed_str = nil
|
44
|
+
|
45
|
+
@segment_separator = '~'
|
46
|
+
@field_separator = '*'
|
47
|
+
@composite_separator = ':'
|
48
|
+
|
49
|
+
#puts "Created #{name} #{object_id} #{self.class} "
|
50
|
+
end
|
51
|
+
|
52
|
+
# Formats a printable string containing the base element's content
|
53
|
+
def inspect
|
54
|
+
"#{self.class.to_s.sub(/^.*::/, '')} (#{name}) #{repeats} #{super.inspect[1..-2]} =<#{parsed_str}, #{next_repeat.inspect}> ".gsub(/\\*\"/, '"')
|
55
|
+
end
|
56
|
+
|
57
|
+
# Prints a tree-like representation of the element
|
58
|
+
def show(ind = '')
|
59
|
+
count = 0
|
60
|
+
self.to_a.each{|i|
|
61
|
+
#puts "#{ind}#{i.name} #{i.object_id} #{i.super.object_id} [#{count}]: #{i.parsed_str} #{i.super.class}"
|
62
|
+
puts "#{ind}#{i.name} [#{count}]: #{i.to_s.sub(/^(.{30})(.*?)(.{30})$/, '\1...\3')}"
|
63
|
+
i.nodes.each{|j|
|
64
|
+
case
|
65
|
+
when j.kind_of?(X12::Base) : j.show(ind+' ')
|
66
|
+
when j.kind_of?(X12::Field) : puts "#{ind+' '}#{j.name} -> '#{j.to_s}'"
|
67
|
+
end
|
68
|
+
}
|
69
|
+
count += 1
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Try to parse the current element one more time if required. Returns the rest of the string
|
74
|
+
# or the same string if no more repeats are found or required.
|
75
|
+
def do_repeats(s)
|
76
|
+
if self.repeats.end > 1
|
77
|
+
possible_repeat = self.dup
|
78
|
+
p_s = possible_repeat.parse(s)
|
79
|
+
if p_s
|
80
|
+
s = p_s
|
81
|
+
self.next_repeat = possible_repeat
|
82
|
+
end # if parsed
|
83
|
+
end # more repeats
|
84
|
+
s
|
85
|
+
end # do_repeats
|
86
|
+
|
87
|
+
# Empty out the current element
|
88
|
+
def set_empty!
|
89
|
+
@next_repeat = nil
|
90
|
+
@parsed_str = nil
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
# Make a deep copy of the element
|
95
|
+
def dup
|
96
|
+
n = clone
|
97
|
+
n.set_empty!
|
98
|
+
n.nodes = n.nodes.dup
|
99
|
+
n.nodes.each_index{|i|
|
100
|
+
n.nodes[i] = n.nodes[i].dup
|
101
|
+
n.nodes[i].set_empty!
|
102
|
+
}
|
103
|
+
#puts "Duped #{self.class} #{self.name} #{self.object_id} #{super.object_id} -> #{n.name} #{n.super.object_id} #{n.object_id} "
|
104
|
+
n
|
105
|
+
end # dup
|
106
|
+
|
107
|
+
# Recursively find a sub-element, which also has to be of type Base.
|
108
|
+
def find(e)
|
109
|
+
#puts "Finding [#{e}] in #{self.class} #{name}"
|
110
|
+
case self
|
111
|
+
when X12::Loop
|
112
|
+
nodes.each{|i|
|
113
|
+
return i if e==i.name
|
114
|
+
res = i.find(e) if i.kind_of?(X12::Loop)
|
115
|
+
return res unless res.nil? or EMPTY==res # otherwise keep looping
|
116
|
+
}
|
117
|
+
when X12::Segment
|
118
|
+
return find_field(e).to_s
|
119
|
+
end # case
|
120
|
+
return EMPTY
|
121
|
+
end
|
122
|
+
|
123
|
+
# Present self and all repeats as an array with self being #0
|
124
|
+
def to_a
|
125
|
+
res = [self]
|
126
|
+
nr = self.next_repeat
|
127
|
+
while nr do
|
128
|
+
res << nr
|
129
|
+
nr = nr.next_repeat
|
130
|
+
end
|
131
|
+
res
|
132
|
+
end
|
133
|
+
|
134
|
+
# Returns a parsed string representation of the element
|
135
|
+
def to_s
|
136
|
+
@parsed_str || ''
|
137
|
+
end
|
138
|
+
|
139
|
+
# The main method implementing Ruby-like access methods for nested elements
|
140
|
+
def method_missing(meth, *args, &block)
|
141
|
+
str = meth.id2name
|
142
|
+
if str =~ /=$/
|
143
|
+
# Assignment
|
144
|
+
str.chop!
|
145
|
+
#puts str
|
146
|
+
case self
|
147
|
+
when X12::Segment
|
148
|
+
res = find_field(str)
|
149
|
+
throw Exception.new("No field '#{str}' in segment '#{self.name}'") if EMPTY == res
|
150
|
+
res.content = args[0].to_s
|
151
|
+
#puts res.inspect
|
152
|
+
else
|
153
|
+
throw Exception.new("Illegal assignment to #{meth} of #{self.class}")
|
154
|
+
end # case
|
155
|
+
else
|
156
|
+
# Retrieval
|
157
|
+
res = find(str)
|
158
|
+
yield res if block_given?
|
159
|
+
res
|
160
|
+
end # if assignment
|
161
|
+
end
|
162
|
+
|
163
|
+
# The main method implementing Ruby-like access methods for repeating elements
|
164
|
+
def [](*args)
|
165
|
+
#puts "squares #{args.inspect}"
|
166
|
+
return self.to_a[args[0]] || EMPTY
|
167
|
+
end
|
168
|
+
|
169
|
+
# Returns number of repeats
|
170
|
+
def size
|
171
|
+
return self.to_a.size
|
172
|
+
end
|
173
|
+
|
174
|
+
# Check if any of the fields has been set yet
|
175
|
+
def has_content?
|
176
|
+
self.nodes.find{|i| i.has_content?}
|
177
|
+
end
|
178
|
+
|
179
|
+
# Adds a repeat to a segment or loop. Returns a new segment/loop or self if empty.
|
180
|
+
def repeat
|
181
|
+
res = if self.has_content? # Do not repeat an empty segment
|
182
|
+
last_repeat = self.to_a[-1]
|
183
|
+
last_repeat.next_repeat = last_repeat.dup
|
184
|
+
else
|
185
|
+
self
|
186
|
+
end
|
187
|
+
yield res if block_given?
|
188
|
+
res
|
189
|
+
end
|
190
|
+
|
191
|
+
end # Base
|
192
|
+
end
|