stupidedi 1.3.21 → 1.3.22
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 +4 -4
- data/lib/stupidedi/builder/builder_dsl.rb +5 -0
- data/lib/stupidedi/builder/constraint_table.rb +100 -74
- data/lib/stupidedi/builder/generation.rb +73 -70
- data/lib/stupidedi/builder/instruction.rb +10 -0
- data/lib/stupidedi/builder/instruction_table.rb +19 -7
- data/lib/stupidedi/builder/state_machine.rb +9 -3
- data/lib/stupidedi/builder/states/abstract_state.rb +1 -1
- data/lib/stupidedi/builder/states/failure_state.rb +1 -1
- data/lib/stupidedi/builder/states/initial_state.rb +4 -4
- data/lib/stupidedi/contrib/002001/guides/SH856.rb +4 -4
- data/lib/stupidedi/contrib/002001/transaction_set_defs/PO830.rb +2 -2
- data/lib/stupidedi/contrib/003010/guides/PS830.rb +4 -4
- data/lib/stupidedi/contrib/003010/guides/RA820.rb +22 -12
- data/lib/stupidedi/contrib/003010/transaction_set_defs/PC860.rb +2 -2
- data/lib/stupidedi/contrib/003010/transaction_set_defs/PS830.rb +1 -1
- data/lib/stupidedi/contrib/003050/guides/PO850.rb +2 -2
- data/lib/stupidedi/contrib/003050/transaction_set_defs/PO850.rb +2 -2
- data/lib/stupidedi/contrib/004010/guides.rb +0 -1
- data/lib/stupidedi/contrib/004010/transaction_set_defs/AR943.rb +1 -1
- data/lib/stupidedi/contrib/004010/transaction_set_defs/IM210.rb +2 -2
- data/lib/stupidedi/contrib/004010/transaction_set_defs/RE944.rb +1 -1
- data/lib/stupidedi/contrib/004010/transaction_set_defs/SH856.rb +1 -7
- data/lib/stupidedi/editor.rb +0 -1
- data/lib/stupidedi/guides/004010/guide_builder.rb +1 -1
- data/lib/stupidedi/guides/005010/X223-HC837I.rb +1192 -1195
- data/lib/stupidedi/guides/005010/guide_builder.rb +1 -1
- data/lib/stupidedi/schema.rb +1 -0
- data/lib/stupidedi/schema/auditor.rb +435 -0
- data/lib/stupidedi/schema/loop_def.rb +18 -1
- data/lib/stupidedi/schema/transaction_set_def.rb +12 -0
- data/lib/stupidedi/version.rb +1 -1
- data/lib/stupidedi/versions/functional_groups/004010/transaction_set_defs/HP835.rb +3 -17
- data/lib/stupidedi/versions/functional_groups/005010/element_types/time_val.rb +3 -2
- data/lib/stupidedi/versions/functional_groups/005010/segment_defs.rb +9 -6
- data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HB271.rb +25 -9
- data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HP835.rb +2 -2
- data/lib/stupidedi/zipper.rb +20 -1
- data/lib/stupidedi/zipper/memoized_cursor.rb +2 -0
- data/lib/stupidedi/zipper/path.rb +10 -0
- data/lib/stupidedi/zipper/root_cursor.rb +1 -1
- data/lib/stupidedi/zipper/stack_cursor.rb +174 -0
- data/spec/examples/stupidedi/audit_spec.rb +58 -0
- data/spec/spec_helper.rb +21 -13
- data/spec/support/rcov.rb +9 -4
- metadata +4 -1
@@ -142,7 +142,24 @@ module Stupidedi
|
|
142
142
|
raise Exceptions::InvalidSchemaError,
|
143
143
|
"first child must be a SegmentUse"
|
144
144
|
elsif header.head.repeat_count.include?(2)
|
145
|
-
|
145
|
+
raise Exceptions::InvalidSchemaError,
|
146
|
+
"first child must have RepeatCount.bounded(1)"
|
147
|
+
end
|
148
|
+
|
149
|
+
trailer.each.with_index do |s, k|
|
150
|
+
unless s.segment?
|
151
|
+
if s.respond_to?(:pretty_inspect)
|
152
|
+
raise Exceptions::InvalidSchemaError,
|
153
|
+
"arguments after last child LoopDef (#{loop_defs.last.id}) " +
|
154
|
+
"must be segments, but #{k+1} arguments later is not a " +
|
155
|
+
"SegmentUse: #{s.pretty_inspect}"
|
156
|
+
else
|
157
|
+
raise Exceptions::InvalidSchemaError,
|
158
|
+
"arguments after last child LoopDef (#{loop_defs.last.id}) " +
|
159
|
+
"must be segments, but #{k+1} arguments later is not a " +
|
160
|
+
"SegmentUse: #{s.inspect}"
|
161
|
+
end
|
162
|
+
end
|
146
163
|
end
|
147
164
|
|
148
165
|
new(id, repeat_count, header, loop_defs, trailer, nil)
|
@@ -84,6 +84,18 @@ module Stupidedi
|
|
84
84
|
|
85
85
|
# @return [TransactionSetDef]
|
86
86
|
def build(functional_group, id, name, *table_defs)
|
87
|
+
table_defs.each.with_index do |t, k|
|
88
|
+
unless t.table?
|
89
|
+
if t.respond_to?(:pretty_inspect)
|
90
|
+
raise Exceptions::InvalidSchemaError,
|
91
|
+
"argument #{k+4} is not a TableDef: #{t.pretty_inspect}"
|
92
|
+
else
|
93
|
+
raise Exceptions::InvalidSchemaError,
|
94
|
+
"argument #{k+4} is not a TableDef: #{t.inspect}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
87
99
|
new(functional_group, id, name, table_defs)
|
88
100
|
end
|
89
101
|
end
|
data/lib/stupidedi/version.rb
CHANGED
@@ -20,21 +20,14 @@ module Stupidedi
|
|
20
20
|
s::TRN.use(400, r::Optional, d::RepeatCount.bounded(1)),
|
21
21
|
s::CUR.use(500, r::Optional, d::RepeatCount.bounded(1)),
|
22
22
|
s::REF.use(600, r::Optional, d::RepeatCount.bounded(1)),
|
23
|
-
s::REF.use(600, r::Optional, d::RepeatCount.bounded(1)),
|
24
23
|
s::DTM.use(700, r::Optional, d::RepeatCount.bounded(1)),
|
25
24
|
|
26
|
-
d::LoopDef.build("
|
25
|
+
d::LoopDef.build("1000", d::RepeatCount.bounded(200),
|
27
26
|
s:: N1.use( 800, r::Mandatory, d::RepeatCount.bounded(1)),
|
28
27
|
s:: N3.use(1000, r::Mandatory, d::RepeatCount.bounded(1)),
|
29
28
|
s:: N4.use(1100, r::Mandatory, d::RepeatCount.bounded(1)),
|
30
29
|
s::REF.use(1200, r::Optional, d::RepeatCount.bounded(4)),
|
31
|
-
s::PER.use(1300, r::Optional, d::RepeatCount.bounded(1))),
|
32
|
-
|
33
|
-
d::LoopDef.build("1000B", d::RepeatCount.bounded(1),
|
34
|
-
s:: N1.use( 800, r::Mandatory, d::RepeatCount.bounded(1)),
|
35
|
-
s:: N3.use(1000, r::Optional, d::RepeatCount.bounded(1)),
|
36
|
-
s:: N4.use(1100, r::Optional, d::RepeatCount.bounded(1)),
|
37
|
-
s::REF.use(1200, r::Optional, d::RepeatCount.unbounded))),
|
30
|
+
s::PER.use(1300, r::Optional, d::RepeatCount.bounded(1)))),
|
38
31
|
|
39
32
|
d::TableDef.detail("Table 2 - Detail",
|
40
33
|
d::LoopDef.build("2000", d::RepeatCount.unbounded,
|
@@ -45,15 +38,9 @@ module Stupidedi
|
|
45
38
|
d::LoopDef.build("2100", d::RepeatCount.unbounded,
|
46
39
|
s::CLP.use(100, r::Mandatory, d::RepeatCount.bounded(1)),
|
47
40
|
s::CAS.use(200, r::Optional, d::RepeatCount.bounded(99)),
|
48
|
-
s::NM1.use(300, r::Mandatory, d::RepeatCount.bounded(
|
49
|
-
s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
|
50
|
-
s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
|
51
|
-
s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
|
52
|
-
s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
|
53
|
-
s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
|
41
|
+
s::NM1.use(300, r::Mandatory, d::RepeatCount.bounded(9)),
|
54
42
|
s::MIA.use(330, r::Optional, d::RepeatCount.bounded(1)),
|
55
43
|
s::MOA.use(350, r::Optional, d::RepeatCount.bounded(1)),
|
56
|
-
s::REF.use(400, r::Optional, d::RepeatCount.bounded(5)),
|
57
44
|
s::REF.use(400, r::Optional, d::RepeatCount.bounded(10)),
|
58
45
|
s::DTM.use(500, r::Optional, d::RepeatCount.bounded(4)),
|
59
46
|
s::PER.use(600, r::Optional, d::RepeatCount.bounded(3)),
|
@@ -65,7 +52,6 @@ module Stupidedi
|
|
65
52
|
s::DTM.use( 800, r::Optional, d::RepeatCount.bounded(3)),
|
66
53
|
s::CAS.use( 900, r::Optional, d::RepeatCount.bounded(99)),
|
67
54
|
s::REF.use(1000, r::Optional, d::RepeatCount.bounded(7)),
|
68
|
-
s::REF.use(1000, r::Optional, d::RepeatCount.bounded(10)),
|
69
55
|
s::AMT.use(1100, r::Optional, d::RepeatCount.bounded(12)),
|
70
56
|
s::QTY.use(1200, r::Optional, d::RepeatCount.bounded(6)),
|
71
57
|
s:: LQ.use(1300, r::Optional, d::RepeatCount.bounded(99))))),
|
@@ -289,9 +289,10 @@ module Stupidedi
|
|
289
289
|
hour = object.to_s.slice(0, 2).to_i
|
290
290
|
minute = object.to_s.slice(2, 2).try{|mm| mm.to_i unless mm.blank? }
|
291
291
|
second = object.to_s.slice(4, 2).try{|ss| ss.to_d unless ss.blank? }
|
292
|
+
decimal = object.to_s.slice(6..-1).try{|dd| dd.to_d unless dd.blank? }
|
292
293
|
|
293
|
-
if decimal
|
294
|
-
second += "0
|
294
|
+
if decimal
|
295
|
+
second += ("0.%02d" % decimal).to_d
|
295
296
|
end
|
296
297
|
|
297
298
|
self::NonEmpty.new(hour, minute, second, usage, position)
|
@@ -10,8 +10,8 @@ module Stupidedi
|
|
10
10
|
autoload :AAA,
|
11
11
|
"stupidedi/versions/functional_groups/005010/segment_defs/AAA"
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
autoload :ACT,
|
14
|
+
"stupidedi/versions/functional_groups/005010/segment_defs/ACT"
|
15
15
|
|
16
16
|
autoload :AK1,
|
17
17
|
"stupidedi/versions/functional_groups/005010/segment_defs/AK1"
|
@@ -91,9 +91,12 @@ module Stupidedi
|
|
91
91
|
autoload :DTP,
|
92
92
|
"stupidedi/versions/functional_groups/005010/segment_defs/DTP"
|
93
93
|
|
94
|
-
|
94
|
+
autoload :EB,
|
95
95
|
"stupidedi/versions/functional_groups/005010/segment_defs/EB"
|
96
96
|
|
97
|
+
autoload :EC,
|
98
|
+
"stupidedi/versions/functional_groups/005010/segment_defs/EC"
|
99
|
+
|
97
100
|
autoload :EQ,
|
98
101
|
"stupidedi/versions/functional_groups/005010/segment_defs/EQ"
|
99
102
|
|
@@ -114,9 +117,9 @@ module Stupidedi
|
|
114
117
|
|
115
118
|
autoload :HLH,
|
116
119
|
"stupidedi/versions/functional_groups/005010/segment_defs/HLH"
|
117
|
-
|
118
|
-
|
119
|
-
"stupidedi/versions/functional_groups/005010/segment_defs/III"
|
120
|
+
|
121
|
+
autoload :III,
|
122
|
+
"stupidedi/versions/functional_groups/005010/segment_defs/III"
|
120
123
|
|
121
124
|
autoload :ICM,
|
122
125
|
"stupidedi/versions/functional_groups/005010/segment_defs/ICM"
|
@@ -11,6 +11,15 @@ module Stupidedi
|
|
11
11
|
r = SegmentReqs
|
12
12
|
s = SegmentDefs
|
13
13
|
|
14
|
+
# NOTE: This definition is not usable as-is, because it references
|
15
|
+
# segments that we don't have definitions for. The HB270 and HB271
|
16
|
+
# *standards* refer to these, but the *implementation guide* doesn't
|
17
|
+
# use or include definitions for these: LUI, VEH, PID, PDR, PDP, EM,
|
18
|
+
# SD1, PKD, PCT.
|
19
|
+
#
|
20
|
+
# Furthermore, the 2120 NM1 loop is in conflict with the 2100 NM1
|
21
|
+
# loop because both don't have any constraints (the implementation
|
22
|
+
# guides do have the necessary constraints).
|
14
23
|
HB271 = d::TransactionSetDef.build("HB", "271",
|
15
24
|
"Eligibility, Coverage, or Benefit Information",
|
16
25
|
|
@@ -25,6 +34,9 @@ module Stupidedi
|
|
25
34
|
s::AAA.use(250, r::Optional, d::RepeatCount.bounded(9)),
|
26
35
|
|
27
36
|
d::LoopDef.build("2100", d::RepeatCount.unbounded,
|
37
|
+
# This NM1 needs to have a constraint on NM1-01 to avoid
|
38
|
+
# ambiguity with 2120 NM1, but the particular constraints
|
39
|
+
# need to be specified in the implementation guide
|
28
40
|
s::NM1.use( 300, r::Mandatory, d::RepeatCount.bounded(1)),
|
29
41
|
s::REF.use( 400, r::Optional, d::RepeatCount.bounded(9)),
|
30
42
|
s:: N2.use( 500, r::Optional, d::RepeatCount.bounded(1)),
|
@@ -67,17 +79,21 @@ module Stupidedi
|
|
67
79
|
s::AMT.use(3100, r::Optional, d::RepeatCount.bounded(5)))),
|
68
80
|
# s::PCT.use(3200, r::Optional, d::RepeatCount.bounded(5)))),
|
69
81
|
|
70
|
-
|
82
|
+
d::LoopDef.build("2120 LS", d::RepeatCount.bounded(1),
|
83
|
+
s:: LS.use(3300, r::Optional, d::RepeatCount.bounded(1)),
|
71
84
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
s::
|
77
|
-
s::
|
78
|
-
s::
|
85
|
+
# d::LoopDef.build("2120", d::RepeatCount.unbounded,
|
86
|
+
# # This NM1 needs to have a constraint on NM1-01 to avoid
|
87
|
+
# # ambiguity with 2100 NM1, but the particular constraints
|
88
|
+
# # need to be specified in the implementation guide
|
89
|
+
# s::NM1.use(3400, r::Optional, d::RepeatCount.bounded(1)),
|
90
|
+
# s:: N2.use(3500, r::Optional, d::RepeatCount.bounded(1)),
|
91
|
+
# s:: N3.use(3600, r::Optional, d::RepeatCount.bounded(1)),
|
92
|
+
# s:: N4.use(3700, r::Optional, d::RepeatCount.bounded(1)),
|
93
|
+
# s::PER.use(3800, r::Optional, d::RepeatCount.bounded(3)),
|
94
|
+
# s::PRV.use(3900, r::Optional, d::RepeatCount.bounded(1))),
|
79
95
|
|
80
|
-
|
96
|
+
s:: LE.use(4000, r::Optional, d::RepeatCount.bounded(1))))))),
|
81
97
|
|
82
98
|
d::TableDef.summary("Table 3 - Summary",
|
83
99
|
s:: SE.use(4100, r::Mandatory, d::RepeatCount.bounded(1))))
|
@@ -29,9 +29,9 @@ module Stupidedi
|
|
29
29
|
s:: N3.use(1000, r::Optional, d::RepeatCount.unbounded),
|
30
30
|
s:: N4.use(1100, r::Optional, d::RepeatCount.bounded(1)),
|
31
31
|
s::REF.use(1200, r::Optional, d::RepeatCount.unbounded),
|
32
|
-
s::PER.use(1300, r::Optional, d::RepeatCount.unbounded)
|
32
|
+
s::PER.use(1300, r::Optional, d::RepeatCount.unbounded),
|
33
33
|
s::RDM.use(1400, r::Optional, d::RepeatCount.bounded(1)),
|
34
|
-
s::DTM.use(1500, r::Optional, d::RepeatCount.bounded(1))),
|
34
|
+
s::DTM.use(1500, r::Optional, d::RepeatCount.bounded(1)))),
|
35
35
|
|
36
36
|
d::TableDef.detail("Table 2 - Detail",
|
37
37
|
d::LoopDef.build("2000", d::RepeatCount.unbounded,
|
data/lib/stupidedi/zipper.rb
CHANGED
@@ -9,10 +9,29 @@ module Stupidedi
|
|
9
9
|
autoload :EditedCursor, "stupidedi/zipper/edited_cursor"
|
10
10
|
autoload :MemoizedCursor, "stupidedi/zipper/memoized_cursor"
|
11
11
|
autoload :RootCursor, "stupidedi/zipper/root_cursor"
|
12
|
+
autoload :StackCursor, "stupidedi/zipper/stack_cursor"
|
12
13
|
|
13
14
|
autoload :AbstractPath, "stupidedi/zipper/path"
|
14
15
|
autoload :Hole, "stupidedi/zipper/path"
|
15
16
|
autoload :Root, "stupidedi/zipper/path"
|
17
|
+
|
18
|
+
# @todo
|
19
|
+
module Tree
|
20
|
+
class << self
|
21
|
+
def build(node)
|
22
|
+
Zipper::RootCursor.new(node)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @todo
|
28
|
+
module Stack
|
29
|
+
class << self
|
30
|
+
def build(node)
|
31
|
+
Zipper::StackCursor.new(node, Zipper::Root, nil)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
16
35
|
end
|
17
36
|
|
18
37
|
class << Zipper
|
@@ -22,7 +41,7 @@ module Stupidedi
|
|
22
41
|
|
23
42
|
# @return [AbstractCursor]
|
24
43
|
def build(node)
|
25
|
-
Zipper::
|
44
|
+
Zipper::Tree.build(node)
|
26
45
|
end
|
27
46
|
end
|
28
47
|
|
@@ -25,10 +25,12 @@ module Stupidedi
|
|
25
25
|
# @group Querying the Tree Location
|
26
26
|
#########################################################################
|
27
27
|
|
28
|
+
# (see AbstractCursor#leaf?)
|
28
29
|
def leaf?
|
29
30
|
@node.leaf? or @node.children.empty?
|
30
31
|
end
|
31
32
|
|
33
|
+
# (see AbstractCursor#root?)
|
32
34
|
def root?
|
33
35
|
false
|
34
36
|
end
|
@@ -7,6 +7,8 @@ module Stupidedi
|
|
7
7
|
|
8
8
|
class AbstractPath
|
9
9
|
|
10
|
+
abstract :root?
|
11
|
+
|
10
12
|
# @return [AbstractPath]
|
11
13
|
abstract :parent
|
12
14
|
|
@@ -35,6 +37,10 @@ module Stupidedi
|
|
35
37
|
# @private
|
36
38
|
Root = Class.new(AbstractPath) do
|
37
39
|
|
40
|
+
def root?
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
38
44
|
# @return self
|
39
45
|
def parent
|
40
46
|
self
|
@@ -93,6 +99,10 @@ module Stupidedi
|
|
93
99
|
left, parent, right
|
94
100
|
end
|
95
101
|
|
102
|
+
def root?
|
103
|
+
false
|
104
|
+
end
|
105
|
+
|
96
106
|
# (see AbstractPath#last?)
|
97
107
|
def last?
|
98
108
|
@right.empty?
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Stupidedi
|
4
|
+
using Refinements
|
5
|
+
|
6
|
+
module Zipper
|
7
|
+
|
8
|
+
class StackCursor < AbstractCursor
|
9
|
+
|
10
|
+
# @return [#leaf?, #children, #copy]
|
11
|
+
attr_reader :node
|
12
|
+
|
13
|
+
# @return [Hole]
|
14
|
+
attr_reader :path
|
15
|
+
|
16
|
+
# @private
|
17
|
+
# @return [AbstractCursor]
|
18
|
+
attr_reader :parent
|
19
|
+
|
20
|
+
def initialize(node, path, parent)
|
21
|
+
@node, @path, @parent =
|
22
|
+
node, path, parent
|
23
|
+
end
|
24
|
+
|
25
|
+
def copy(changes = {})
|
26
|
+
StackCursor.new \
|
27
|
+
changes.fetch(:node, @node),
|
28
|
+
changes.fetch(:path, @path),
|
29
|
+
changes.fetch(:parent, @parent)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @group Querying the Tree Location
|
33
|
+
#########################################################################
|
34
|
+
|
35
|
+
# (see AbstractCursor#leaf?)
|
36
|
+
def leaf?
|
37
|
+
@node.leaf? or @node.children.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
# (see AbstractCursor#root?)
|
41
|
+
def root?
|
42
|
+
@path.root?
|
43
|
+
end
|
44
|
+
|
45
|
+
def between(other)
|
46
|
+
raise Exceptions::ZipperError,
|
47
|
+
"stack cursor doesn't support this method"
|
48
|
+
end
|
49
|
+
|
50
|
+
# @group Traversing the Tree
|
51
|
+
#########################################################################
|
52
|
+
|
53
|
+
# (see AbstractCursor#first)
|
54
|
+
def first
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
# (see AbstractCursor#last)
|
59
|
+
def last
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# (see AbstractCursor#next)
|
64
|
+
# @return [void]
|
65
|
+
def next
|
66
|
+
raise Exceptions::ZipperError,
|
67
|
+
"stack cursor doesn't maintain siblings"
|
68
|
+
end
|
69
|
+
|
70
|
+
# (see AbstractCursor#prev)
|
71
|
+
# @return [void]
|
72
|
+
def prev
|
73
|
+
raise Exceptions::ZipperError,
|
74
|
+
"stack cursor doesn't maintain siblings"
|
75
|
+
end
|
76
|
+
|
77
|
+
# (see AbstractCursor#up)
|
78
|
+
def up
|
79
|
+
if root?
|
80
|
+
raise Exceptions::ZipperError,
|
81
|
+
"root node has no siblings"
|
82
|
+
end
|
83
|
+
|
84
|
+
@parent
|
85
|
+
end
|
86
|
+
|
87
|
+
# (see AbstractCursor#down)
|
88
|
+
def down
|
89
|
+
if leaf?
|
90
|
+
raise Exceptions::ZipperError,
|
91
|
+
"cannot descend into leaf node"
|
92
|
+
end
|
93
|
+
|
94
|
+
head, *tail = @node.children
|
95
|
+
|
96
|
+
unless tail.empty?
|
97
|
+
raise Exceptions::ZipperError,
|
98
|
+
"stack cursor doesn't support nodes with multiple children"
|
99
|
+
end
|
100
|
+
|
101
|
+
StackCursor.new(head, Hole.new([], @path, []), self)
|
102
|
+
end
|
103
|
+
|
104
|
+
# @group Editing the Tree
|
105
|
+
#########################################################################
|
106
|
+
|
107
|
+
# (see AbstractCursor#append)
|
108
|
+
# @return [void]
|
109
|
+
def append(node)
|
110
|
+
if root?
|
111
|
+
raise Exceptions::ZipperError,
|
112
|
+
"root node has no siblings"
|
113
|
+
end
|
114
|
+
|
115
|
+
replace(node)
|
116
|
+
end
|
117
|
+
|
118
|
+
# (see AbstractCursor#prepend)
|
119
|
+
# @return [void]
|
120
|
+
def prepend(node)
|
121
|
+
if root?
|
122
|
+
raise Exceptions::ZipperError,
|
123
|
+
"root node has no siblings"
|
124
|
+
end
|
125
|
+
|
126
|
+
replace(node)
|
127
|
+
end
|
128
|
+
|
129
|
+
def prepend_child(child)
|
130
|
+
StackCursor.new(child, Hole.new([], @path, []), self)
|
131
|
+
end
|
132
|
+
|
133
|
+
def append_child(child)
|
134
|
+
StackCursor.new(child, Hole.new([], @path, []), self)
|
135
|
+
end
|
136
|
+
|
137
|
+
# (see AbstractCursor#replace)
|
138
|
+
# @return [RootCursor]
|
139
|
+
def replace(node)
|
140
|
+
StackCursor.new(node, @path, @parent)
|
141
|
+
end
|
142
|
+
|
143
|
+
# (see AbstractCursor#delete)
|
144
|
+
# @return [void]
|
145
|
+
def delete
|
146
|
+
if root?
|
147
|
+
raise Exceptions::ZipperError,
|
148
|
+
"cannot delete root node"
|
149
|
+
end
|
150
|
+
|
151
|
+
@parent
|
152
|
+
end
|
153
|
+
|
154
|
+
def dangle
|
155
|
+
if leaf?
|
156
|
+
StackCursor.new(nil, Hole.new([], @path, []), self)
|
157
|
+
else
|
158
|
+
head, *tail = @node.children
|
159
|
+
|
160
|
+
unless tail.empty?
|
161
|
+
raise Exceptions::ZipperError,
|
162
|
+
"stack cursor doesn't support nodes with multiple children"
|
163
|
+
end
|
164
|
+
|
165
|
+
StackCursor.new(head, Hole.new([], @path, []), self)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# @endgroup
|
170
|
+
#########################################################################
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|