stupidedi 1.2.20 → 1.3.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -1
  3. data/bin/edi-obfuscate +112 -0
  4. data/lib/stupidedi/builder/generation.rb +39 -11
  5. data/lib/stupidedi/builder/navigation.rb +15 -2
  6. data/lib/stupidedi/either.rb +1 -1
  7. data/lib/stupidedi/reader/tokens/component_element_tok.rb +12 -0
  8. data/lib/stupidedi/reader/tokens/composite_element_tok.rb +17 -0
  9. data/lib/stupidedi/reader/tokens/segment_tok.rb +19 -1
  10. data/lib/stupidedi/reader/tokens/simple_element_tok.rb +12 -0
  11. data/lib/stupidedi/values/functional_group_val.rb +1 -1
  12. data/lib/stupidedi/values/interchange_val.rb +1 -1
  13. data/lib/stupidedi/values/loop_val.rb +1 -1
  14. data/lib/stupidedi/values/table_val.rb +1 -1
  15. data/lib/stupidedi/values/transaction_set_val.rb +1 -1
  16. data/lib/stupidedi/values/transmission_val.rb +1 -1
  17. data/lib/stupidedi/version.rb +1 -1
  18. data/lib/stupidedi/versions/functional_groups/002001/element_defs.rb +1 -14
  19. data/lib/stupidedi/versions/functional_groups/002001/element_types/date_val.rb +3 -3
  20. data/lib/stupidedi/versions/functional_groups/002001/element_types/fixnum_val.rb +2 -2
  21. data/lib/stupidedi/versions/functional_groups/002001/element_types/float_val.rb +2 -2
  22. data/lib/stupidedi/versions/functional_groups/002001/element_types/identifier_val.rb +1 -1
  23. data/lib/stupidedi/versions/functional_groups/002001/element_types/string_val.rb +2 -2
  24. data/lib/stupidedi/versions/functional_groups/002001/element_types/time_val.rb +2 -2
  25. data/lib/stupidedi/versions/functional_groups/003010/element_defs.rb +1 -14
  26. data/lib/stupidedi/versions/functional_groups/003010/element_types/date_val.rb +3 -3
  27. data/lib/stupidedi/versions/functional_groups/003010/element_types/fixnum_val.rb +2 -2
  28. data/lib/stupidedi/versions/functional_groups/003010/element_types/float_val.rb +2 -2
  29. data/lib/stupidedi/versions/functional_groups/003010/element_types/identifier_val.rb +2 -2
  30. data/lib/stupidedi/versions/functional_groups/003010/element_types/string_val.rb +2 -2
  31. data/lib/stupidedi/versions/functional_groups/003010/element_types/time_val.rb +2 -2
  32. data/lib/stupidedi/versions/functional_groups/003040/element_defs.rb +1 -14
  33. data/lib/stupidedi/versions/functional_groups/003040/element_types/date_val.rb +3 -3
  34. data/lib/stupidedi/versions/functional_groups/003040/element_types/fixnum_val.rb +2 -2
  35. data/lib/stupidedi/versions/functional_groups/003040/element_types/float_val.rb +2 -2
  36. data/lib/stupidedi/versions/functional_groups/003040/element_types/identifier_val.rb +2 -2
  37. data/lib/stupidedi/versions/functional_groups/003040/element_types/string_val.rb +2 -2
  38. data/lib/stupidedi/versions/functional_groups/003040/element_types/time_val.rb +2 -2
  39. data/lib/stupidedi/versions/functional_groups/003050/element_defs.rb +1 -14
  40. data/lib/stupidedi/versions/functional_groups/003050/element_types/date_val.rb +3 -3
  41. data/lib/stupidedi/versions/functional_groups/003050/element_types/fixnum_val.rb +2 -2
  42. data/lib/stupidedi/versions/functional_groups/003050/element_types/float_val.rb +2 -2
  43. data/lib/stupidedi/versions/functional_groups/003050/element_types/identifier_val.rb +2 -2
  44. data/lib/stupidedi/versions/functional_groups/003050/element_types/string_val.rb +2 -2
  45. data/lib/stupidedi/versions/functional_groups/003050/element_types/time_val.rb +2 -2
  46. data/lib/stupidedi/versions/functional_groups/004010/element_defs.rb +2 -3
  47. data/lib/stupidedi/versions/functional_groups/004010/element_types/date_val.rb +3 -3
  48. data/lib/stupidedi/versions/functional_groups/004010/element_types/fixnum_val.rb +2 -2
  49. data/lib/stupidedi/versions/functional_groups/004010/element_types/float_val.rb +2 -2
  50. data/lib/stupidedi/versions/functional_groups/004010/element_types/string_val.rb +2 -2
  51. data/lib/stupidedi/versions/functional_groups/004010/element_types/time_val.rb +2 -2
  52. data/lib/stupidedi/versions/functional_groups/005010/element_types/date_val.rb +1 -1
  53. data/lib/stupidedi/versions/functional_groups/005010/element_types/fixnum_val.rb +1 -1
  54. data/lib/stupidedi/versions/functional_groups/005010/element_types/float_val.rb +1 -1
  55. data/lib/stupidedi/versions/functional_groups/005010/element_types/string_val.rb +1 -1
  56. data/lib/stupidedi/versions/functional_groups/005010/element_types/time_val.rb +1 -1
  57. data/lib/stupidedi/versions/interchanges/00200/element_defs.rb +1 -1
  58. data/lib/stupidedi/versions/interchanges/00300/element_defs.rb +1 -1
  59. data/lib/stupidedi/versions/interchanges/00400/element_defs.rb +1 -1
  60. data/lib/stupidedi/versions/interchanges/00401/element_defs.rb +1 -1
  61. data/spec/examples/integration/navigating_spec.rb +44 -0
  62. data/spec/examples/integration/nondeterminism_spec.rb +165 -0
  63. metadata +4 -2
@@ -90,7 +90,7 @@ module Stupidedi
90
90
  end
91
91
  end
92
92
 
93
- ansi.element("DT.invalid#{id}") << "(#{ansi.invalid(@value.inspect)})"
93
+ ansi.element("DT.invalid#{id}") + "(#{ansi.invalid(@value.inspect)})"
94
94
  end
95
95
 
96
96
  # @return [String]
@@ -100,7 +100,7 @@ module Stupidedi
100
100
  end
101
101
  end
102
102
 
103
- ansi.element("Nn.invalid#{id}") << "(#{ansi.invalid(@value.inspect)})"
103
+ ansi.element("Nn.invalid#{id}") + "(#{ansi.invalid(@value.inspect)})"
104
104
  end
105
105
 
106
106
  # @return [String]
@@ -89,7 +89,7 @@ module Stupidedi
89
89
  end
90
90
  end
91
91
 
92
- ansi.element(" R.invalid#{id}") << "(#{ansi.invalid(@value.inspect)})"
92
+ ansi.element(" R.invalid#{id}") + "(#{ansi.invalid(@value.inspect)})"
93
93
  end
94
94
 
95
95
  # @return [String]
@@ -79,7 +79,7 @@ module Stupidedi
79
79
  end
80
80
  end
81
81
 
82
- ansi.element("AN.invalid#{id}") << "(#{ansi.invalid(@value.inspect)})"
82
+ ansi.element("AN.invalid#{id}") + "(#{ansi.invalid(@value.inspect)})"
83
83
  end
84
84
 
85
85
  # @return [String]
@@ -76,7 +76,7 @@ module Stupidedi
76
76
  end
77
77
  end
78
78
 
79
- ansi.element("TM.invalid#{id}") << "(#{ansi.invalid(@value.inspect)})"
79
+ ansi.element("TM.invalid#{id}") + "(#{ansi.invalid(@value.inspect)})"
80
80
  end
81
81
 
82
82
  # @return [String]
@@ -98,7 +98,7 @@ module Stupidedi
98
98
 
99
99
  def inspect
100
100
  id = definition.try{|d| ansi.bold("[#{d.id}]") }
101
- ansi.element("SeparatorElementVal.value#{id}") << "(#{@value || "nil"})"
101
+ ansi.element("SeparatorElementVal.value#{id}") + "(#{@value || "nil"})"
102
102
  end
103
103
  end
104
104
 
@@ -98,7 +98,7 @@ module Stupidedi
98
98
 
99
99
  def inspect
100
100
  id = definition.try{|d| ansi.bold("[#{d.id}]") }
101
- ansi.element("SeparatorElementVal.value#{id}") << "(#{@value || "nil"})"
101
+ ansi.element("SeparatorElementVal.value#{id}") + "(#{@value || "nil"})"
102
102
  end
103
103
  end
104
104
 
@@ -98,7 +98,7 @@ module Stupidedi
98
98
 
99
99
  def inspect
100
100
  id = definition.try{|d| ansi.bold("[#{d.id}]") }
101
- ansi.element("SeparatorElementVal.value#{id}") << "(#{@value || "nil"})"
101
+ ansi.element("SeparatorElementVal.value#{id}") + "(#{@value || "nil"})"
102
102
  end
103
103
  end
104
104
 
@@ -99,7 +99,7 @@ module Stupidedi
99
99
 
100
100
  def inspect
101
101
  id = definition.try{|d| ansi.bold("[#{d.id}]") }
102
- ansi.element("SeparatorElementVal.value#{id}") << "(#{@value || "nil"})"
102
+ ansi.element("SeparatorElementVal.value#{id}") + "(#{@value || "nil"})"
103
103
  end
104
104
  end
105
105
 
@@ -49,6 +49,50 @@ describe "Navigating" do
49
49
  end
50
50
  end
51
51
 
52
+ context "repeatable segments" do
53
+ specify "can be iterated" do
54
+ expect(lambda do
55
+ payment.flatmap do |m|
56
+ m.iterate(:ISA) do |isa|
57
+ raise "didn't expect a second ISA segment"
58
+ end
59
+ end
60
+ end).not_to raise_error
61
+ end
62
+
63
+ specify "can be iterated" do
64
+ expect(lambda do
65
+ payment.flatmap do |m|
66
+ m.iterate(:GS) do |gs|
67
+ expect(gs.segment.tap do |segment|
68
+ expect(segment.node.id).to eq(:GS)
69
+ end).to be_defined
70
+
71
+ gs.iterate(:ST) do |st|
72
+ expect(st.segment.tap do |segment|
73
+ expect(segment.node.id).to eq(:ST)
74
+ end).to be_defined
75
+ end
76
+ end
77
+ end
78
+ end).not_to raise_error
79
+ end
80
+ end
81
+
82
+ context "non-repeatable segments" do
83
+ specify "cannot be iterated" do
84
+ expect(lambda do
85
+ payment.flatmap do |m|
86
+ m.iterate(:GS) do |gs|
87
+ gs.iterate(:ST) do |st|
88
+ st.iterate(:BHT)
89
+ end
90
+ end
91
+ end
92
+ end).to raise_error("BHT segment is not repeatable")
93
+ end
94
+ end
95
+
52
96
  describe "error handling" do
53
97
  context "accessing an undefined element" do
54
98
  it "raises an exception" do
@@ -0,0 +1,165 @@
1
+ require "spec_helper"
2
+ require "pp"
3
+
4
+ describe "Non-determinism" do
5
+ include NavigationMatchers
6
+
7
+ let(:strict) { Stupidedi::Builder::BuilderDsl.build(config, true) }
8
+ let(:relaxed) { Stupidedi::Builder::BuilderDsl.build(config, false) }
9
+
10
+ let(:config) do
11
+ Stupidedi::Config.default.customize do |c|
12
+ c.transaction_set.customize do |x|
13
+ x.register("005010", "BE", "999") { schema }
14
+ end
15
+ end
16
+ end
17
+
18
+ let(:schema) do
19
+ d = Stupidedi::Schema
20
+ r = Stupidedi::Versions::FunctionalGroups::FiftyTen::SegmentReqs
21
+ s = Stupidedi::Versions::FunctionalGroups::FiftyTen::SegmentDefs
22
+
23
+ d::TransactionSetDef.build("BE", "000", "Example of Ambiguous Grammar",
24
+ d::TableDef.header("Table 1",
25
+ s::ST.use(10, r::Mandatory, d::RepeatCount.bounded(1))),
26
+ d::TableDef.detail("Table 2",
27
+ d::LoopDef.build("Loop 1", d::RepeatCount.bounded(1),
28
+ s::N1.use(20, r::Mandatory, d::RepeatCount.bounded(1)),
29
+ s::N3.use(30, r::Optional, d::RepeatCount.bounded(1))),
30
+ d::LoopDef.build("Loop 2", d::RepeatCount.bounded(1),
31
+ s::N1.use(40, r::Mandatory, d::RepeatCount.bounded(1)),
32
+ s::N4.use(50, r::Optional, d::RepeatCount.bounded(1)))),
33
+ d::TableDef.summary("Table 3",
34
+ s::SE.use(60, r::Mandatory, d::RepeatCount.bounded(1))))
35
+ end
36
+
37
+ let(:nondet_zero) { Fixtures.parse_("GH-129/1.txt") }
38
+ let(:nondet_five) { Fixtures.parse_("GH-129/1.txt") }
39
+ let(:nondet_nine) { Fixtures.parse_("GH-129/1.txt") }
40
+
41
+ def prelude(dsl)
42
+ dsl.ISA("00", "", "00", "", "ZZ", "_", "ZZ", "_",
43
+ Time.now.utc, Time.now.utc, "", "00501",
44
+ 123456789, "1", "T", "")
45
+
46
+ dsl.GS("BE", "SENDER ID", "RECEIVER ID",
47
+ Time.now.utc, Time.now.utc, "1", "X", "005010")
48
+
49
+ dsl.ST("999", "0000", "005010")
50
+ end
51
+
52
+ context "generating an ambiguous segment" do
53
+ context "when strict" do
54
+ it "throws an exception" do
55
+ expect(lambda do
56
+ prelude(strict)
57
+ .N1("6Y", "BOB BELCHER")
58
+ .N1("6Y", "NON DETERMINISM") # could be Loop 1 or Loop 2
59
+ end).to raise_error \
60
+ "non-deterministic machine state: N1 Party Identification, N1 Party Identification"
61
+ end
62
+ end
63
+
64
+ context "when non-strict" do
65
+ it "does not throw an exception" do
66
+ expect(lambda do
67
+ prelude(relaxed)
68
+ .N1("6Y", "BOB BELCHER")
69
+ .N1("6Y", "NON DETERMINISM") # could be Loop 1 or Loop 2
70
+ end).not_to raise_error
71
+ end
72
+
73
+ context "with later unambiguous input" do
74
+ it "does not discard invalid trees" do
75
+ expect(prelude(relaxed)
76
+ .N1("6Y", "BOB BELCHER")
77
+ .N1("6Y", "NON DETERMINISM") # could be Loop 1 or Loop 2
78
+ .N3("OCEAN AVENUE") # could only be Loop 1
79
+ .machine.active.length
80
+ ).to eq(2)
81
+ end
82
+
83
+ it "does not discard invalid trees" do
84
+ expect(prelude(relaxed)
85
+ .N1("6Y", "BOB BELCHER")
86
+ .N1("6Y", "NON DETERMINISM") # could be Loop 1 or Loop 2
87
+ .N4("UNKNOWN CITY") # could only be Loop 2
88
+ .machine.active.length
89
+ ).to eq(2)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ context "reading" do
96
+ def read(suffix, nondeterminism: 1)
97
+ input =
98
+ ["ISA*00*..........*01*SECRET....*ZZ*SUBMITTERS.ID..*ZZ*RECEIVERS.ID...*030101*1253*^*00501*000000905*1*T*:~",
99
+ "GS*BE*SENDER ID*RECEIVER ID*19991231*0802*1*x*005010~",
100
+ "ST*999*0000*005010~",
101
+ "N1*6Y*LINDA BELCHER~",
102
+ suffix].join("\n")
103
+
104
+ machine = Stupidedi::Builder::StateMachine.build(config)
105
+ machine.read(Stupidedi::Reader.build(input), nondeterminism: nondeterminism)
106
+ end
107
+
108
+ context "when nondenterminism = 1" do
109
+ it "ordinary input suceeds" do
110
+ machine, result = read("N3*OCEAN AVENUE~", nondeterminism: 1)
111
+
112
+ result.should_not be_fatal
113
+ result.reason.should eq("reached end of input without finding a segment identifier")
114
+ machine.should be_deterministic
115
+ end
116
+
117
+ it "ambiguous input causes a failure result" do
118
+ machine, result = read("N1*6Y*NON DETERMINISM~...", nondeterminism: 1)
119
+
120
+ result.should be_fatal # no usable parse tree
121
+ result.reason.should eq("too much non-determinism: N1 Party Identification, N1 Party Identification")
122
+ result.remainder.should eq("...")
123
+ machine.should_not be_deterministic
124
+ end
125
+ end
126
+
127
+ context "when nondenterminism = 2" do
128
+ it "acceptably ambiguous input succeeds" do
129
+ machine, result = read("N1*6Y*NON DETERMINISM~...", nondeterminism: 2)
130
+
131
+ result.should_not be_fatal # we have a usable parse tree, despite trailing garbage
132
+ result.remainder.should eq("...")
133
+ machine.should_not be_deterministic
134
+ machine.active.length.should eq(2)
135
+ end
136
+
137
+ it "too much ambiguity causes a failure" do
138
+ machine, result = read(
139
+ "N1*6Y*NON DETERMINISM~" \
140
+ "N1*6Y*THIS IS TOO MUCH~...", nondeterminism: 2)
141
+
142
+ result.should be_fatal # no useable parse tree
143
+ result.remainder.should eq("...")
144
+ machine.should_not be_deterministic
145
+ machine.active.length.should eq(1 + 2)
146
+ end
147
+ end
148
+
149
+ context "when nondenterminism = 3" do
150
+ it "too much ambiguity causes a failure" do
151
+ machine, result = read(
152
+ "N1*6Y*NON DETERMINISM~" \
153
+ "N1*6Y*BLAH BLAH BLAH~" \
154
+ "N1*6Y*THIS IS TOO MUCH~" \
155
+ "N1*6Y*NOT GONNA SEE THIS~...", nondeterminism: 3)
156
+
157
+ result.should be_fatal # no useable parse tree
158
+ result.remainder.should eq("N1*6Y*NOT GONNA SEE THIS~...")
159
+ machine.should_not be_deterministic
160
+ machine.active.length.should eq(1 + 2*2)
161
+ end
162
+ end
163
+ end
164
+
165
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stupidedi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.20
4
+ version: 1.3.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Putnam/Isi Robayna
@@ -49,6 +49,7 @@ files:
49
49
  - README.md
50
50
  - Rakefile
51
51
  - bin/edi-ed
52
+ - bin/edi-obfuscate
52
53
  - bin/edi-pp
53
54
  - doc/Generating.md
54
55
  - doc/Navigating.md
@@ -973,6 +974,7 @@ files:
973
974
  - lib/stupidedi/zipper/root_cursor.rb
974
975
  - spec/examples/integration/generating_spec.rb
975
976
  - spec/examples/integration/navigating_spec.rb
977
+ - spec/examples/integration/nondeterminism_spec.rb
976
978
  - spec/examples/integration/parsing/005010/X091A1-HP835_spec.rb
977
979
  - spec/examples/integration/parsing/005010/X212-HR276_spec.rb
978
980
  - spec/examples/integration/parsing/005010/X221-HP835_spec.rb
@@ -1211,7 +1213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1211
1213
  version: '0'
1212
1214
  requirements: []
1213
1215
  rubyforge_project:
1214
- rubygems_version: 2.7.6
1216
+ rubygems_version: 2.7.8
1215
1217
  signing_key:
1216
1218
  specification_version: 4
1217
1219
  summary: Parse, generate, validate ASC X12 EDI