yaml_tools 1.0.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fe18af8ef1c5ccad515bc83b88c2a663d143e56d49a30efe748b772b9ff3572b
4
+ data.tar.gz: 6fc99c8e0aa6ef9385ba82a1999b763fcab26f1a6298f6f02c4228c932e8b23a
5
+ SHA512:
6
+ metadata.gz: 1c771e0e390a84bf7bac523e6a81f630ee46d20540b1b4bcd251c6840a6747b0d4a54059d4325f6c655ddbec95395730db98aae2dbcee67153d94e57a96b8b01
7
+ data.tar.gz: eb91e0ccc7c759123cee799b7b5422975a55dff273b6e965aba62a438f64aab246e9418a2e6ccff1fe9bea2eedb2bade562dcbaa668c2e2ea7f4640f4d6fc6da
@@ -0,0 +1,214 @@
1
+ require 'yaml'
2
+
3
+ module YAMLTools
4
+ class Combiner
5
+ def combine_levels (s, d)
6
+ level = []
7
+
8
+ # Split into key/value pairs
9
+ sourceChildren = s.each_slice(2).to_a
10
+ differenceChildren = d.each_slice(2).to_a
11
+
12
+ sourceChildren.each {|sourcePair|
13
+ sourceKey = sourcePair[0]
14
+ sourceValue = sourcePair[1]
15
+
16
+ # Find difference pair
17
+ differencePairs = differenceChildren.find_all {|i| i[0].value == sourceKey.value}
18
+
19
+ if (differencePairs.length > 1) then
20
+ if (sourceKey.value == "<<") then
21
+ # Find merge key with matching alias
22
+ differencePair = differencePairs.find {|i|
23
+ (i[1].is_a?(Psych::Nodes::Alias) && i[1].anchor == sourceValue.anchor) ||
24
+ (i[1].is_a?(Psych::Nodes::Sequence) && i[1].children.any? {|a| a.is_a?(Psych::Nodes::Alias) && a.anchor == sourceValue.anchor})}
25
+ else
26
+ # Some ArchivesSpace files have duplicate keys so use the last one
27
+ differencePair = differencePairs.last
28
+ end
29
+ else
30
+ differencePair = differencePairs.first
31
+ end
32
+
33
+ if (differencePair == nil) then
34
+ # difference not found so copy node
35
+ level << sourceKey
36
+ level << sourceValue
37
+ else
38
+ differenceKey = differencePair[0]
39
+ differenceValue = differencePair[1]
40
+
41
+ if (differenceKey.value == '<<') then
42
+ # If aliases or sequences of aliases then merge
43
+ if ((sourceValue.is_a?(Psych::Nodes::Alias) || sourceValue.is_a?(Psych::Nodes::Sequence)) && (differenceValue.is_a?(Psych::Nodes::Alias) || differenceValue.is_a?(Psych::Nodes::Sequence))) then
44
+ if (sourceValue.is_a?(Psych::Nodes::Alias) && (differenceValue.is_a?(Psych::Nodes::Sequence) && differenceValue.children.all? {|a| a.is_a?(Psych::Nodes::Alias)})) then
45
+ # Merge aliases
46
+ if (differenceValue.children.none? {|a| a.anchor == sourceValue.anchor}) then
47
+ # Add alias to sequence
48
+ differenceValue.children = differenceValue.children << sourceValue
49
+ end
50
+
51
+ level.insert(0, sourceKey)
52
+ level.insert(1, differenceValue)
53
+
54
+ elsif (differenceValue.is_a?(Psych::Nodes::Alias) && (sourceValue.is_a?(Psych::Nodes::Sequence) && sourceValue.children.all? {|a| a.is_a?(Psych::Nodes::Alias)})) then
55
+ # Merge aliases
56
+ if (sourceValue.children.none? {|a| a.anchor == differenceValue.anchor}) then
57
+ # Add alias to sequence
58
+ sourceValue.children = sourceValue.children << differenceValue
59
+ end
60
+
61
+ level.insert(0, sourceKey)
62
+ level.insert(1, sourceValue)
63
+ elsif (sourceValue.is_a?(Psych::Nodes::Sequence) && differenceValue.is_a?(Psych::Nodes::Sequence))
64
+ newSequence = Psych::Nodes::Sequence.new(sourceValue.anchor, sourceValue.tag, sourceValue.implicit, Psych::Nodes::Sequence::FLOW)
65
+
66
+ newSequence.children
67
+ .concat(sourceValue.children, differenceValue.children)
68
+ .uniq! {|a| a.anchor}
69
+
70
+ level.insert(0, sourceKey)
71
+ level.insert(1, newSequence)
72
+ elsif (sourceValue.is_a?(Psych::Nodes::Alias) && differenceValue.is_a?(Psych::Nodes::Alias))
73
+ if (sourceValue.anchor == differenceValue.anchor) then
74
+ level.insert(0, sourceKey)
75
+ level.insert(1, sourceValue)
76
+ else
77
+ newSequence = Psych::Nodes::Sequence.new(sourceValue.anchor, sourceValue.tag, sourceValue.implicit, Psych::Nodes::Sequence::FLOW)
78
+
79
+ newSequence.children
80
+ .concat([sourceValue, differenceValue])
81
+ .uniq! {|a| a.anchor}
82
+
83
+ level.insert(0, sourceKey)
84
+ level.insert(1, newSequence)
85
+ end
86
+ end
87
+ end
88
+ elsif (differenceValue.is_a?(Psych::Nodes::Mapping)) then
89
+ childLevel = combine_levels(sourceValue.children, differenceValue.children)
90
+
91
+ newMapping = Psych::Nodes::Mapping.new(sourceValue.anchor, sourceValue.tag, sourceValue.implicit, sourceValue.style)
92
+
93
+ if (childLevel.length > 0) then
94
+ newMapping.children.push(*childLevel)
95
+ end
96
+
97
+ level << differenceKey
98
+ level << newMapping
99
+ else
100
+ level << differenceKey
101
+ level << differenceValue
102
+ end
103
+ end
104
+ }
105
+
106
+ # Add all difference pairs that don't exist in the source
107
+
108
+ differenceChildren.each {|differencePair|
109
+ differenceKey = differencePair[0]
110
+ differenceValue = differencePair[1]
111
+
112
+ if (sourceChildren.none? {|i| i[0].value == differenceKey.value}) then
113
+ if (differenceKey.value == '<<') then
114
+ level.insert(0, differenceKey)
115
+ level.insert(1, differenceValue)
116
+ else
117
+ level << differenceKey
118
+ level << differenceValue
119
+ end
120
+ end
121
+ }
122
+
123
+ level
124
+ end
125
+
126
+ # def flatten_merge_keys(s)
127
+ # level = []
128
+
129
+ # sourceChildren = s.each_slice(2).to_a
130
+
131
+ # mergeKeys = sourceChildren.find_all {|i| i[0].value == "<<" }
132
+
133
+ # if (mergeKeys.length > 0) then
134
+ # if (mergeKeys.length == 1) then
135
+ # # Add merge key
136
+ # level << mergeKeys.first[0]
137
+ # level << mergeKeys.first[1]
138
+ # else
139
+ # newSequence = Psych::Nodes::Sequence.new(nil, nil, true, Psych::Nodes::Sequence::FLOW)
140
+
141
+ # mergeKeys.each {|m|
142
+ # if (m[1].is_a?(Psych::Nodes::Alias)) then
143
+ # newSequence.children << m[1]
144
+ # elsif (m[1].is_a?(Psych::Nodes::Sequence)) then
145
+ # newSequence.children.concat(m[1].children)
146
+ # end
147
+ # }
148
+
149
+ # level << Psych::Nodes::Scalar.new("<<")
150
+ # level << newSequence
151
+ # end
152
+ # end
153
+
154
+ # sourceChildren.each {|sourcePair|
155
+ # sourceKey = sourcePair[0]
156
+ # sourceValue = sourcePair[1]
157
+
158
+ # if (sourceValue.is_a?(Psych::Nodes::Mapping)) then
159
+ # childLevel = flatten_merge_keys(sourceValue.children)
160
+
161
+ # newMapping = Psych::Nodes::Mapping.new(sourceValue.anchor, sourceValue.tag, sourceValue.implicit, sourceValue.style)
162
+
163
+ # if (childLevel.length > 0) then
164
+ # newMapping.children.push(*childLevel)
165
+ # end
166
+
167
+ # level << sourceKey
168
+ # level << newMapping
169
+ # else
170
+ # if (sourceKey.value != "<<") then
171
+ # level << sourceKey
172
+ # level << sourceValue
173
+ # end
174
+ # end
175
+ # }
176
+
177
+ # level
178
+ # end
179
+
180
+ def combine_files(sourceFilePath, differenceFilePath)
181
+ sourceFile = File.open(sourceFilePath, "r")
182
+ differenceFile = File.open(differenceFilePath, "r")
183
+
184
+ begin
185
+ output = combine(sourceFile, differenceFile)
186
+ ensure
187
+ sourceFile.close
188
+ differenceFile.close
189
+ end
190
+
191
+ output
192
+ end
193
+
194
+ def combine(source, difference)
195
+ # Load files
196
+ sourceDocument = YAML.parse(source)
197
+ differenceDocument = YAML.parse(difference)
198
+
199
+ # Flatten merge keys for older ArchivesSpace files
200
+ sourceDocument = YAMLTools.flatten_merge_keys(sourceDocument.root.children)
201
+ differenceDocument = YAMLTools.flatten_merge_keys(differenceDocument.root.children)
202
+
203
+ @combined = combine_levels(sourceDocument, differenceDocument)
204
+
205
+ if (@combined.length > 0) then
206
+ output = YAMLTools.createDocument(@combined)
207
+ else
208
+ output = ''
209
+ end
210
+
211
+ output
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,267 @@
1
+ require 'yaml'
2
+
3
+ module YAMLTools
4
+ class Comparer
5
+ @source_anchors = {}
6
+ @modified_anchors = []
7
+
8
+ def processLevel (s, d, includeAnchorDependencies)
9
+ level = []
10
+
11
+ # Split into key/value pairs
12
+ sourceChildren = s.each_slice(2).to_a
13
+ destinationChildren = d.each_slice(2).to_a
14
+
15
+ # Add all anchors for this level for use when performing potential comparisons later
16
+ sourceChildren.find_all {|i| !i[1].is_a?(Psych::Nodes::Alias) && !i[1].anchor.nil?}.each {|i| @source_anchors[i[1].anchor] = i[1]}
17
+
18
+ destinationChildren.each {|destinationPair|
19
+ destinationKey = destinationPair[0]
20
+ destinationValue = destinationPair[1]
21
+
22
+ # Find source pair
23
+ sourcePairs = sourceChildren.find_all {|i| i[0].value == destinationKey.value}
24
+
25
+ if (sourcePairs.length > 1) then
26
+ if (destinationKey.value == "<<") then
27
+ # Find merge key with matching alias
28
+ sourcePair = sourcePairs.find {|i| i[1].is_a?(Psych::Nodes::Alias) && i[1].anchor == destinationValue.anchor}
29
+ else
30
+ # Some ArchivesSpace files have duplicate keys so use the last one
31
+ sourcePair = sourcePairs.last
32
+ end
33
+ else
34
+ sourcePair = sourcePairs.first
35
+ end
36
+
37
+ if (sourcePair == nil) then
38
+ # Source not found so copy node
39
+ level << destinationKey
40
+ level << destinationValue
41
+ else
42
+ sourceKey = sourcePair[0]
43
+ sourceValue = sourcePair[1]
44
+
45
+ if (sourceKey.value == "<<") then
46
+ # Handle merge keys specifically since they can be an individual alias or a sequence or aliases
47
+
48
+ if (sourceValue.is_a?(Psych::Nodes::Sequence)) then
49
+ if (destinationValue.is_a?(Psych::Nodes::Sequence)) then
50
+ if (sourceValue.children.length == destinationValue.children.length) then
51
+ # Compare sequences
52
+ sourceValue.children.each_with_index {|a, index|
53
+ if (a.anchor != destinationValue.children[index].anchor || (includeAnchorDependencies && @modified_anchors.include?(destinationValue.children[index].anchor))) then
54
+ # Different aliases or ordering
55
+ level << destinationKey
56
+ level << destinationValue
57
+ break
58
+ end
59
+ }
60
+ else
61
+ # Different number of aliases
62
+ level << destinationKey
63
+ level << destinationValue
64
+ end
65
+ elsif (destinationValue.is_a?(Psych::Nodes::Alias)) then
66
+ # Sequence of aliases overriden by single alias
67
+ level << destinationKey
68
+ level << destinationValue
69
+ else
70
+ # Bad data
71
+ end
72
+ elsif (sourceValue.is_a?(Psych::Nodes::Alias)) then
73
+ if (destinationValue.is_a?(Psych::Nodes::Sequence)) then
74
+ # Single alias overriden by sequence of aliases
75
+ level << destinationKey
76
+ level << destinationValue
77
+ elsif (destinationValue.is_a?(Psych::Nodes::Alias)) then
78
+ # Compare aliases
79
+ if (sourceValue.anchor != destinationValue.anchor || (includeAnchorDependencies && @modified_anchors.include?(destinationValue.anchor))) then
80
+ # Different aliases
81
+ level << destinationKey
82
+ level << destinationValue
83
+ end
84
+ else
85
+ # Bad data
86
+ end
87
+ else
88
+ # Bad data
89
+ end
90
+ elsif (destinationValue.is_a?(Psych::Nodes::Mapping)) then
91
+ childLevel = processLevel(sourceValue.children, destinationValue.children, includeAnchorDependencies)
92
+
93
+ if (childLevel.length > 0) then
94
+ newMapping = Psych::Nodes::Mapping.new(destinationValue.anchor, destinationValue.tag, destinationValue.implicit, destinationValue.style)
95
+ newMapping.children.push(*childLevel)
96
+
97
+ level << destinationKey
98
+ level << newMapping
99
+
100
+ if (destinationValue.anchor != nil) then
101
+ @modified_anchors << destinationValue.anchor
102
+ end
103
+ end
104
+ elsif (destinationValue.is_a?(Psych::Nodes::Scalar)) then
105
+ if (sourceValue.is_a?(Psych::Nodes::Scalar) && (destinationValue.value != sourceValue.value)) then
106
+ level << destinationKey
107
+ level << destinationValue
108
+
109
+ if destinationValue.anchor != nil then
110
+ @modified_anchors << destinationValue.anchor
111
+ end
112
+ elsif (sourceValue.is_a?(Psych::Nodes::Alias || (includeAnchorDependencies && @modified_anchors.include?(destinationValue.anchor)))) then
113
+ level << destinationKey
114
+ level << destinationValue
115
+ end
116
+ elsif (destinationValue.is_a?(Psych::Nodes::Alias)) then
117
+ if (sourceValue.is_a?(Psych::Nodes::Alias) && (destinationValue.anchor != sourceValue.anchor)) then
118
+ level << destinationKey
119
+ level << destinationValue
120
+ elsif (sourceValue.is_a?(Psych::Nodes::Scalar)) then
121
+ level << destinationKey
122
+ level << destinationValue
123
+ end
124
+ end
125
+ end
126
+ }
127
+
128
+ if (includeAnchorDependencies)
129
+ # Find source pairs where value is alias that don't exist in destination
130
+ # Look for aliases whose anchor was modified
131
+ sourceChildren.find_all {|i|
132
+ i[1].is_a?(Psych::Nodes::Alias) &&
133
+ !i[1].anchor.nil? &&
134
+ @modified_anchors.include?(i[1].anchor)
135
+ }.each {|sp|
136
+ dPair = destinationChildren.find_all {|i| i[0].value == sp[0].value}.last
137
+
138
+ if (dPair == nil) then
139
+ level << sp[0]
140
+ level << sp[1]
141
+ end
142
+ }
143
+ end
144
+
145
+ level
146
+ end
147
+
148
+ def processModifiedAnchors(s, anchors)
149
+ level = []
150
+
151
+ # Split into key/value pairs
152
+ sourceChildren = s.each_slice(2).to_a
153
+
154
+ sourceChildren.each {|sourcePair|
155
+ sourceKey = sourcePair[0]
156
+ sourceValue = sourcePair[1]
157
+
158
+ # Check if merge key
159
+ if (sourceKey.value == "<<") then
160
+ # Check if in modified_anchors
161
+
162
+ if (sourceValue.is_a?(Psych::Nodes::Sequence)) then
163
+ # Check each anchor in sequence
164
+ aliases = sourceValue.children.find_all {|a| anchors.include?(a.anchor)}
165
+
166
+ if (aliases.length > 0) then
167
+ if (aliases.length == 1) then
168
+ level << sourceKey
169
+ level << aliases[0]
170
+ else
171
+ newSequence = Psych::Nodes::Sequence.new(sourceValue.anchor, sourceValue.tag, sourceValue.implicit, sourceValue.style)
172
+ newSequence.children.push(*aliases)
173
+
174
+ level << sourceKey
175
+ level << newSequence
176
+ end
177
+ end
178
+ else
179
+ if (anchors.include?(sourceValue.anchor)) then
180
+ # Add the merge key and include in the level
181
+ level << sourceKey
182
+ level << sourceValue
183
+ end
184
+ end
185
+
186
+ next
187
+ elsif (sourceValue.is_a?(Psych::Nodes::Mapping)) then
188
+ childLevel = processModifiedAnchors(sourceValue.children, anchors)
189
+
190
+ if (childLevel.length > 0) then
191
+ newMapping = Psych::Nodes::Mapping.new(sourceValue.anchor, sourceValue.tag, sourceValue.implicit, sourceValue.style)
192
+ newMapping.children.push(*childLevel)
193
+
194
+ level << sourceKey
195
+ level << newMapping
196
+
197
+ # Add new anchors that are located
198
+ if (sourceValue.anchor != nil) then
199
+ @modified_anchors << sourceValue.anchor
200
+ end
201
+ end
202
+ elsif (sourceValue.is_a?(Psych::Nodes::Alias) && anchors.include?(sourceValue.anchor)) then
203
+ # Add the merge key and include in the level
204
+ level << sourceKey
205
+ level << sourceValue
206
+ end
207
+ }
208
+
209
+ level
210
+ end
211
+
212
+ def compare_files(sourceFilePath, destinationFilePath, includeAnchorDependencies = false)
213
+ sourceFile = File.open(sourceFilePath, "r")
214
+ differenceFile = File.open(destinationFilePath, "r")
215
+
216
+ begin
217
+ result = compare(sourceFile, differenceFile, includeAnchorDependencies)
218
+ ensure
219
+ sourceFile.close
220
+ differenceFile.close
221
+ end
222
+
223
+ result
224
+ end
225
+
226
+ def compare(source, destination, includeAnchorDependencies = false)
227
+ @source_anchors = {}
228
+ @modified_anchors = []
229
+
230
+ sourceDocument = YAML.parse(source)
231
+ destinationDocument = YAML.parse(destination)
232
+
233
+ # Flatten merge keys for older ArchivesSpace files
234
+ sourceRootLevel = YAMLTools.flatten_merge_keys(sourceDocument.root.children)
235
+ destinationRootLevel = YAMLTools.flatten_merge_keys(destinationDocument.root.children)
236
+
237
+ @differences = processLevel(sourceRootLevel, destinationRootLevel, includeAnchorDependencies)
238
+
239
+ if (includeAnchorDependencies) then
240
+ @current_modified_anchors = []
241
+
242
+ combiner = Combiner.new
243
+
244
+ loop do
245
+ @current_modified_anchors = @modified_anchors.clone
246
+ @modified_anchors = []
247
+ modified_anchor_additions = processModifiedAnchors(sourceRootLevel, @current_modified_anchors)
248
+
249
+ if (modified_anchor_additions.length > 0) then
250
+ mergedDifferences = combiner.combine_levels(@differences, modified_anchor_additions)
251
+ @differences = mergedDifferences
252
+ end
253
+
254
+ break if (@current_modified_anchors.length == 0)
255
+ end
256
+ end
257
+
258
+ if (@differences.length > 0) then
259
+ output = YAMLTools.createDocument(@differences)
260
+ else
261
+ output = ''
262
+ end
263
+
264
+ output
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,74 @@
1
+ require 'yaml'
2
+
3
+ module YAMLTools
4
+ def self.createDocument(levels)
5
+ document = Psych::Nodes::Document.new()
6
+ documentRoot = Psych::Nodes::Mapping.new();
7
+ documentRoot.children.push(*levels)
8
+ document.children << documentRoot
9
+
10
+ stream = Psych::Nodes::Stream.new
11
+ stream.children << document
12
+ output = stream.to_yaml
13
+
14
+ # Remove initial document start
15
+ document_start = (output.index("---\n") || size - 1) + 4
16
+ output.slice!(0, document_start)
17
+
18
+ output
19
+ end
20
+
21
+ def self.flatten_merge_keys(s)
22
+ level = []
23
+
24
+ sourceChildren = s.each_slice(2).to_a
25
+
26
+ mergeKeys = sourceChildren.find_all {|i| i[0].value == "<<" }
27
+
28
+ if (mergeKeys.length > 0) then
29
+ if (mergeKeys.length == 1) then
30
+ # Add merge key
31
+ level << mergeKeys.first[0]
32
+ level << mergeKeys.first[1]
33
+ else
34
+ newSequence = Psych::Nodes::Sequence.new(nil, nil, true, Psych::Nodes::Sequence::FLOW)
35
+
36
+ mergeKeys.each {|m|
37
+ if (m[1].is_a?(Psych::Nodes::Alias)) then
38
+ newSequence.children << m[1]
39
+ elsif (m[1].is_a?(Psych::Nodes::Sequence)) then
40
+ newSequence.children.concat(m[1].children)
41
+ end
42
+ }
43
+
44
+ level << Psych::Nodes::Scalar.new("<<")
45
+ level << newSequence
46
+ end
47
+ end
48
+
49
+ sourceChildren.each {|sourcePair|
50
+ sourceKey = sourcePair[0]
51
+ sourceValue = sourcePair[1]
52
+
53
+ if (sourceValue.is_a?(Psych::Nodes::Mapping)) then
54
+ childLevel = flatten_merge_keys(sourceValue.children)
55
+
56
+ newMapping = Psych::Nodes::Mapping.new(sourceValue.anchor, sourceValue.tag, sourceValue.implicit, sourceValue.style)
57
+
58
+ if (childLevel.length > 0) then
59
+ newMapping.children.push(*childLevel)
60
+ end
61
+
62
+ level << sourceKey
63
+ level << newMapping
64
+ else
65
+ if (sourceKey.value != "<<") then
66
+ level << sourceKey
67
+ level << sourceValue
68
+ end
69
+ end
70
+ }
71
+
72
+ level
73
+ end
74
+ end
data/lib/yaml_tools.rb ADDED
@@ -0,0 +1,5 @@
1
+ module YAMLTools
2
+ require 'tools/combine'
3
+ require 'tools/compare'
4
+ require 'tools/utility'
5
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yaml_tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Atlas Systems, Inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-02-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.12'
27
+ description:
28
+ email:
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/tools/combine.rb
34
+ - lib/tools/compare.rb
35
+ - lib/tools/utility.rb
36
+ - lib/yaml_tools.rb
37
+ homepage: https://github.com/AtlasSystems/yaml_tools
38
+ licenses:
39
+ - MIT
40
+ metadata: {}
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '2.5'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '4'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.4.6
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Tools for YAML files.
63
+ test_files: []