edifact_rails 1.2.1 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c51652b41747f2b0c07ecd834c5c79b3bebbb1537464a450f37ee58ea68150e
4
- data.tar.gz: 2669313b30c7565c60f4dc568c528127577770946f7d4a8ffee7a1fc87f4c07e
3
+ metadata.gz: 617b14ce31edcecdb4d3c4a599f79612716680513a740a425f2bcd0cdb8f1d65
4
+ data.tar.gz: aa8d78ea8759f43a1465e2036c55ea704c1dce3f4c67c30f943324d32525787c
5
5
  SHA512:
6
- metadata.gz: ded47109a99423254023e4f7316e1bdc3d1dc6602e73225a900c815baa2b2c4d9d14fe16f131aa5e1239b6b49ecab6394d7051ec9fc66923c6ffb5eb0e674ba5
7
- data.tar.gz: f3c9d7ae8f793651c62eff11b3356321f6bcc531b5ce61020f23d530a08b0112d46e338edc8ff1711bc514fb53875508b5792795c3cbea8056e5ee97a60e52f1
6
+ metadata.gz: a7531b90d3f9d84223e3176fd6ebd012a26076d3f029e30c344c2ab2a26964c069e8a387f5c73c02445cccbc140e3bdba81bbb832ac08c07af7625bc56a4f686
7
+ data.tar.gz: ccd019d6bd9beac78be1c07563357a4b6f616bdb538e9a66b5b816a2a6ceadcd7abb05749940a8bf6277cc2d9507da0a003e6f8954fa0d90ef6588ade5327f71
data/CHANGELOG.md CHANGED
@@ -1,23 +1,45 @@
1
1
  # Changelog
2
2
 
3
- ## 1.0.0 (26/04/2023)
3
+ ## 2.1.0 (18/06/2024)
4
4
 
5
- * Initial release
5
+ * Added EDIFACT serialization. Contributed by [sallesma](https://github.com/sallesma)
6
6
 
7
- ## 1.1.0 (27/04/2023)
7
+ ## 2.0.0 (18/06/2024)
8
8
 
9
- * Added support for TRADACOMS input
9
+ * Added support for ANSIX12 format.
10
10
 
11
- ## 1.1.1 (4/05/2023)
11
+ ##### Breaking changes:
12
+ * `#una_special_characters` renamed to `#special_characters` (since it can now accept input of any supported format)
13
+ * New `UnrecognizedFormat` Error will now be thrown if the format of the input can not be detected.
14
+ * In essence, input must begin now with `UNA` or `UNB` (EDIFACT), `STX` (TRADACOMS), or `ISA` (ANSIX12)
12
15
 
13
- * Fixed crash caused by running the gem in a production environment.
16
+ ## 1.2.1 (4/06/2024)
17
+
18
+ * `#una_special_characters` method now also returns decimal notation character, default `.`.
19
+ * `#una_special_characters` method can now take no arguments, and will return the default special characters if so.
14
20
 
15
21
  ## 1.2.0 (31/05/2024)
16
22
 
17
23
  * Added support for UNA segments. Special characters different from the defaults can now be used.
18
24
  * Added `#una_special_characters` method that returns just the special characters.
19
25
 
20
- ## 1.2.1 (4/06/2024)
26
+ ## 1.1.1 (4/05/2023)
27
+
28
+ * Fixed crash caused by running the gem in a production environment.
29
+
30
+ ## 1.1.0 (27/04/2023)
31
+
32
+ * Added support for TRADACOMS input
33
+
34
+ ## 1.0.0 (26/04/2023)
35
+
36
+ * Initial release
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
21
45
 
22
- * `#una_special_characters` method now also returns decimal notation character, default `.`.
23
- * `#una_special_characters` method can now take no arguments, and will return the default special characters if so.
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # EdifactRails
2
2
 
3
- This gem parses EDIFACT or TRADACOMS input, and converts it into a ruby array structure for whatever further processing or validation you desire.
3
+ This gem parses EDIFACT, TRADACOMS, or ANSIX12 input, and converts it into a ruby array structure for whatever further processing or validation you desire.
4
4
 
5
- It does not handle validation itself.
5
+ This gem can also take a ruby array input, and serialize it into EDIFACT.
6
6
 
7
- This gem is heavily inspired by and attempts to output similar results as [edifact_parser](https://github.com/pvdvreede/edifact_parser)
7
+ This gem is heavily inspired by [edifact_parser](https://github.com/pvdvreede/edifact_parser)
8
8
 
9
9
  ## Requirements
10
10
 
@@ -20,7 +20,7 @@ This gem has been tested on the following ruby versions:
20
20
  In your `Gemfile`:
21
21
 
22
22
  ```ruby
23
- gem 'edifact_rails', '~> 1.2'
23
+ gem 'edifact_rails', '~> 2.1.0'
24
24
  ```
25
25
 
26
26
  Otherwise:
@@ -36,21 +36,40 @@ If you don't have the gem in your `Gemfile`, you will need to:
36
36
  ```ruby
37
37
  require 'edifact_rails'
38
38
  ```
39
+ ### Parsing
39
40
 
40
- You can pass either the path to your EDIFACT (or TRADACOMS) file, or a document (or snippet) as a string:
41
+ You can parse a string input with `#parse`, or a file with `#parse_file`
42
+
43
+ ```ruby
44
+ ruby_array = EdifactRails.parse("UNB+UNOA:3+TESTPLACE:1+DEP1:1+20051107:1159+6002'")
45
+ ```
41
46
 
42
47
  ```ruby
43
48
  ruby_array = EdifactRails.parse_file("your/file/path")
44
49
  ```
45
50
 
51
+ ### Serialization
52
+
53
+ You can convert a ruby input into EDIFACT with `#serialize`. Use the `with_service` option to insert the UNA segment.
54
+
46
55
  ```ruby
47
- ruby_array = EdifactRails.parse("LIN+1+1+0764569104:IB'QTY+1:25'")
56
+ edifact_output = Edifact.serialize(
57
+ [
58
+ ["LIN", [1], [1], ["0764569104", "IB"]],
59
+ ["QTY", [1, 25]]
60
+ ],
61
+ with_service: true
62
+ )
63
+ # edifact_output =>
64
+ "UNA:+.? 'LIN+1+1+0764569104:IB'QTY+1:25'"
48
65
  ```
49
66
 
50
- You can pull just the special characters from the UNA segment (or the defaults if no UNA segment is present):
67
+ ### Special Characters
68
+
69
+ You can return the special characters of your input with `#special_characters`.
51
70
  ```ruby
52
- una_special_characters = EdifactRails.una_special_characters(your_string_input)
53
- # una_special_characters =>
71
+ special_characters = EdifactRails.special_characters(example_edifact_input)
72
+ # special_characters =>
54
73
  {
55
74
  component_data_element_seperator: ":",
56
75
  data_element_seperator: "+",
@@ -60,7 +79,7 @@ una_special_characters = EdifactRails.una_special_characters(your_string_input)
60
79
  }
61
80
  ```
62
81
 
63
- ## Output
82
+ ## Parse Output
64
83
 
65
84
  ### EDIFACT
66
85
 
@@ -179,4 +198,66 @@ Will be returned as:
179
198
  ['MTR', [3]],
180
199
  ['END', [5]]
181
200
  ]
182
- ```
201
+ ```
202
+
203
+ ### ANSIX12
204
+
205
+ This ANSIX12 file:
206
+
207
+ ```
208
+ ISA*00* *00* *01*SENDER *01*RECEIVER *231014*1200*U*00401*000000001*1*P*>~
209
+ GS*SS*APP SENDER*APP RECEIVER*20231014*1200*0001*X*004010~
210
+ ST*862*0001~
211
+ BSS*05*12345*20230414*DL*20231014*20231203****ORDER1*A~
212
+ N1*MI*SEEBURGER AG*ZZ*00000085~
213
+ N3*EDISONSTRASSE 1~
214
+ N4*BRETTEN**75015*DE~
215
+ N1*SU*SUPLIER NAME*ZZ*11222333~
216
+ N3*203 STREET NAME~
217
+ N4*ATLANTA*GA*30309*US~
218
+ LIN**BP*MATERIAL1*EC*ENGINEERING1*DR*001~
219
+ UIT*EA~
220
+ PER*SC*SEEBURGER INFO*TE*+49(7525)0~
221
+ FST*13*C*D*20231029****DO*12345-1~
222
+ FST*77*C*D*20231119****DO*12345-2~
223
+ FST*68*C*D*20231203****DO*12345-3~
224
+ SHP*01*927*011*20231014~
225
+ REF*SI*Q5880~
226
+ SHP*02*8557*011*20231014**20231203~
227
+ CTT*1*5~
228
+ SE*19*0001~
229
+ GE*1*0001~
230
+ IEA*1*000000001~
231
+ ```
232
+
233
+ Will be returned as:
234
+
235
+ ```ruby
236
+ [
237
+ ["ISA", ["00"], [nil], ["00"], [nil], ["01"], ["SENDER"], ["01"], ["RECEIVER"], [231014], [1200], ["U"], ["00401"], ["000000001"], [1], ["P"], []],
238
+ ["GS", ["SS"], ["APP SENDER"], ["APP RECEIVER"], [20231014], [1200], ["0001"], ["X"], ["004010"]],
239
+ ["ST", [862], ["0001"]],
240
+ ["BSS", ["05"], [12345], [20230414], ["DL"], [20231014], [20231203], [], [], [], ["ORDER1"], ["A"]],
241
+ ["N1", ["MI"], ["SEEBURGER AG"], ["ZZ"], ["00000085"]],
242
+ ["N3", ["EDISONSTRASSE 1"]],
243
+ ["N4", ["BRETTEN"], [], [75015], ["DE"]],
244
+ ["N1", ["SU"], ["SUPLIER NAME"], ["ZZ"], [11222333]],
245
+ ["N3", ["203 STREET NAME"]],
246
+ ["N4", ["ATLANTA"], ["GA"], [30309], ["US"]],
247
+ ["LIN", [], ["BP"], ["MATERIAL1"], ["EC"], ["ENGINEERING1"], ["DR"], ["001"]],
248
+ ["UIT", ["EA"]],
249
+ ["PER", ["SC"], ["SEEBURGER INFO"], ["TE"], ["+49(7525)0"]],
250
+ ["FST", [13], ["C"], ["D"], [20231029], [], [], [], ["DO"], ["12345-1"]],
251
+ ["FST", [77], ["C"], ["D"], [20231119], [], [], [], ["DO"], ["12345-2"]],
252
+ ["FST", [68], ["C"], ["D"], [20231203], [], [], [], ["DO"], ["12345-3"]],
253
+ ["SHP", ["01"], [927], ["011"], [20231014]],
254
+ ["REF", ["SI"], ["Q5880"]],
255
+ ["SHP", ["02"], [8557], ["011"], [20231014], [], [20231203]],
256
+ ["CTT", [1], [5]],
257
+ ["SE", [19], ["0001"]],
258
+ ["GE", [1], ["0001"]],
259
+ ["IEA", [1], ["000000001"]]
260
+ ]
261
+ ```
262
+
263
+
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EdifactRails
4
+ class UnrecognizedFormat < StandardError
5
+ def initialize
6
+ super("Unrecognized EDI format. Accepted formats: Edifact, Tradacoms, ANSIX12. File must begin with UNA, UNB, STX, or ISA.")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EdifactRails
4
+ class Formats
5
+ EDIFACT = "EDIFACT"
6
+ TRADACOMS = "TRADACOMS"
7
+ ANSIX12 = "ANSIX12"
8
+ end
9
+ end
@@ -10,20 +10,26 @@ module EdifactRails
10
10
 
11
11
  # Treat the input, split the input string into segments, parse those segments
12
12
  def parse(string)
13
- # Trim newlines and excess spaces around those newlines
14
- string = string.gsub(/\s*\n\s*/, "")
13
+ # Remove all carraige returns, and leading and trailing whitespace
14
+ string = string.delete("\r").gsub(/^\s*(.*)\s*$/, '\1')
15
15
 
16
- # Check for UNA segment, update special characters if so
16
+ @edi_format = detect_edi_format(string)
17
+
18
+ # Detects special characters in the UNA segment (edifact) or ISA segment (ansix12),
19
+ # updates special characters if so
17
20
  detect_special_characters(string)
18
21
 
19
22
  # Does some funky regex maniulation to handle escaped special characters
20
- string = treat_input(string)
23
+ # Ansix12 does not have escape characters, so we can skip
24
+ string = handle_duplicate_escape_characters(string) unless @edi_format == EdifactRails::Formats::ANSIX12
21
25
 
22
26
  # Split the input string into segments
23
- segments = string.split(/(?<!#{Regexp.quote(@escape_character)})#{Regexp.quote(@segment_seperator)}/)
24
-
25
- # Detect if the input is a tradacoms file
26
- @is_tradacoms = segments.map { |s| s[3] }.uniq == ["="]
27
+ segments =
28
+ if @edi_format == EdifactRails::Formats::ANSIX12
29
+ string.split(@special_characters[:segment_seperator])
30
+ else
31
+ string.split(/(?<!#{Regexp.quote(@special_characters[:escape_character])})#{Regexp.quote(@special_characters[:segment_seperator])}/)
32
+ end
27
33
 
28
34
  # Drop the UNA segment, if present (we have already dealt with it in #detect_special_characters)
29
35
  segments.reject! { |s| s[0..2] == "UNA" }
@@ -33,62 +39,92 @@ module EdifactRails
33
39
  end
34
40
 
35
41
  # Given an input string, return the special characters as defined by the UNA segment
36
- # If no UNA segment is present, returns the default special characters
37
- def una_special_characters(string)
42
+ def special_characters(string = "")
43
+ # If no string is passed, return default edifact characters
44
+ return EdifactRails::DEFAULT_SPECIAL_CHARACTERS if string.empty?
45
+
46
+ string = string.delete("\r").gsub(/^\s*(.*)\s*$/, '\1')
47
+ @edi_format = detect_edi_format(string)
38
48
  detect_special_characters(string)
39
49
 
40
- {
41
- component_data_element_seperator: @component_data_element_seperator,
42
- data_element_seperator: @data_element_seperator,
43
- decimal_notation: @decimal_notation,
44
- escape_character: @escape_character,
45
- segment_seperator: @segment_seperator
46
- }
50
+ @special_characters
47
51
  end
48
52
 
49
53
  private
50
54
 
51
- def set_special_characters(
52
- component_data_element_seperator =
53
- EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:component_data_element_seperator],
54
- data_element_seperator = EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:data_element_seperator],
55
- decimal_notation = EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:decimal_notation],
56
- escape_character = EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:escape_character],
57
- segment_seperator = EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:segment_seperator]
58
- )
59
- # Set the special characters
60
- @component_data_element_seperator = component_data_element_seperator
61
- @data_element_seperator = data_element_seperator
62
- @decimal_notation = decimal_notation
63
- @escape_character = escape_character
64
- @segment_seperator = segment_seperator
55
+ def detect_edi_format(string)
56
+ case string[0..2]
57
+ when "UNA", "UNB"
58
+ EdifactRails::Formats::EDIFACT
59
+ when "STX"
60
+ EdifactRails::Formats::TRADACOMS
61
+ when "ISA"
62
+ EdifactRails::Formats::ANSIX12
63
+ else
64
+ raise EdifactRails::UnrecognizedFormat
65
+ end
65
66
  end
66
67
 
67
68
  def detect_special_characters(string)
68
- # UNA tags must be at the start of the input otherwise they are ignored
69
- return unless string[0..2] == "UNA"
69
+ # Format must be EDIFACT or ANSI X12 to set custom characters
70
+ # Tradacoms uses the defaults
71
+ return unless [EdifactRails::Formats::EDIFACT, EdifactRails::Formats::ANSIX12].include?(@edi_format)
72
+
73
+ # If EDIFACT, UNA tags are optional, so return if it's not present
74
+ return if @edi_format == EdifactRails::Formats::EDIFACT && string[0..2] != "UNA"
75
+
76
+ case @edi_format
77
+ when EdifactRails::Formats::EDIFACT
78
+ # UNA segments look like this:
79
+ #
80
+ # UNA:+.? '
81
+ #
82
+ # UNA followed by 6 special characters which are, in order:
83
+ # 1. Component data element separator
84
+ # 2. Data element separator
85
+ # 3. Decimal notation (must be . or ,)
86
+ # 4. Release character (aka escape character)
87
+ # 5. Reserved for future use, so always a space for now
88
+ # 6. Segment terminator
89
+ set_special_characters(
90
+ component_data_element_seperator: string[3],
91
+ data_element_seperator: string[4],
92
+ decimal_notation: string[5],
93
+ escape_character: string[6],
94
+ segment_seperator: string[8]
95
+ )
96
+ when EdifactRails::Formats::ANSIX12
97
+ # ISA segments look like this:
98
+ # ISA*00* *00* *01*SENDER *01*RECEIVER *231014*1200*U*00401*000000001*1*P*>~
99
+ # These are designed to always be the same number of characters, so we can use the hardcoded positions
100
+ # The special characters are the 4th (default *, data_element_seperator),
101
+ # 105th, 106th, 103rd, and 3rd characters
102
+ set_special_characters(
103
+ data_element_seperator: string[3],
104
+ component_data_element_seperator: string[104],
105
+ segment_seperator: string[105]
106
+ )
107
+ end
108
+ end
70
109
 
71
- # UNA segments look like this:
72
- #
73
- # UNA:+.? '
74
- #
75
- # UNA followed by 6 special characters which are, in order:
76
- # 1. Component data element separator
77
- # 2. Data element separator
78
- # 3. Decimal notation (must be . or ,)
79
- # 4. Release character (aka escape character)
80
- # 5. Reserved for future use, so always a space for now
81
- # 6. Segment terminator
82
- set_special_characters(string[3], string[4], string[5], string[6], string[8])
110
+ def set_special_characters(args = {})
111
+ # arg keys will overwrite the defaults when present
112
+ @special_characters = EdifactRails::DEFAULT_SPECIAL_CHARACTERS.merge(args)
113
+
114
+ # ANSIX12 files have no escape character or decimal notation character§
115
+ return unless @edi_format == EdifactRails::Formats::ANSIX12
116
+
117
+ @special_characters.delete(:escape_character)
118
+ @special_characters.delete(:decimal_notation)
83
119
  end
84
120
 
85
- def treat_input(string)
121
+ def handle_duplicate_escape_characters(string)
86
122
  # Prepare regex
87
- other_specials_rx = Regexp.quote(
123
+ other_specials_regex = Regexp.quote(
88
124
  [
89
- @segment_seperator,
90
- @data_element_seperator,
91
- @component_data_element_seperator
125
+ @special_characters[:segment_seperator],
126
+ @special_characters[:data_element_seperator],
127
+ @special_characters[:component_data_element_seperator]
92
128
  ].join
93
129
  )
94
130
 
@@ -96,7 +132,7 @@ module EdifactRails
96
132
  # the special character is therefore unescaped.
97
133
  # Add a space between these even number of escapes, and the special character
98
134
  #
99
- # This means the regex logic for #splitting on special characters is now consistent, since there will only ever
135
+ # This means the regex logic for splitting on special characters is now consistent, since there will only ever
100
136
  # be either 0 or 1 escape characters before every special character.
101
137
  #
102
138
  # We have to do this because we can't negative lookbehind for 'an even number of escape characters' since
@@ -110,20 +146,30 @@ module EdifactRails
110
146
  # "LIN+even????+123" => '+' is not escaped, gsub'ed => "even???? +123" => parsed => ['LIN', ['even??'], [123]]
111
147
  # "LIN+odd???+123" => '+' is escaped, not gsub'ed => "odd???+123" => parsed => ['LIN', ['odd?+123']]
112
148
  string.gsub(
113
- /(?<!#{Regexp.quote(@escape_character)})((#{Regexp.quote(@escape_character)}{2})+)([#{other_specials_rx}])/,
149
+ /(?<!#{Regexp.quote(@special_characters[:escape_character])})((#{Regexp.quote(@special_characters[:escape_character])}{2})+)([#{other_specials_regex}])/,
114
150
  '\1 \3'
115
151
  )
116
152
  end
117
153
 
118
154
  # Split the segment into data elements, take the first as the tag, then parse the rest
119
155
  def parse_segment(segment)
156
+ segment.chomp("")
157
+ segment.gsub!(/^\s*(.*)\s*/, '\1')
158
+
120
159
  # If the input is a tradacoms file, the segment tag will be proceeded by '=' instead of '+'
121
160
  # 'QTY=1+A:B' instead of 'QTY+1+A:B'
122
161
  # Fortunately, this is easily handled by simply changing these "="s into "+"s before the split
123
- segment[3] = @data_element_seperator if @is_tradacoms && segment.length >= 4
162
+ if @edi_format == EdifactRails::Formats::TRADACOMS && segment.length >= 4
163
+ segment[3] = @special_characters[:data_element_seperator]
164
+ end
124
165
 
125
166
  # Segments are made up of data elements
126
- data_elements = segment.split(/(?<!#{Regexp.quote(@escape_character)})#{Regexp.quote(@data_element_seperator)}/)
167
+ data_elements =
168
+ if @edi_format == EdifactRails::Formats::ANSIX12
169
+ segment.split(@special_characters[:data_element_seperator])
170
+ else
171
+ segment.split(/(?<!#{Regexp.quote(@special_characters[:escape_character])})#{Regexp.quote(@special_characters[:data_element_seperator])}/)
172
+ end
127
173
 
128
174
  # The first element is the tag, pop it off
129
175
  parsed_segment = []
@@ -137,7 +183,11 @@ module EdifactRails
137
183
  def parse_data_element(element)
138
184
  # Split data element into components
139
185
  components =
140
- element.split(/(?<!#{Regexp.quote(@escape_character)})#{Regexp.quote(@component_data_element_seperator)}/)
186
+ if @edi_format == EdifactRails::Formats::ANSIX12
187
+ element.split(@special_characters[:component_data_element_seperator])
188
+ else
189
+ element.split(/(?<!#{Regexp.quote(@special_characters[:escape_character])})#{Regexp.quote(@special_characters[:component_data_element_seperator])}/)
190
+ end
141
191
 
142
192
  components.map { |component| treat_component(component) }
143
193
  end
@@ -149,15 +199,19 @@ module EdifactRails
149
199
 
150
200
  # Prepare regex
151
201
  all_special_characters_string = [
152
- @segment_seperator,
153
- @data_element_seperator,
154
- @component_data_element_seperator,
155
- @escape_character
202
+ @special_characters[:segment_seperator],
203
+ @special_characters[:data_element_seperator],
204
+ @special_characters[:component_data_element_seperator],
205
+ @special_characters[:escape_character]
156
206
  ].join
157
207
 
158
- # If the component has escaped characters in it, remove the escape character and return the character as is
159
- # "?+" -> "+", "??" -> "?"
160
- component.gsub!(/#{Regexp.quote(@escape_character)}([#{Regexp.quote(all_special_characters_string)}])/, '\1')
208
+ unless @edi_format == EdifactRails::Formats::ANSIX12
209
+ # If the component has escaped characters in it, remove the escape character and return the character as is
210
+ # "?+" -> "+", "??" -> "?"
211
+ component.gsub!(
212
+ /#{Regexp.quote(@special_characters[:escape_character])}([#{Regexp.quote(all_special_characters_string)}])/, '\1'
213
+ )
214
+ end
161
215
 
162
216
  # Convert empty strings to nils
163
217
  component = nil if component.empty?
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EdifactRails
4
+ class Serializer
5
+ # with_service is used to force the service segment (UNA) at the beginning of the message
6
+ def serialize(segments, with_service:)
7
+ # Serialize and join the segments
8
+ output = segments.map { |segment| serialize_segment(segment) }
9
+ .join(EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:segment_seperator])
10
+
11
+ # Add the UNA segment
12
+ output.insert(0, "UNA:+.? '") unless segments.first.first == "UNA" || !with_service
13
+ output + EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:segment_seperator]
14
+ end
15
+
16
+ private
17
+
18
+ # Serialize the data elements and join them to serialize the segment
19
+ def serialize_segment(segment)
20
+ return if segment.empty?
21
+
22
+ # Get the tag
23
+ tag = segment.first
24
+ data_elements = segment[1..]
25
+
26
+ # Serialize the data elements
27
+ serialized_elements = data_elements.map { |element| serialize_data_element(element) }
28
+
29
+ # Join tag and data elements
30
+ serialized_elements.prepend(tag).join(EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:data_element_seperator])
31
+ end
32
+
33
+ def serialize_data_element(element)
34
+ element.map { |component| treat_component(component) }
35
+ .join(EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:component_data_element_seperator])
36
+ end
37
+
38
+ # Strip, remove escape characters, convert to nil where needed, convert to integer where needed
39
+ def treat_component(component)
40
+ return component unless component.is_a? String
41
+
42
+ # Prepare regex
43
+ all_special_characters = [
44
+ EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:segment_seperator],
45
+ EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:data_element_seperator],
46
+ EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:component_data_element_seperator],
47
+ EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:escape_character]
48
+ ].join
49
+
50
+ # If the component has escaped characters in it, prepend the escape character "+" -> "?+", "?" -> "??"
51
+ component.gsub(/([#{Regexp.quote(all_special_characters)}])/) do |match|
52
+ EdifactRails::DEFAULT_SPECIAL_CHARACTERS[:escape_character] + match
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EdifactRails
4
- VERSION = "1.2.1"
4
+ VERSION = "2.1.0"
5
5
  end
data/lib/edifact_rails.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "edifact_rails/parser"
4
+ require "edifact_rails/serializer"
5
+ require "edifact_rails/formats"
6
+ require "edifact_rails/exceptions"
4
7
 
5
8
  module EdifactRails
6
9
  DEFAULT_SPECIAL_CHARACTERS = {
@@ -17,11 +20,16 @@ module EdifactRails
17
20
  end
18
21
 
19
22
  def self.parse_file(file_path)
20
- parse(File.read(file_path).split("\n").join)
23
+ parse(File.read(file_path))
21
24
  end
22
25
 
23
- def self.una_special_characters(string = '')
26
+ def self.special_characters(string = "")
24
27
  parser = EdifactRails::Parser.new
25
- parser.una_special_characters(string)
28
+ parser.special_characters(string)
29
+ end
30
+
31
+ def self.serialize(array, with_service: true)
32
+ serializer = EdifactRails::Serializer.new
33
+ serializer.serialize array, with_service: with_service
26
34
  end
27
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: edifact_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Blackwood
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-04 00:00:00.000000000 Z
11
+ date: 2024-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -124,7 +124,10 @@ files:
124
124
  - LICENSE
125
125
  - README.md
126
126
  - lib/edifact_rails.rb
127
+ - lib/edifact_rails/exceptions.rb
128
+ - lib/edifact_rails/formats.rb
127
129
  - lib/edifact_rails/parser.rb
130
+ - lib/edifact_rails/serializer.rb
128
131
  - lib/edifact_rails/version.rb
129
132
  homepage: https://github.com/david-blackwood/edifact_rails
130
133
  licenses: