kputnam/stupidedi — pull request #7 by kputnam (2013-05-21 03:44:31+00:00)
Title: Navigation of sibling detail tables is wrong

In transactions that have multiple detail tables, `m.find` behaves incorrectly when iterating their start segments. This happens under very specific circumstances. Consider this 277 Health Care Information Status Notification transaction where the `HL` segments denote the start of a loop (and possibly a table).

HL*..*..*19
HL*..*..*19

When building the parse tree, a heuristic is used: the segment is placed within the current structure if possible, but a new "uncle" structure is created only if the current structure cannot be used. For example, if two `HL*..*..*19` occur consecutively, they will be placed in adjacent loops within the same table.

TableVal[Table 2 - Service Provider Level](
LoopVal[2000C SERVICE PROVIDER LEVEL](
SegmentVal[HL: Service Provider Level](
AN.value[ E628: Hierarchical ID Number](3),
AN.value[ E734: Hierarchical Parent ID Number](2),
ID.value[ E735: Hierarchical Level Code](19: Provider of Service),
...
...
LoopVal[2000C SERVICE PROVIDER LEVEL](
SegmentVal[HL: Service Provider Level](
AN.value[ E628: Hierarchical ID Number](5),
AN.value[ E734: Hierarchical Parent ID Number](2),
ID.value[ E735: Hierarchical Level Code](19: Provider of Service),
...
...

However, if an `HL*..*..*20` is placed between them, each `HL` segment must be placed in separate tables.

TableVal[Table 2 - Service Provider Level](
LoopVal[2000C SERVICE PROVIDER LEVEL](
SegmentVal[HL: Service Provider Level](
AN.value[ E628: Hierarchical ID Number](3),
AN.value[ E734: Hierarchical Parent ID Number](2),
ID.value[ E735: Hierarchical Level Code](19: Provider of Service),
...
...

TableVal[Table 2 - Information Source Level](
LoopVal[2000A INFORMATION SOURCE LEVEL](
SegmentVal[HL: Information Source Level](
AN.value[ E628: Hierarchical ID Number](1),
AN.empty[ E734: Hierarchical Parent ID Number],
ID.value[ E735: Hierarchical Level Code](20: Information Source),
...
...

TableVal[Table 2 - Service Provider Level](
LoopVal[2000C SERVICE PROVIDER LEVEL](
SegmentVal[HL: Service Provider Level](
AN.value[ E628: Hierarchical ID Number](5),
AN.value[ E734: Hierarchical Parent ID Number](2),
ID.value[ E735: Hierarchical Level Code](19: Provider of Service),
...
...

This is a reasonable heuristic for constructing the parse tree. However, the same heuristic is used when traversing the parse tree. If we're currently positioned at an `HL*..*..*19` and we call `m.find(:HL, nil, nil, "19")`, the search is incorrectly limited to within the current loop. In the example above, we cannot reach the third `HL` segment because it was placed in an "uncle" table, which is outside the scope of our search.

Note that we *can* reach all `HL` segments by removing the element constraints: `m.find(:HL)` should first search for sibling loops within the current table, then search uncle tables. This was addressed in #6.