stupidedi 1.3.21 → 1.3.22
Sign up to get free protection for your applications and to get access to all the features.
- 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
|