psychgus 1.2.0 → 1.3.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 +4 -4
- data/.yardopts +4 -0
- data/CHANGELOG.md +58 -3
- data/Gemfile +0 -18
- data/README.md +38 -43
- data/Rakefile +33 -126
- data/lib/psychgus.rb +178 -186
- data/lib/psychgus/blueberry.rb +28 -39
- data/lib/psychgus/ext.rb +6 -17
- data/lib/psychgus/ext/core_ext.rb +17 -28
- data/lib/psychgus/ext/node_ext.rb +13 -24
- data/lib/psychgus/ext/yaml_tree_ext.rb +23 -34
- data/lib/psychgus/stylables.rb +78 -89
- data/lib/psychgus/styled_document_stream.rb +14 -25
- data/lib/psychgus/styled_tree_builder.rb +90 -101
- data/lib/psychgus/styler.rb +33 -44
- data/lib/psychgus/stylers.rb +67 -78
- data/lib/psychgus/super_sniffer.rb +128 -138
- data/lib/psychgus/super_sniffer/parent.rb +48 -149
- data/lib/psychgus/version.rb +4 -16
- data/psychgus.gemspec +46 -49
- data/test/blueberry_test.rb +30 -41
- data/test/psychgus_test.rb +73 -54
- data/test/psychgus_tester.rb +23 -31
- data/test/sniffer_test.rb +18 -32
- data/test/styler_test.rb +20 -31
- data/test/stylers_test.rb +32 -43
- metadata +38 -23
@@ -1,22 +1,11 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
4
|
#--
|
5
5
|
# This file is part of Psychgus.
|
6
|
-
# Copyright (c) 2019 Jonathan Bradley Whited
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# it under the terms of the GNU Lesser General Public License as published by
|
10
|
-
# the Free Software Foundation, either version 3 of the License, or
|
11
|
-
# (at your option) any later version.
|
12
|
-
#
|
13
|
-
# Psychgus is distributed in the hope that it will be useful,
|
14
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
-
# GNU Lesser General Public License for more details.
|
17
|
-
#
|
18
|
-
# You should have received a copy of the GNU Lesser General Public License
|
19
|
-
# along with Psychgus. If not, see <http://www.gnu.org/licenses/>.
|
6
|
+
# Copyright (c) 2019-2021 Jonathan Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
20
9
|
#++
|
21
10
|
|
22
11
|
|
@@ -26,12 +15,11 @@ module Psychgus
|
|
26
15
|
class SuperSniffer
|
27
16
|
###
|
28
17
|
# An empty {SuperSniffer} used for speed when you don't need sniffing in {StyledTreeBuilder}.
|
29
|
-
#
|
30
|
-
# @author Jonathan Bradley Whited
|
18
|
+
#
|
19
|
+
# @author Jonathan Bradley Whited
|
31
20
|
# @since 1.0.0
|
32
21
|
###
|
33
22
|
class Empty < SuperSniffer
|
34
|
-
def initialize(*) end
|
35
23
|
def add_alias(*) end
|
36
24
|
def add_scalar(*) end
|
37
25
|
def end_document(*) end
|
@@ -44,29 +32,31 @@ module Psychgus
|
|
44
32
|
def start_stream(*) end
|
45
33
|
end
|
46
34
|
end
|
47
|
-
|
35
|
+
|
48
36
|
###
|
49
37
|
# This is used in {StyledTreeBuilder} to "sniff" information about the YAML.
|
50
|
-
#
|
38
|
+
#
|
51
39
|
# Then this information can be used in a {Styler} and/or a {Blueberry}.
|
52
|
-
#
|
40
|
+
#
|
53
41
|
# Most information is straightforward:
|
54
42
|
# - {#aliases} # Array of Psych::Nodes::Alias processed so far
|
43
|
+
# - {#documents} # Array of Psych::Nodes::Document processed so far
|
55
44
|
# - {#mappings} # Array of Psych::Nodes::Mapping processed so far
|
56
|
-
# - {#nodes} # Array of
|
45
|
+
# - {#nodes} # Array of Psych::Nodes::Node processed so far
|
57
46
|
# - {#scalars} # Array of Psych::Nodes::Scalar processed so far
|
58
47
|
# - {#sequences} # Array of Psych::Nodes::Sequence processed so far
|
59
|
-
#
|
48
|
+
# - {#streams} # Array of Psych::Nodes::Stream processed so far
|
49
|
+
#
|
60
50
|
# {#parent} is the current {SuperSniffer::Parent} of the node being processed,
|
61
|
-
# which is
|
62
|
-
#
|
51
|
+
# which is an empty Parent for the first node (not nil).
|
52
|
+
#
|
63
53
|
# {#parents} are all of the (grand){SuperSniffer::Parent}(s) for the current node,
|
64
|
-
# which is empty for the first node.
|
65
|
-
#
|
54
|
+
# which is an Array that just contains an empty Parent for the first node.
|
55
|
+
#
|
66
56
|
# A parent is a Mapping or Sequence, or a Key (Scalar) in a Mapping.
|
67
|
-
#
|
57
|
+
#
|
68
58
|
# {#level} and {#position} can be best understood by an example.
|
69
|
-
#
|
59
|
+
#
|
70
60
|
# If you have this YAML:
|
71
61
|
# Burgers:
|
72
62
|
# Classic:
|
@@ -85,10 +75,10 @@ module Psychgus
|
|
85
75
|
# - Mushrooms
|
86
76
|
# - [Lettuce, Onions, Pickles, Tomatoes]
|
87
77
|
# - [[Ketchup,Mustard], [Salt,Pepper]]
|
88
|
-
#
|
78
|
+
#
|
89
79
|
# Then the levels and positions will be as follows:
|
90
80
|
# # (level:position):current_node - <parent:(parent_level:parent_position)>
|
91
|
-
#
|
81
|
+
#
|
92
82
|
# (1:1):Psych::Nodes::Stream - <root:(0:0)>
|
93
83
|
# (1:1):Psych::Nodes::Document - <stream:(1:1)>
|
94
84
|
# (1:1):Psych::Nodes::Mapping - <doc:(1:1)>
|
@@ -135,37 +125,37 @@ module Psychgus
|
|
135
125
|
# (5:2):Psych::Nodes::Sequence - <seq:(4:3)>
|
136
126
|
# (6:1):Salt - <seq:(5:2)>
|
137
127
|
# (6:2):Pepper - <seq:(5:2)>
|
138
|
-
#
|
139
|
-
# The
|
128
|
+
#
|
129
|
+
# "The Super Sniffer" is the nickname for Gus's nose from the TV show Psych
|
140
130
|
# because he has a very refined sense of smell.
|
141
|
-
#
|
131
|
+
#
|
142
132
|
# @note You should never call the methods that are not readers, like {#add_alias}, {#start_mapping}, etc.
|
143
133
|
# unless you are extending this class (creating a subclass).
|
144
|
-
#
|
145
|
-
# @author Jonathan Bradley Whited
|
134
|
+
#
|
135
|
+
# @author Jonathan Bradley Whited
|
146
136
|
# @since 1.0.0
|
147
|
-
#
|
137
|
+
#
|
148
138
|
# @see StyledTreeBuilder
|
149
139
|
# @see Styler
|
150
140
|
# @see Blueberry#psychgus_stylers
|
151
141
|
###
|
152
142
|
class SuperSniffer
|
153
|
-
EMPTY = Empty.new
|
154
|
-
|
155
|
-
attr_reader :aliases
|
156
|
-
attr_reader :documents
|
157
|
-
attr_reader :level
|
158
|
-
attr_reader :mappings
|
159
|
-
attr_reader :nodes
|
160
|
-
attr_reader :parent
|
161
|
-
attr_reader :parents
|
162
|
-
attr_reader :position
|
163
|
-
attr_reader :scalars
|
164
|
-
attr_reader :sequences
|
165
|
-
attr_reader :streams
|
166
|
-
|
143
|
+
EMPTY = Empty.new.freeze
|
144
|
+
|
145
|
+
attr_reader :aliases # @return [Array<Psych::Nodes::Alias>] the aliases processed so far
|
146
|
+
attr_reader :documents # @return [Array<Psych::Nodes::Document>] the documents processed so far
|
147
|
+
attr_reader :level # @return [Integer] the current level
|
148
|
+
attr_reader :mappings # @return [Array<Psych::Nodes::Mapping>] the mappings processed so far
|
149
|
+
attr_reader :nodes # @return [Array<Psych::Nodes::Node>] the nodes processed so far
|
150
|
+
attr_reader :parent # @return [Parent] the current parent
|
151
|
+
attr_reader :parents # @return [Array<Parent>] the current (grand)parents
|
152
|
+
attr_reader :position # @return [Integer] the current position
|
153
|
+
attr_reader :scalars # @return [Array<Psych::Nodes::Scalar>] the scalars processed so far
|
154
|
+
attr_reader :sequences # @return [Array<Psych::Nodes::Sequence>] the sequences processed so far
|
155
|
+
attr_reader :streams # @return [Array<Psych::Nodes::Stream>] the streams processed so far
|
156
|
+
|
167
157
|
# Initialize this class for sniffing.
|
168
|
-
def initialize
|
158
|
+
def initialize
|
169
159
|
@aliases = []
|
170
160
|
@documents = []
|
171
161
|
@level = 0
|
@@ -177,240 +167,240 @@ module Psychgus
|
|
177
167
|
@scalars = []
|
178
168
|
@sequences = []
|
179
169
|
@streams = []
|
180
|
-
|
170
|
+
|
181
171
|
# Do not pass in "top_level: true"
|
182
172
|
start_parent(nil,debug_tag: :root)
|
183
173
|
end
|
184
|
-
|
174
|
+
|
185
175
|
# Add a Psych::Nodes::Alias to this class only (not to the YAML).
|
186
|
-
#
|
176
|
+
#
|
187
177
|
# A {Styler} should probably never call this.
|
188
|
-
#
|
178
|
+
#
|
189
179
|
# @param node [Psych::Nodes::Alias] the alias to add
|
190
|
-
#
|
180
|
+
#
|
191
181
|
# @see add_child
|
192
182
|
def add_alias(node)
|
193
183
|
add_child(node)
|
194
184
|
@aliases.push(node)
|
195
185
|
end
|
196
|
-
|
186
|
+
|
197
187
|
# Add a Psych::Nodes::Scalar to this class only (not to the YAML).
|
198
|
-
#
|
188
|
+
#
|
199
189
|
# A {Styler} should probably never call this.
|
200
|
-
#
|
190
|
+
#
|
201
191
|
# @param node [Psych::Nodes::Scalar] the scalar to add
|
202
|
-
#
|
192
|
+
#
|
203
193
|
# @see add_child
|
204
194
|
def add_scalar(node)
|
205
195
|
add_child(node)
|
206
196
|
@scalars.push(node)
|
207
197
|
end
|
208
|
-
|
198
|
+
|
209
199
|
# End a Psych::Nodes::Document started with {#start_document}.
|
210
|
-
#
|
200
|
+
#
|
211
201
|
# Pops off a parent from {#parents} and sets {#parent} to the last one.
|
212
202
|
# {#level} and {#position} are reset according to the last parent.
|
213
|
-
#
|
203
|
+
#
|
214
204
|
# A {Styler} should probably never call this.
|
215
|
-
def end_document
|
205
|
+
def end_document
|
216
206
|
end_parent(top_level: true)
|
217
207
|
end
|
218
|
-
|
208
|
+
|
219
209
|
# End a Psych::Nodes::Mapping started with {#start_mapping}.
|
220
|
-
#
|
210
|
+
#
|
221
211
|
# Pops off a parent from {#parents} and sets {#parent} to the last one.
|
222
212
|
# {#level} and {#position} are reset according to the last parent.
|
223
|
-
#
|
213
|
+
#
|
224
214
|
# A {Styler} should probably never call this.
|
225
|
-
#
|
215
|
+
#
|
226
216
|
# @see end_parent
|
227
|
-
def end_mapping
|
217
|
+
def end_mapping
|
228
218
|
end_parent(mapping_value: true)
|
229
219
|
end
|
230
|
-
|
220
|
+
|
231
221
|
# End a Psych::Nodes::Sequence started with {#start_sequence}.
|
232
|
-
#
|
222
|
+
#
|
233
223
|
# Pops off a parent from {#parents} and sets {#parent} to the last one.
|
234
224
|
# {#level} and {#position} are reset according to the last parent.
|
235
|
-
#
|
225
|
+
#
|
236
226
|
# A {Styler} should probably never call this.
|
237
|
-
#
|
227
|
+
#
|
238
228
|
# @see end_parent
|
239
|
-
def end_sequence
|
229
|
+
def end_sequence
|
240
230
|
end_parent(mapping_value: true)
|
241
231
|
end
|
242
|
-
|
232
|
+
|
243
233
|
# End a Psych::Nodes::Stream started with {#start_stream}.
|
244
|
-
#
|
234
|
+
#
|
245
235
|
# Pops off a parent from {#parents} and sets {#parent} to the last one.
|
246
236
|
# {#level} and {#position} are reset according to the last parent.
|
247
|
-
#
|
237
|
+
#
|
248
238
|
# A {Styler} should probably never call this.
|
249
|
-
def end_stream
|
239
|
+
def end_stream
|
250
240
|
end_parent(top_level: true)
|
251
241
|
end
|
252
|
-
|
242
|
+
|
253
243
|
# Start a Psych::Nodes::Document.
|
254
|
-
#
|
244
|
+
#
|
255
245
|
# Creates a {SuperSniffer::Parent}, sets {#parent} to it, and adds it to {#parents}.
|
256
246
|
# {#level} and {#position} are incremented/set accordingly.
|
257
|
-
#
|
247
|
+
#
|
258
248
|
# A {Styler} should probably never call this.
|
259
|
-
#
|
249
|
+
#
|
260
250
|
# @param node [Psych::Nodes::Document] the Document to start
|
261
|
-
#
|
251
|
+
#
|
262
252
|
# @see start_parent
|
263
253
|
def start_document(node)
|
264
254
|
start_parent(node,debug_tag: :doc,top_level: true)
|
265
255
|
@documents.push(node)
|
266
256
|
end
|
267
|
-
|
257
|
+
|
268
258
|
# Start a Psych::Nodes::Mapping.
|
269
|
-
#
|
259
|
+
#
|
270
260
|
# Creates a {SuperSniffer::Parent}, sets {#parent} to it, and adds it to {#parents}.
|
271
261
|
# {#level} and {#position} are incremented/set accordingly.
|
272
|
-
#
|
262
|
+
#
|
273
263
|
# A {Styler} should probably never call this.
|
274
|
-
#
|
264
|
+
#
|
275
265
|
# @param node [Psych::Nodes::Mapping] the Mapping to start
|
276
|
-
#
|
266
|
+
#
|
277
267
|
# @see start_parent
|
278
268
|
def start_mapping(node)
|
279
269
|
start_parent(node,debug_tag: :map,child_type: :key)
|
280
270
|
@mappings.push(node)
|
281
271
|
end
|
282
|
-
|
272
|
+
|
283
273
|
# Start a Psych::Nodes::Sequence.
|
284
|
-
#
|
274
|
+
#
|
285
275
|
# Creates a {SuperSniffer::Parent}, sets {#parent} to it, and adds it to {#parents}.
|
286
276
|
# {#level} and {#position} are incremented/set accordingly.
|
287
|
-
#
|
277
|
+
#
|
288
278
|
# A {Styler} should probably never call this.
|
289
|
-
#
|
279
|
+
#
|
290
280
|
# @param node [Psych::Nodes::Sequence] the Sequence to start
|
291
|
-
#
|
281
|
+
#
|
292
282
|
# @see start_parent
|
293
283
|
def start_sequence(node)
|
294
284
|
start_parent(node,debug_tag: :seq)
|
295
285
|
@sequences.push(node)
|
296
286
|
end
|
297
|
-
|
287
|
+
|
298
288
|
# Start a Psych::Nodes::Stream.
|
299
|
-
#
|
289
|
+
#
|
300
290
|
# Creates a {SuperSniffer::Parent}, sets {#parent} to it, and adds it to {#parents}.
|
301
291
|
# {#level} and {#position} are incremented/set accordingly.
|
302
|
-
#
|
292
|
+
#
|
303
293
|
# A {Styler} should probably never call this.
|
304
|
-
#
|
294
|
+
#
|
305
295
|
# @param node [Psych::Nodes::Stream] the Stream to start
|
306
|
-
#
|
296
|
+
#
|
307
297
|
# @see start_parent
|
308
298
|
def start_stream(node)
|
309
299
|
start_parent(node,debug_tag: :stream,top_level: true)
|
310
300
|
@streams.push(node)
|
311
301
|
end
|
312
|
-
|
302
|
+
|
313
303
|
protected
|
314
|
-
|
304
|
+
|
315
305
|
# Add a non-parent node.
|
316
|
-
#
|
306
|
+
#
|
317
307
|
# This will increment {#position} accordingly, and if the child is a Key to a Mapping,
|
318
308
|
# create a fake "{SuperSniffer::Parent}".
|
319
|
-
#
|
309
|
+
#
|
320
310
|
# @param node [Psych::Nodes::Node] the non-parent Node to add
|
321
|
-
#
|
311
|
+
#
|
322
312
|
# @see end_mapping_value
|
323
313
|
def add_child(node)
|
324
|
-
if !@parent.nil?
|
314
|
+
if !@parent.nil?
|
325
315
|
# Fake a "parent" if necessary
|
326
316
|
case @parent.child_type
|
327
317
|
when :key
|
328
318
|
start_mapping_key(node)
|
329
319
|
return
|
330
320
|
when :value
|
331
|
-
end_mapping_value
|
321
|
+
end_mapping_value
|
332
322
|
return
|
333
323
|
else
|
334
324
|
@parent.child_position += 1
|
335
325
|
end
|
336
326
|
end
|
337
|
-
|
327
|
+
|
338
328
|
@position += 1
|
339
|
-
|
329
|
+
|
340
330
|
@nodes.push(node)
|
341
331
|
end
|
342
|
-
|
332
|
+
|
343
333
|
# End a fake "{SuperSniffer::Parent}" that is a Key/Value to a Mapping.
|
344
|
-
#
|
334
|
+
#
|
345
335
|
# @see add_child
|
346
|
-
def end_mapping_value
|
347
|
-
end_parent
|
348
|
-
|
349
|
-
@parent.child_type = :key unless @parent.nil?
|
336
|
+
def end_mapping_value
|
337
|
+
end_parent # Do not pass in "mapping_value: true" and/or "top_level: true"
|
338
|
+
|
339
|
+
@parent.child_type = :key unless @parent.nil?
|
350
340
|
end
|
351
|
-
|
341
|
+
|
352
342
|
# End a {SuperSniffer::Parent}.
|
353
|
-
#
|
343
|
+
#
|
354
344
|
# Pops off a parent from {#parents} and sets {#parent} to the last one.
|
355
345
|
# {#level} and {#position} are reset according to the last parent.
|
356
|
-
#
|
346
|
+
#
|
357
347
|
# @param mapping_value [true,false] true if parent can be the value of a Mapping's key
|
358
348
|
# @param top_level [true,false] true if a top-level parent (i.e., encapsulating the main data)
|
359
349
|
def end_parent(mapping_value: false,top_level: false)
|
360
|
-
@parents.pop
|
350
|
+
@parents.pop
|
361
351
|
@parent = @parents.last
|
362
|
-
|
352
|
+
|
363
353
|
@level = top_level ? 1 : (@level - 1)
|
364
|
-
|
365
|
-
if !@parent.nil?
|
354
|
+
|
355
|
+
if !@parent.nil?
|
366
356
|
@parent.child_position += 1
|
367
357
|
@position = @parent.child_position
|
368
|
-
|
358
|
+
|
369
359
|
# add_child() will not be called again, so end a fake "parent" manually with a fake "value"
|
370
360
|
# - This is necessary for any parents that can be the value of a map's key (e.g., Sequence)
|
371
|
-
end_mapping_value
|
361
|
+
end_mapping_value if mapping_value && !@parent.child_type.nil?
|
372
362
|
end
|
373
363
|
end
|
374
|
-
|
364
|
+
|
375
365
|
# Start a fake "{SuperSniffer::Parent}" that is a Key/Value to a Mapping.
|
376
|
-
#
|
366
|
+
#
|
377
367
|
# Creates a {SuperSniffer::Parent}, sets {#parent} to it, and adds it to {#parents}.
|
378
368
|
# {#level} and {#position} are incremented/set accordingly.
|
379
|
-
#
|
369
|
+
#
|
380
370
|
# @param node [Psych::Nodes::Node] the Node to start
|
381
|
-
#
|
371
|
+
#
|
382
372
|
# @see start_parent
|
383
373
|
def start_mapping_key(node)
|
384
374
|
debug_tag = nil
|
385
|
-
|
375
|
+
|
386
376
|
# Value must be first because Scalar also has an anchor
|
387
377
|
if node.respond_to?(:value)
|
388
378
|
debug_tag = node.value
|
389
379
|
elsif node.respond_to?(:anchor)
|
390
380
|
debug_tag = node.anchor
|
391
381
|
end
|
392
|
-
|
393
|
-
debug_tag = :noface if debug_tag.nil?
|
394
|
-
|
382
|
+
|
383
|
+
debug_tag = :noface if debug_tag.nil?
|
384
|
+
|
395
385
|
start_parent(node,debug_tag: debug_tag,child_type: :value)
|
396
386
|
end
|
397
|
-
|
387
|
+
|
398
388
|
# Start a {SuperSniffer::Parent}.
|
399
|
-
#
|
389
|
+
#
|
400
390
|
# Creates a {SuperSniffer::Parent}, sets {#parent} to it, and adds it to {#parents}.
|
401
391
|
# {#level} and {#position} are incremented/set accordingly.
|
402
|
-
#
|
392
|
+
#
|
403
393
|
# @param node [Psych::Nodes::Node] the parent Node to start
|
404
394
|
# @param top_level [true,false] true if a top-level parent (i.e., encapsulating the main data)
|
405
395
|
# @param extra [Hash] the extra keyword args to pass to {SuperSniffer::Parent#initialize}
|
406
|
-
#
|
396
|
+
#
|
407
397
|
# @see SuperSniffer::Parent#initialize
|
408
398
|
def start_parent(node,top_level: false,**extra)
|
409
399
|
@parent = Parent.new(self,node,**extra)
|
410
|
-
|
400
|
+
|
411
401
|
@parents.push(@parent)
|
412
|
-
@nodes.push(node) unless node.nil?
|
413
|
-
|
402
|
+
@nodes.push(node) unless node.nil?
|
403
|
+
|
414
404
|
if top_level
|
415
405
|
@level = 1
|
416
406
|
@position = @parent.position
|