psychgus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,294 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ #--
5
+ # This file is part of Psychgus.
6
+ # Copyright (c) 2019 Jonathan Bradley Whited (@esotericpig)
7
+ #
8
+ # Psychgus is free software: you can redistribute it and/or modify
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/>.
20
+ #++
21
+
22
+
23
+ require 'psych'
24
+
25
+ require 'psychgus/styler'
26
+ require 'psychgus/super_sniffer'
27
+
28
+ module Psychgus
29
+ ###
30
+ # Use this wherever Psych::TreeBuilder would have been used, to enable styling.
31
+ #
32
+ # @author Jonathan Bradley Whited (@esotericpig)
33
+ # @since 1.0.0
34
+ #
35
+ # @see Psychgus.parser Psychgus.parser
36
+ # @see Psychgus.dump_stream Psychgus.dump_stream
37
+ # @see Psych::TreeBuilder
38
+ ###
39
+ class StyledTreeBuilder < Psych::TreeBuilder
40
+ # @return [true,false] whether to dereference aliases; output the actual value instead of the alias
41
+ attr_accessor :deref_aliases
42
+ alias_method :deref_aliases?,:deref_aliases
43
+
44
+ # @return [SuperSniffer] the {SuperSniffer} being used to sniff the YAML nodes, level, etc.
45
+ attr_reader :sniffer
46
+
47
+ # @return [Array<Stylers>] the {Styler}(s) being used to style the YAML nodes
48
+ attr_reader :stylers
49
+
50
+ # Initialize this class with {Styler}(s).
51
+ #
52
+ # @param stylers [Styler] {Styler}(s) to use for styling this TreeBuilder
53
+ # @param deref_aliases [true,false] whether to dereference aliases; output the actual value
54
+ # instead of the alias
55
+ def initialize(*stylers,deref_aliases: false,**options)
56
+ super()
57
+
58
+ @deref_aliases = deref_aliases
59
+ @sniffer = SuperSniffer.new()
60
+ @stylers = []
61
+
62
+ add_styler(*stylers)
63
+ end
64
+
65
+ # Add {Styler}(s) onto the end of the data structure.
66
+ #
67
+ # @param stylers [Styler] {Styler}(s) to add
68
+ #
69
+ # @return [self] this class
70
+ def add_styler(*stylers)
71
+ @stylers.push(*stylers)
72
+
73
+ return self
74
+ end
75
+
76
+ # Calls super, styler(s), and sniffer.
77
+ #
78
+ # @see Psych::TreeBuilder#alias
79
+ # @see Styler#style
80
+ # @see Styler#style_alias
81
+ # @see SuperSniffer#add_alias
82
+ #
83
+ # @return [Psych::Nodes::Alias] the alias node created
84
+ def alias(*)
85
+ node = super
86
+
87
+ @stylers.each do |styler|
88
+ styler.style(sniffer,node)
89
+ styler.style_alias(sniffer,node)
90
+ end
91
+
92
+ @sniffer.add_alias(node)
93
+
94
+ return node
95
+ end
96
+
97
+ # Calls super and sniffer.
98
+ #
99
+ # @see Psych::TreeBuilder#end_document
100
+ # @see SuperSniffer#end_document
101
+ def end_document(*)
102
+ result = super
103
+
104
+ @sniffer.end_document()
105
+
106
+ return result
107
+ end
108
+
109
+ # Calls super and sniffer.
110
+ #
111
+ # @see Psych::TreeBuilder#end_mapping
112
+ # @see SuperSniffer#end_mapping
113
+ def end_mapping(*)
114
+ result = super
115
+
116
+ @sniffer.end_mapping()
117
+
118
+ return result
119
+ end
120
+
121
+ # Calls super and sniffer.
122
+ #
123
+ # @see Psych::TreeBuilder#end_sequence
124
+ # @see SuperSniffer#end_sequence
125
+ def end_sequence(*)
126
+ result = super
127
+
128
+ @sniffer.end_sequence()
129
+
130
+ return result
131
+ end
132
+
133
+ # Calls super and sniffer.
134
+ #
135
+ # @see Psych::TreeBuilder#end_stream
136
+ # @see SuperSniffer#end_stream
137
+ def end_stream(*)
138
+ result = super
139
+
140
+ @sniffer.end_stream()
141
+
142
+ return result
143
+ end
144
+
145
+ # Insert {Styler}(s) at +index+ into the data structure.
146
+ #
147
+ # @param stylers [Styler] {Styler}(s) to insert
148
+ #
149
+ # @return [self] this class
150
+ def insert_styler(index,*stylers)
151
+ @stylers.insert(index,*stylers)
152
+
153
+ return self
154
+ end
155
+
156
+ # Remove the last {Styler}(s) from the data structure.
157
+ #
158
+ # @param count [Integer] the optional amount of tail elements to pop
159
+ #
160
+ # @return [Styler,Array<Styler>,nil] the last {Styler}(s), or if empty or count==0, nil
161
+ def pop_styler(count=1)
162
+ return nil if count == 0
163
+ return @stylers.pop() if count == 1
164
+
165
+ return @stylers.pop(count)
166
+ end
167
+
168
+ # Remove the {Styler} that matches +styler+ from the data structure.
169
+ #
170
+ # An optional +block+ can return a default value if not found.
171
+ #
172
+ # @param styler [Styler] the {Styler} to find and remove
173
+ # @param block [Proc] an optional block to call when +styler+ is not found
174
+ #
175
+ # @return [Styler,nil] the last {Styler}, or if not found, nil or the result of +block+
176
+ def remove_styler(styler,&block)
177
+ return @stylers.delete(styler,&block)
178
+ end
179
+
180
+ # Remove the {Styler} at +index+ from the data structure.
181
+ #
182
+ # @param index [Integer] the index of the {Styler} to remove
183
+ #
184
+ # @return [Styler,nil] the {Styler} removed or nil if empty
185
+ def remove_styler_at(index)
186
+ return @stylers.delete_at(index)
187
+ end
188
+
189
+ # Calls super, styler(s), and sniffer.
190
+ #
191
+ # @see Psych::TreeBuilder#scalar
192
+ # @see Styler#style
193
+ # @see Styler#style_scalar
194
+ # @see SuperSniffer#add_scalar
195
+ #
196
+ # @return [Psych::Nodes::Scalar] the scalar node created
197
+ def scalar(*)
198
+ node = super
199
+
200
+ @stylers.each do |styler|
201
+ styler.style(sniffer,node)
202
+ styler.style_scalar(sniffer,node)
203
+ end
204
+
205
+ @sniffer.add_scalar(node)
206
+
207
+ return node
208
+ end
209
+
210
+ # Calls super, styler(s), and sniffer.
211
+ #
212
+ # @see Psych::TreeBuilder#start_document
213
+ # @see Styler#style
214
+ # @see Styler#style_document
215
+ # @see SuperSniffer#start_document
216
+ #
217
+ # @return [Psych::Nodes::Document] the document node created
218
+ def start_document(*)
219
+ node = super
220
+
221
+ @stylers.each do |styler|
222
+ styler.style(sniffer,node)
223
+ styler.style_document(sniffer,node)
224
+ end
225
+
226
+ @sniffer.start_document(node)
227
+
228
+ return node
229
+ end
230
+
231
+ # Calls super, styler(s), and sniffer.
232
+ #
233
+ # @see Psych::TreeBuilder#start_mapping
234
+ # @see Styler#style
235
+ # @see Styler#style_mapping
236
+ # @see SuperSniffer#start_mapping
237
+ #
238
+ # @return [Psych::Nodes::Mapping] the mapping node created
239
+ def start_mapping(*)
240
+ node = super
241
+
242
+ @stylers.each do |styler|
243
+ styler.style(sniffer,node)
244
+ styler.style_mapping(sniffer,node)
245
+ end
246
+
247
+ @sniffer.start_mapping(node)
248
+
249
+ return node
250
+ end
251
+
252
+ # Calls super, styler(s), and sniffer.
253
+ #
254
+ # @see Psych::TreeBuilder#start_sequence
255
+ # @see Styler#style
256
+ # @see Styler#style_sequence
257
+ # @see SuperSniffer#start_sequence
258
+ #
259
+ # @return [Psych::Nodes::Sequence] the sequence node created
260
+ def start_sequence(*)
261
+ node = super
262
+
263
+ @stylers.each do |styler|
264
+ styler.style(sniffer,node)
265
+ styler.style_sequence(sniffer,node)
266
+ end
267
+
268
+ @sniffer.start_sequence(node)
269
+
270
+ return node
271
+ end
272
+
273
+ # Calls super, styler(s), and sniffer.
274
+ #
275
+ # @see Psych::TreeBuilder#start_stream
276
+ # @see Styler#style
277
+ # @see Styler#style_stream
278
+ # @see SuperSniffer#start_stream
279
+ #
280
+ # @return [Psych::Nodes::Stream] the stream node created
281
+ def start_stream(*)
282
+ node = super
283
+
284
+ @stylers.each do |styler|
285
+ styler.style(sniffer,node)
286
+ styler.style_stream(sniffer,node)
287
+ end
288
+
289
+ @sniffer.start_stream(node)
290
+
291
+ return node
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ #--
5
+ # This file is part of Psychgus.
6
+ # Copyright (c) 2019 Jonathan Bradley Whited (@esotericpig)
7
+ #
8
+ # Psychgus is free software: you can redistribute it and/or modify
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/>.
20
+ #++
21
+
22
+
23
+ require 'psychgus/super_sniffer'
24
+
25
+ module Psychgus
26
+ module Styler
27
+ ###
28
+ # An empty {Styler} as a class.
29
+ #
30
+ # @author Jonathan Bradley Whited (@esotericpig)
31
+ # @since 1.0.0
32
+ ###
33
+ class Empty
34
+ include Styler
35
+ end
36
+ end
37
+
38
+ ###
39
+ # Mix in (include) this module to make a class/module/etc. a styler for YAML.
40
+ #
41
+ # Although it's unnecessary (because of Duck Typing), it's the recommended practice in case a new method is
42
+ # added in the future, and also so you don't have to define methods that you don't use.
43
+ #
44
+ # You can either use this as is (see example) or inside of a class (see {Blueberry}).
45
+ #
46
+ # @example
47
+ # class MyStyler
48
+ # include Psychgus::Styler
49
+ #
50
+ # def style_sequence(sniffer,node)
51
+ # node.style = Psychgus::SEQUENCE_FLOW if sniffer.level == 3
52
+ # end
53
+ # end
54
+ #
55
+ # hash = {'Coffee'=>{
56
+ # 'Roast'=>['Light','Medium','Dark','Extra Dark'],
57
+ # 'Style'=>['Cappuccino','Espresso','Latte','Mocha']
58
+ # }}
59
+ # puts hash.to_yaml(stylers: MyStyler.new())
60
+ #
61
+ # # Output:
62
+ # # ---
63
+ # # Coffee:
64
+ # # Roast: [Light, Medium, Dark, Extra Dark]
65
+ # # Style: [Cappuccino, Espresso, Latte, Mocha]
66
+ #
67
+ # @author Jonathan Bradley Whited (@esotericpig)
68
+ # @since 1.0.0
69
+ #
70
+ # @see Psychgus
71
+ # @see Ext::ObjectExt#to_yaml
72
+ # @see Blueberry
73
+ # @see StyledTreeBuilder#initialize
74
+ # @see StyledDocumentStream#initialize
75
+ # @see Ext::YAMLTreeExt#accept
76
+ ###
77
+ module Styler
78
+ EMPTY = Empty.new().freeze()
79
+
80
+ # Style a node of any type.
81
+ #
82
+ # You can use {Ext::NodeExt#node_of?} to determine its type:
83
+ # puts node.value if node.node_of?(:scalar)
84
+ #
85
+ # @param sniffer [SuperSniffer] passed in from {StyledTreeBuilder}
86
+ # @param node [Psych::Nodes::Node] passed in from {StyledTreeBuilder}
87
+ #
88
+ # @see Ext::NodeExt#node_of?
89
+ def style(sniffer,node) end
90
+
91
+ # Style a node guaranteed to be of type Psych::Nodes::Alias, to avoid if statements.
92
+ #
93
+ # @param sniffer [SuperSniffer] passed in from {StyledTreeBuilder}
94
+ # @param node [Psych::Nodes::Alias] of type Alias passed in from {StyledTreeBuilder}
95
+ def style_alias(sniffer,node) end
96
+
97
+ # Style a node guaranteed to be of type Psych::Nodes::Document, to avoid if statements.
98
+ #
99
+ # @param sniffer [SuperSniffer] passed in from {StyledTreeBuilder}
100
+ # @param node [Psych::Nodes::Document] of type Document passed in from {StyledTreeBuilder}
101
+ def style_document(sniffer,node) end
102
+
103
+ # Style a node guaranteed to be of type Psych::Nodes::Mapping, to avoid if statements.
104
+ #
105
+ # @param sniffer [SuperSniffer] passed in from {StyledTreeBuilder}
106
+ # @param node [Psych::Nodes::Mapping] of type Mapping passed in from {StyledTreeBuilder}
107
+ def style_mapping(sniffer,node) end
108
+
109
+ # Style a node guaranteed to be of type Psych::Nodes::Scalar, to avoid if statements.
110
+ #
111
+ # @param sniffer [SuperSniffer] passed in from {StyledTreeBuilder}
112
+ # @param node [Psych::Nodes::Scalar] of type Scalar passed in from {StyledTreeBuilder}
113
+ def style_scalar(sniffer,node) end
114
+
115
+ # Style a node guaranteed to be of type Psych::Nodes::Sequence, to avoid if statements.
116
+ #
117
+ # @param sniffer [SuperSniffer] passed in from {StyledTreeBuilder}
118
+ # @param node [Psych::Nodes::Sequence] of type Sequence passed in from {StyledTreeBuilder}
119
+ def style_sequence(sniffer,node) end
120
+
121
+ # Style a node guaranteed to be of type Psych::Nodes::Stream, to avoid if statements.
122
+ #
123
+ # @param sniffer [SuperSniffer] passed in from {StyledTreeBuilder}
124
+ # @param node [Psych::Nodes::Stream] of type Stream passed in from {StyledTreeBuilder}
125
+ def style_stream(sniffer,node) end
126
+ end
127
+ end
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ #--
5
+ # This file is part of Psychgus.
6
+ # Copyright (c) 2019 Jonathan Bradley Whited (@esotericpig)
7
+ #
8
+ # Psychgus is free software: you can redistribute it and/or modify
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/>.
20
+ #++
21
+
22
+
23
+ module Psychgus
24
+ class SuperSniffer
25
+ ###
26
+ # A container for the parent of a Psych::Nodes::Node.
27
+ #
28
+ # A parent is a Mapping, Sequence, or a Key (Scalar) of a Mapping.
29
+ #
30
+ # You can use the getters in this class in {Styler} to filter what to change.
31
+ #
32
+ # If a Node method has not been exposed, you can use {#node}:
33
+ # if parent.node_of?(:scalar)
34
+ # parent.value = 'FUBAR'
35
+ # parent.node.value = 'FUBAR' # Same as above
36
+ #
37
+ # parent.fubar = true # NoMethodError
38
+ # parent.node.fubar = true # Use some new Psych::Nodes::Node method not in this version
39
+ # # of Psychgus or that is not exposed by Parent
40
+ # end
41
+ #
42
+ # @author Jonathan Bradley Whited (@esotericpig)
43
+ # @since 1.0.0
44
+ #
45
+ # @see SuperSniffer
46
+ # @see SuperSniffer#start_parent SuperSniffer#start_parent
47
+ # @see SuperSniffer#end_parent SuperSniffer#end_parent
48
+ # @see Styler
49
+ ###
50
+ class Parent
51
+ # Calling the getter is fine; calling the setter is *not* and could cause weird results.
52
+ #
53
+ # @return [Integer] the next child's position
54
+ attr_accessor :child_position
55
+
56
+ # Calling the getter is fine; calling the setter is *not* and could cause weird results.
57
+ #
58
+ # @return [nil,:key,:value] the next child's Mapping type, if {#node} is a Mapping
59
+ attr_accessor :child_type
60
+
61
+ # @return [:noface,Symbol,String] a tag (class name, value) for debugging; also used in {#to_s}
62
+ attr_reader :debug_tag
63
+
64
+ attr_reader :level # @return [Integer] the level of this Node in the YAML
65
+ attr_reader :node # @return [Psych::Nodes::Node] the Node of this parent
66
+ attr_reader :position # @return [Integer] the position of this Node in the YAML
67
+
68
+ # Initialize this class with parent data.
69
+ #
70
+ # @param sniffer [SuperSniffer] the sniffer that contains this parent (not stored; used for data)
71
+ # @param node [Psych::Nodes::Node] the node of this parent
72
+ # @param debug_tag [:noface,Symbol,String] the tag (class name, value) used for debugging and in {#to_s}
73
+ # @param child_type [nil,:key,:value] the next child's Mapping type, if +node+ is a Mapping
74
+ def initialize(sniffer,node,debug_tag: nil,child_type: nil)
75
+ @child_position = 1
76
+ @child_type = child_type
77
+ @debug_tag = debug_tag
78
+ @level = sniffer.level
79
+ @node = node
80
+ @position = sniffer.position
81
+ end
82
+
83
+ # @see Psych::Nodes::Alias#anchor=
84
+ # @see Psych::Nodes::Mapping#anchor=
85
+ # @see Psych::Nodes::Scalar#anchor=
86
+ # @see Psych::Nodes::Sequence#anchor=
87
+ def anchor=(anchor)
88
+ node.anchor = anchor
89
+ end
90
+
91
+ # @see Psych::Nodes::Scalar#plain=
92
+ def plain=(plain)
93
+ node.plain = plain
94
+ end
95
+
96
+ # @see Psych::Nodes::Scalar#quoted=
97
+ def quoted=(quoted)
98
+ node.quoted = quoted
99
+ end
100
+
101
+ # @see Psych::Nodes::Mapping#style=
102
+ # @see Psych::Nodes::Scalar#style=
103
+ # @see Psych::Nodes::Sequence#style=
104
+ def style=(style)
105
+ node.style = style
106
+ end
107
+
108
+ # @see Psych::Nodes::Node#tag=
109
+ def tag=(tag)
110
+ node.tag = tag
111
+ end
112
+
113
+ # @see Psych::Nodes::Scalar#value=
114
+ def value=(value)
115
+ node.value = value
116
+ end
117
+
118
+ # @see Psych::Nodes::Alias#anchor
119
+ # @see Psych::Nodes::Mapping#anchor
120
+ # @see Psych::Nodes::Scalar#anchor
121
+ # @see Psych::Nodes::Sequence#anchor
122
+ def anchor()
123
+ return node.anchor
124
+ end
125
+
126
+ # @see Psych::Nodes::Stream#encoding
127
+ def encoding()
128
+ return node.encoding
129
+ end
130
+
131
+ # @see Psych::Nodes::Node#end_column
132
+ def end_column()
133
+ return node.end_column
134
+ end
135
+
136
+ # @see Psych::Nodes::Node#end_line
137
+ def end_line()
138
+ return node.end_line
139
+ end
140
+
141
+ # @see Psych::Nodes::Document#implicit
142
+ # @see Psych::Nodes::Mapping#implicit
143
+ # @see Psych::Nodes::Sequence#implicit
144
+ def implicit?()
145
+ return node.implicit
146
+ end
147
+
148
+ # @see Psych::Nodes::Document#implicit_end
149
+ def implicit_end?()
150
+ return node.implicit_end
151
+ end
152
+
153
+ # (see Ext::NodeExt#node_of?)
154
+ def node_of?(*names)
155
+ return node.node_of?(*names)
156
+ end
157
+
158
+ # @see Psych::Nodes::Scalar#plain
159
+ def plain?()
160
+ return node.plain
161
+ end
162
+
163
+ # @see Psych::Nodes::Scalar#quoted
164
+ def quoted?()
165
+ return node.quoted
166
+ end
167
+
168
+ # @see Psych::Nodes::Node#start_column
169
+ def start_column()
170
+ return node.start_column
171
+ end
172
+
173
+ # @see Psych::Nodes::Node#start_line
174
+ def start_line()
175
+ return node.start_line
176
+ end
177
+
178
+ # @see Psych::Nodes::Mapping#style
179
+ # @see Psych::Nodes::Scalar#style
180
+ # @see Psych::Nodes::Sequence#style
181
+ def style()
182
+ return node.style
183
+ end
184
+
185
+ # @see Psych::Nodes::Node#tag
186
+ def tag()
187
+ return node.tag
188
+ end
189
+
190
+ # @see Psych::Nodes::Document#tag_directives
191
+ def tag_directives()
192
+ return node.tag_directives
193
+ end
194
+
195
+ # @see Psych::Nodes::Scalar#value
196
+ def value()
197
+ return node.value
198
+ end
199
+
200
+ # @see Psych::Nodes::Document#version
201
+ def version()
202
+ return node.version
203
+ end
204
+
205
+ # @note If this method is modified, then tests will fail
206
+ #
207
+ # @return [String] a String representation of this class for debugging and testing
208
+ def to_s()
209
+ return "<#{@debug_tag}:(#{@level}:#{@position}):#{@child_type}:(:#{@child_position})>"
210
+ end
211
+
212
+ alias_method :implicit,:implicit?
213
+ alias_method :implicit_end,:implicit_end?
214
+ alias_method :plain,:plain?
215
+ alias_method :quoted,:quoted?
216
+ end
217
+ end
218
+ end