psychgus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,158 @@
1
+ # encoding: UTF-8
2
+
3
+ #--
4
+ # This file is part of Psychgus.
5
+ # Copyright (c) 2019 Jonathan Bradley Whited (@esotericpig)
6
+ #
7
+ # Psychgus is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # Psychgus is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with Psychgus. If not, see <http://www.gnu.org/licenses/>.
19
+ #++
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'yard'
25
+
26
+ require 'psychgus/version'
27
+
28
+ require 'rake/clean'
29
+ require 'rake/testtask'
30
+
31
+ task default: [:test]
32
+
33
+ CLEAN.exclude('.git/','stock/')
34
+ CLOBBER.include('doc/')
35
+
36
+ module PsychgusRake
37
+ # Remove if exists
38
+ def self.rm_exist(filename,output=true)
39
+ if File.exist?(filename)
40
+ puts "Delete [#{filename}]" if output
41
+ File.delete(filename)
42
+ end
43
+ end
44
+ end
45
+
46
+ # Execute "rake ghp_doc" for a dry run
47
+ # Execute "rake ghp_doc[true]" for actually deploying
48
+ desc %q(Rsync "doc/" to my GitHub Page's repo; not useful for others)
49
+ task :ghp_doc,[:deploy] do |task,args|
50
+ dry_run = args.deploy ? '' : '--dry-run'
51
+ rsync_cmd = "rsync -ahv --delete-after --progress #{dry_run} 'doc/' '../esotericpig.github.io/docs/psychgus/yardoc/'"
52
+
53
+ sh rsync_cmd
54
+
55
+ if dry_run
56
+ puts
57
+ puts 'Execute "rake ghp_doc[true]" for actually deploying (non-dry-run)'
58
+ end
59
+ end
60
+
61
+ Rake::TestTask.new() do |task|
62
+ task.libs = ['lib','test']
63
+ task.pattern = 'test/**/*_test.rb'
64
+ task.description += " ('#{task.pattern}')"
65
+ #task.options = '--verbose' # Execute "rake test TESTOPT=-v" instead
66
+ task.verbose = true
67
+ task.warning = true
68
+ end
69
+
70
+ desc 'Run all tests (including writing to temp files, etc.)'
71
+ task :test_all do |task|
72
+ ENV['PSYCHGUS_TEST'] = 'all'
73
+
74
+ test_task = Rake::Task[:test]
75
+ test_task.reenable()
76
+ test_task.invoke()
77
+ end
78
+
79
+ # Execute "rake clobber yard" for pristine docs
80
+ YARD::Rake::YardocTask.new() do |task|
81
+ task.files = ['lib/**/*.rb']
82
+
83
+ task.options += ['--files','LICENSE.txt']
84
+ task.options += ['--readme','README.md']
85
+
86
+ task.options << '--protected' # Show protected methods
87
+ task.options += ['--template-path','yard/templates/']
88
+ task.options += ['--title',"Psychgus v#{Psychgus::VERSION} Doc"]
89
+ end
90
+
91
+ desc 'Fix (find & replace) text in the YARD files for GitHub differences'
92
+ task :yard_fix,[:dev] do |task,args|
93
+ # Delete this file as it's never used (index.html is an exact copy)
94
+ PsychgusRake.rm_exist('doc/file.README.html')
95
+
96
+ ['doc/index.html'].each do |filename|
97
+ puts "File [#{filename}]:"
98
+
99
+ lines = []
100
+ write = false
101
+
102
+ File.open(filename,'r') do |file|
103
+ file.each_line do |line|
104
+ out = false
105
+
106
+ # CSS
107
+ if line =~ /^\s*\<\/head\>\s*$/i
108
+ line = '<link href="'
109
+ line << (args.dev ? '../../esotericpig.github.io/' : '../../../')
110
+ line << 'css/prism.css" rel="stylesheet" /> </head>'
111
+
112
+ out = true
113
+ end
114
+
115
+ # JS
116
+ if line =~ /^\s*\<\/body\>\s*$/i
117
+ line = '<script src="'
118
+ line << (args.dev ? '../../esotericpig.github.io/' : '../../../')
119
+ line << 'js/prism.js"></script> </body>'
120
+
121
+ out = true
122
+ end
123
+
124
+ # Contents relative links
125
+ tag = 'href="#'
126
+ if !(i = line.index(Regexp.new(Regexp.quote(tag) + '[a-z]'))).nil?()
127
+ i += tag.length
128
+ j = line.index('"',i)
129
+
130
+ href = line[i...j].split('-').map(&:capitalize).join('_')
131
+ line = "#{line[0...i]}#{href}#{line[j..-1]}"
132
+
133
+ out = true
134
+ end
135
+
136
+ out ||= !line.gsub!('href="LICENSE.txt"','href="file.LICENSE.html"').nil?()
137
+ out ||= !line.gsub!('code class="Ruby"','code class="language-ruby"').nil?()
138
+
139
+ if out
140
+ puts " #{line}"
141
+ write = true
142
+ end
143
+
144
+ lines << line
145
+ end
146
+ end
147
+
148
+ if write
149
+ File.open(filename,'w') do |file|
150
+ file.puts lines
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ desc 'Generate pristine YARDoc'
157
+ task :yard_fresh => [:clobber,:yard,:yard_fix] do |task|
158
+ end
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ #--
5
+ # This file is part of Psychgus.
6
+ # Copyright (c) 2017-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
+ ###
25
+ # This is the OOP way to style your classes/modules/etc.
26
+ #
27
+ # Even though it's unnecessary to mix in (include) this module, it's recommended because new methods may be
28
+ # added in the future, so this pseudo-guarantees your class won't break in a new version.
29
+ #
30
+ # A complete example:
31
+ # require 'psychgus'
32
+ #
33
+ # class MyClass
34
+ # include Psychgus::Blueberry
35
+ #
36
+ # attr_reader :my_hash
37
+ #
38
+ # def initialize()
39
+ # @my_hash = {:key1=>'val1',:key2=>'val2'}
40
+ # end
41
+ #
42
+ # def psychgus_stylers(sniffer)
43
+ # return MyClassStyler.new(sniffer)
44
+ # end
45
+ # end
46
+ #
47
+ # class MyClassStyler
48
+ # include Psychgus::Styler
49
+ #
50
+ # def initialize(sniffer)
51
+ # @level = sniffer.level
52
+ # end
53
+ #
54
+ # def style_mapping(sniffer,node)
55
+ # node.style = Psychgus::MAPPING_FLOW
56
+ #
57
+ # relative_level = sniffer.level - @level
58
+ # end
59
+ # end
60
+ #
61
+ # my_class = MyClass.new()
62
+ # puts my_class.to_yaml()
63
+ #
64
+ # Alternatively, MyClass could have been the {Blueberry} and the {Styler}, without the need for
65
+ # MyClassStyler:
66
+ # class MyClass
67
+ # include Psychgus::Blueberry
68
+ # include Psychgus::Styler
69
+ #
70
+ # # ...
71
+ #
72
+ # def psychgus_stylers(sniffer)
73
+ # @level = sniffer.level # This will be included in the output of to_yaml()
74
+ #
75
+ # return self
76
+ # end
77
+ #
78
+ # def style_mapping(sniffer,node)
79
+ # # ...
80
+ # end
81
+ # end
82
+ #
83
+ # However, it's best to put the styling logic inside of a separate class (or inner class) away from the main
84
+ # logic. This also prevents extra helper vars, like @level, from showing up in the output.
85
+ #
86
+ # After your class and its children have been processed, the styler(s) will be removed from the logic for
87
+ # the next sibling object(s). Therefore, you can safely do class-specific checks on level, etc. without it
88
+ # affecting the sibling object(s). See {Ext::YAMLTreeExt} and {Ext::YAMLTreeExt#accept} for details.
89
+ #
90
+ # "The Blueberry" is the name of Gus's car from the TV show Psych.
91
+ #
92
+ # @author Jonathan Bradley Whited (@esotericpig)
93
+ # @since 1.0.0
94
+ #
95
+ # @see Ext::YAMLTreeExt
96
+ # @see Ext::YAMLTreeExt#accept
97
+ ###
98
+ module Blueberry
99
+ # Duck Type this method to return the {Styler}(s) for your class/module/etc.
100
+ #
101
+ # @param sniffer [SuperSniffer] passed in from {StyledTreeBuilder}; use this for storing the level,
102
+ # position, etc. for styling your instance variables later relative to your
103
+ # class/module/etc.
104
+ #
105
+ # @return [Styler,Array<Styler>,nil] {Styler}(s) for this class/module/etc.
106
+ def psychgus_stylers(sniffer)
107
+ return nil
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,77 @@
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
+ module Ext
25
+ ###
26
+ # Core extensions to Object.
27
+ #
28
+ # @author Jonathan Bradley Whited (@esotericpig)
29
+ # @since 1.0.0
30
+ #
31
+ # @see https://github.com/ruby/psych/blob/master/lib/psych/core_ext.rb
32
+ ###
33
+ module ObjectExt
34
+ # Convert an Object to YAML.
35
+ #
36
+ # +options+ can also be a Hash, so can be a drop-in-replacement for Psych.
37
+ #
38
+ # @example
39
+ # class MyStyler
40
+ # include Psychgus::Styler
41
+ #
42
+ # def style_sequence(sniffer,node)
43
+ # node.style = Psychgus::SEQUENCE_FLOW
44
+ # end
45
+ # end
46
+ #
47
+ # my_obj = {
48
+ # :Foods => {
49
+ # :Fruits => %w(Apple Banana Blueberry Pear),
50
+ # :Veggies => %w(Bean Carrot Celery Pea)
51
+ # }}
52
+ #
53
+ # puts my_obj.to_yaml(indentation: 5,stylers: MyStyler.new)
54
+ #
55
+ # # Or, pass in a Hash:
56
+ # #puts my_obj.to_yaml({:indentation=>5,:stylers=>MyStyler.new})
57
+ #
58
+ # # Output:
59
+ # # ---
60
+ # # :Foods:
61
+ # # :Fruits: [Apple, Banana, Blueberry, Pear]
62
+ # # :Veggies: [Bean, Carrot, Celery, Pea]
63
+ #
64
+ # @param options [Hash] the options (or keyword args) to pass to {Psychgus.dump}
65
+ #
66
+ # @return [String] the YAML generated from this Object
67
+ #
68
+ # @see Psychgus.dump
69
+ def to_yaml(**options)
70
+ # Do not use Psych.dump() if no Stylers, because a class might be a Blueberry
71
+ return Psychgus.dump(self,**options)
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ Object.prepend(Psychgus::Ext::ObjectExt)
@@ -0,0 +1,68 @@
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
+ module Psychgus
26
+ module Ext
27
+ ###
28
+ # Extensions to Psych::Nodes::Node.
29
+ #
30
+ # @author Jonathan Bradley Whited (@esotericpig)
31
+ # @since 1.0.0
32
+ ###
33
+ module NodeExt
34
+ # Check if this Node is of a certain type (Alias, Mapping, Scalar, Sequence, etc.).
35
+ #
36
+ # New versions of Psych have alias?(), mapping?(), etc., so this is for old versions.
37
+ #
38
+ # This is equivalent to the following (with less typing):
39
+ # node.is_a?(Psych::Nodes::Alias)
40
+ # node.is_a?(Psych::Nodes::Mapping)
41
+ # node.is_a?(Psych::Nodes::Scalar)
42
+ # node.is_a?(Psych::Nodes::Sequence)
43
+ #
44
+ # @example
45
+ # node.node_of?(:alias)
46
+ # node.node_of?(:mapping)
47
+ # node.node_of?(:scalar)
48
+ # node.node_of?(:sequence)
49
+ # node.node_of?(:alias,:mapping,:scalar,:sequence) # OR
50
+ # node.node_of?(:doc,:map,:seq) # OR
51
+ #
52
+ # @param names [Symbol,String] the type(s) to check using OR
53
+ #
54
+ # @return [true,false] true if this Node is one of the +names+ type, else false
55
+ #
56
+ # @see Psychgus.node_class
57
+ def node_of?(*names)
58
+ names.each do |name|
59
+ return true if is_a?(Psychgus.node_class(name))
60
+ end
61
+
62
+ return false
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ Psych::Nodes::Node.prepend(Psychgus::Ext::NodeExt)
@@ -0,0 +1,101 @@
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/styled_tree_builder'
26
+
27
+ module Psychgus
28
+ module Ext
29
+ ###
30
+ # Extensions to Psych::Visitors::YAMLTree::Registrar.
31
+ #
32
+ # @author Jonathan Bradley Whited (@esotericpig)
33
+ # @since 1.0.0
34
+ ###
35
+ module RegistrarExt
36
+ # Remove +target+ from this Registrar to prevent it becoming an alias.
37
+ #
38
+ # @param target [Object] the Object to remove from this Registrar
39
+ def remove_alias(target)
40
+ @obj_to_node.delete(target.object_id)
41
+ end
42
+ end
43
+
44
+ ###
45
+ # Extensions to Psych::Visitors::YAMLTree.
46
+ #
47
+ # @author Jonathan Bradley Whited (@esotericpig)
48
+ # @since 1.0.0
49
+ ###
50
+ module YAMLTreeExt
51
+ # Accepts a new Object to convert to YAML.
52
+ #
53
+ # This is roughly the same place where Psych checks if +target+ responds to :encode_with.
54
+ #
55
+ # This will check if @emitter is a {StyledTreeBuilder} and if +target+ is a {Blueberry}.
56
+ # 1. If the above is true, get the {Styler}(s) and add them to @emitter.
57
+ # 2. Call super.
58
+ # 3. If the above is true, remove the {Styler}(s) from @emitter.
59
+ # 4. Return the result of super.
60
+ #
61
+ # @param target [Object] the Object to pass to super
62
+ #
63
+ # @return the result of super
64
+ #
65
+ # @see Psych::Visitors::YAMLTree
66
+ # @see Blueberry
67
+ # @see Styler
68
+ # @see StyledTreeBuilder
69
+ def accept(target)
70
+ styler_count = 0
71
+
72
+ if @emitter.is_a?(StyledTreeBuilder)
73
+ # Blueberry?
74
+ if target.respond_to?(:psychgus_stylers)
75
+ stylers = target.psychgus_stylers(@emitter.sniffer)
76
+ stylers_old_len = @emitter.stylers.length
77
+
78
+ @emitter.add_styler(*stylers)
79
+
80
+ styler_count = @emitter.stylers.length - stylers_old_len
81
+ end
82
+
83
+ # Dereference aliases?
84
+ if @emitter.deref_aliases?()
85
+ @st.remove_alias(target) if target.respond_to?(:object_id) && @st.key?(target)
86
+ end
87
+ end
88
+
89
+ result = super(target)
90
+
91
+ # Check styler_count because @emitter may not be a StyledTreeBuilder and target may not be a Blueberry
92
+ @emitter.pop_styler(styler_count) if styler_count > 0
93
+
94
+ return result
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ Psych::Visitors::YAMLTree.prepend(Psychgus::Ext::YAMLTreeExt)
101
+ Psych::Visitors::YAMLTree::Registrar.prepend(Psychgus::Ext::RegistrarExt)
@@ -0,0 +1,32 @@
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
+ ###
25
+ # Contains all of the extensions (monkey patching) to core/Psych classes/modules.
26
+ #
27
+ # @author Jonathan Bradley Whited (@esotericpig)
28
+ # @since 1.0.0
29
+ ###
30
+ module Ext
31
+ end
32
+ end
@@ -0,0 +1,66 @@
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/styled_tree_builder'
26
+
27
+ module Psychgus
28
+ ###
29
+ # Use this wherever Psych::Handlers::DocumentStream would have been used, to enable styling.
30
+ #
31
+ # @author Jonathan Bradley Whited (@esotericpig)
32
+ # @since 1.0.0
33
+ #
34
+ # @see Psychgus.parse_stream Psychgus.parse_stream
35
+ # @see Psych::Handlers::DocumentStream
36
+ ###
37
+ class StyledDocumentStream < StyledTreeBuilder
38
+ # Initialize this class with {Styler}(s) and a block.
39
+ #
40
+ # @param stylers [Styler] {Styler}(s) to use for styling this DocumentStream
41
+ # @param deref_aliases [true,false] whether to dereference aliases; output the actual value
42
+ # instead of the alias
43
+ # @param block [Proc] a block to call in {#end_document} to denote a new YAML document
44
+ def initialize(*stylers,deref_aliases: false,**options,&block)
45
+ super(*stylers,deref_aliases: deref_aliases,**options)
46
+
47
+ @block = block
48
+ end
49
+
50
+ # This mimics the behavior of Psych::Handlers::DocumentStream#end_document.
51
+ #
52
+ # @see Psych::Handlers::DocumentStream#end_document
53
+ def end_document(implicit_end=!streaming?())
54
+ @last.implicit_end = implicit_end
55
+ @block.call(pop)
56
+ end
57
+
58
+ # This mimics the behavior of Psych::Handlers::DocumentStream#start_document.
59
+ #
60
+ # @see Psych::Handlers::DocumentStream#start_document
61
+ def start_document(version,tag_directives,implicit)
62
+ node = Psych::Nodes::Document.new(version,tag_directives,implicit)
63
+ push(node)
64
+ end
65
+ end
66
+ end