stupidedi 1.2.20 → 1.3.21

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 (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