psychgus 1.0.0

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.
data/psychgus.gemspec ADDED
@@ -0,0 +1,121 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
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
+ lib = File.expand_path('../lib',__FILE__)
24
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
25
+
26
+ require 'psychgus/version'
27
+
28
+ Gem::Specification.new do |spec|
29
+ spec.name = 'psychgus'
30
+ spec.version = Psychgus::VERSION
31
+ spec.authors = ['Jonathan Bradley Whited (@esotericpig)']
32
+ spec.email = ['bradley@esotericpig.com']
33
+ spec.licenses = ['LGPL-3.0-or-later']
34
+
35
+ spec.metadata = {
36
+ 'bug_tracker_uri' => 'https://github.com/esotericpig/psychgus/issues',
37
+ 'documentation_uri' => 'https://esotericpig.github.io/docs/psychgus/yardoc/index.html',
38
+ 'homepage_uri' => 'https://github.com/esotericpig/psychgus',
39
+ 'source_code_uri' => 'https://github.com/esotericpig/psychgus'
40
+ }
41
+
42
+ spec.homepage = 'https://github.com/esotericpig/psychgus'
43
+ spec.summary = %q(Easily style YAML files using Psych, like Sequence/Mapping Flow style.)
44
+ spec.description = <<-EOS
45
+ Easily style YAML files using Psych, like Sequence/Mapping Flow style.
46
+
47
+ Simple example:
48
+ class CoffeeStyler
49
+ include Psychgus::Styler
50
+
51
+ def style_sequence(sniffer,node)
52
+ node.style = Psychgus::SEQUENCE_FLOW
53
+ end
54
+ end
55
+
56
+ coffee = {
57
+ 'Roast'=>['Light', 'Medium', 'Dark', 'Extra Dark'],
58
+ 'Style'=>['Cappuccino', 'Espresso', 'Latte', 'Mocha']}
59
+
60
+ puts coffee.to_yaml(stylers: CoffeeStyler.new)
61
+
62
+ # Output:
63
+ # ---
64
+ # Roast: [Light, Medium, Dark, Extra Dark]
65
+ # Style: [Cappuccino, Espresso, Latte, Mocha]
66
+
67
+ Class example:
68
+ class Coffee
69
+ include Psychgus::Blueberry
70
+
71
+ def initialize
72
+ @roast = ['Light', 'Medium', 'Dark', 'Extra Dark']
73
+ @style = ['Cappuccino', 'Espresso', 'Latte', 'Mocha']
74
+ end
75
+
76
+ def psychgus_stylers(sniffer)
77
+ CoffeeStyler.new
78
+ end
79
+ end
80
+
81
+ puts Coffee.new.to_yaml
82
+
83
+ # Output:
84
+ # --- !ruby/object:Coffee
85
+ # roast: [Light, Medium, Dark, Extra Dark]
86
+ # style: [Cappuccino, Espresso, Latte, Mocha]
87
+
88
+ The produced YAML without Psychgus styling (i.e., without CoffeeStyler):
89
+ # ---
90
+ # Roast:
91
+ # - Light
92
+ # - Medium
93
+ # - Dark
94
+ # - Extra Dark
95
+ # Style:
96
+ # - Cappuccino
97
+ # - Espresso
98
+ # - Latte
99
+ # - Mocha
100
+ EOS
101
+
102
+ spec.files = Dir.glob("{lib,test,yard}/**/*") + %w(
103
+ Gemfile
104
+ LICENSE.txt
105
+ psychgus.gemspec
106
+ Rakefile
107
+ README.md
108
+ )
109
+ spec.require_paths = ['lib']
110
+
111
+ spec.required_ruby_version = '>= 2.1.10'
112
+
113
+ spec.add_runtime_dependency 'psych','>= 2.0.5'
114
+
115
+ spec.add_development_dependency 'bundler' ,'~> 1.16'
116
+ spec.add_development_dependency 'minitest' ,'~> 5.11' # For testing
117
+ spec.add_development_dependency 'rake' ,'~> 12.3'
118
+ spec.add_development_dependency 'rdoc' ,'~> 6.1' # For RDoc for YARD (*.rb)
119
+ spec.add_development_dependency 'redcarpet','~> 3.4' # For Markdown for YARD (*.md)
120
+ spec.add_development_dependency 'yard' ,'~> 0.9' # For documentation
121
+ end
@@ -0,0 +1,141 @@
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_tester'
24
+
25
+ class Burger
26
+ include Psychgus::Blueberry
27
+
28
+ attr_accessor :bun
29
+ attr_accessor :cheese
30
+ attr_accessor :sauce
31
+
32
+ def initialize(sauce,cheese,bun)
33
+ @bun = bun
34
+ @cheese = cheese
35
+ @sauce = sauce
36
+ end
37
+
38
+ def encode_with(coder)
39
+ coder['Bun'] = @bun
40
+ coder['Cheese'] = @cheese
41
+ coder['Sauce'] = @sauce
42
+ end
43
+
44
+ def psychgus_stylers(sniffer)
45
+ return BurgerStyler.new(sniffer)
46
+ end
47
+ end
48
+
49
+ class Burgers
50
+ attr_accessor :burgers
51
+ attr_accessor :toppings
52
+
53
+ def initialize()
54
+ @burgers = {
55
+ 'Classic' => Burger.new(['Ketchup','Mustard'],'American','Sesame Seed'),
56
+ 'BBQ' => Burger.new('Honey BBQ','Cheddar','Kaiser'),
57
+ 'Fancy' => Burger.new('Spicy Wasabi','Smoked Gouda','Hawaiian')
58
+ }
59
+
60
+ @toppings = [
61
+ 'Mushrooms',
62
+ %w(Lettuce Onions Pickles Tomatoes),
63
+ [%w(Ketchup Mustard),%w(Salt Pepper)]
64
+ ]
65
+ end
66
+
67
+ def encode_with(coder)
68
+ coder['Burgers'] = @burgers
69
+ coder['Toppings'] = @toppings
70
+ end
71
+ end
72
+
73
+ class BurgerStyler
74
+ include Psychgus::Styler
75
+
76
+ def initialize(sniffer)
77
+ @level = sniffer.level
78
+ @position = sniffer.position
79
+ end
80
+
81
+ def style(sniffer,node)
82
+ # Remove ugly and unsafe "!ruby/object:Burger"
83
+ node.tag = nil if node.respond_to?(:tag)
84
+ end
85
+
86
+ def style_mapping(sniffer,node)
87
+ parent = sniffer.parent
88
+
89
+ if !parent.nil?()
90
+ # BBQ
91
+ node.style = Psychgus::MAPPING_FLOW if parent.respond_to?(:value) && parent.value.casecmp('BBQ') == 0
92
+ end
93
+ end
94
+
95
+ def style_scalar(sniffer,node)
96
+ # Only for Burgers
97
+ node.style = Psychgus::SCALAR_SINGLE_QUOTED
98
+ end
99
+
100
+ def style_sequence(sniffer,node)
101
+ relative_level = (sniffer.level - @level) + 1
102
+
103
+ # [Ketchup, Mustard]
104
+ node.style = Psychgus::SEQUENCE_FLOW if relative_level == 3
105
+ end
106
+ end
107
+
108
+ class BlueberryTest < PsychgusTester
109
+ def setup()
110
+ @burgers = Burgers.new()
111
+ end
112
+
113
+ def test_blueberry()
114
+ expected = <<-EOY
115
+ |--- !ruby/object:Burgers
116
+ |Burgers:
117
+ | Classic:
118
+ | 'Bun': 'Sesame Seed'
119
+ | 'Cheese': 'American'
120
+ | 'Sauce': ['Ketchup', 'Mustard']
121
+ | BBQ: {'Bun': 'Kaiser', 'Cheese': 'Cheddar', 'Sauce': 'Honey BBQ'}
122
+ | Fancy:
123
+ | 'Bun': 'Hawaiian'
124
+ | 'Cheese': 'Smoked Gouda'
125
+ | 'Sauce': 'Spicy Wasabi'
126
+ |Toppings:
127
+ |- Mushrooms
128
+ |- - Lettuce
129
+ | - Onions
130
+ | - Pickles
131
+ | - Tomatoes
132
+ |- - - Ketchup
133
+ | - Mustard
134
+ | - - Salt
135
+ | - Pepper
136
+ EOY
137
+ expected = self.class.lstrip_pipe(expected)
138
+
139
+ assert_equal expected,@burgers.to_yaml()
140
+ end
141
+ end
@@ -0,0 +1,142 @@
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_tester'
24
+
25
+ require 'tempfile'
26
+
27
+ class FlowStyler
28
+ include Psychgus::Styler
29
+
30
+ def style_mapping(sniffer,node)
31
+ node.style = Psychgus::MAPPING_FLOW if sniffer.level >= 4
32
+ end
33
+
34
+ def style_sequence(sniffer,node)
35
+ node.style = Psychgus::SEQUENCE_FLOW if sniffer.level >= 4
36
+ end
37
+ end
38
+
39
+ class PsychgusTest < PsychgusTester
40
+ EXPECTED_BURGERS = <<-EOY
41
+ ---
42
+ Burgers:
43
+ Classic: {Sauce: [Ketchup, Mustard], Cheese: American, Bun: Sesame Seed}
44
+ BBQ: {Sauce: Honey BBQ, Cheese: Cheddar, Bun: Kaiser}
45
+ Fancy: {Sauce: Spicy Wasabi, Cheese: Smoked Gouda, Bun: Hawaiian}
46
+ Toppings:
47
+ - Mushrooms
48
+ - [Lettuce, Onions, Pickles, Tomatoes]
49
+ - [[Ketchup, Mustard], [Salt, Pepper]]
50
+ EOY
51
+
52
+ def setup()
53
+ @flow_styler = FlowStyler.new()
54
+ end
55
+
56
+ def test_alias()
57
+ expected = <<-EOY
58
+ |---
59
+ |Dolphins:
60
+ | Common: {Length: "~2.5m", Weight: "~235kg"}
61
+ | Bottlenose: {Length: "~4m", Weight: "~300kg"}
62
+ | Dusky: {Length: "~1.7m", Weight: "~78kg"}
63
+ | Orca: {Length: "~7m", Weight: "~3600kg"}
64
+ |Popular:
65
+ |- {Length: "~4m", Weight: "~300kg"}
66
+ |- {Length: "~7m", Weight: "~3600kg"}
67
+ EOY
68
+ expected = self.class.lstrip_pipe(expected)
69
+
70
+ assert_equal expected,DOLPHINS_DATA.to_yaml(deref_aliases: true,stylers: @flow_styler)
71
+ end
72
+
73
+ def test_dump()
74
+ assert_equal EXPECTED_BURGERS,Psychgus.dump(BURGERS_DATA,stylers: @flow_styler)
75
+ assert_equal EXPECTED_BURGERS,Psychgus.dump_stream(BURGERS_DATA,stylers: @flow_styler)
76
+ assert_equal EXPECTED_BURGERS,BURGERS_DATA.to_yaml(stylers: @flow_styler)
77
+ end
78
+
79
+ # Execute "rake test_all" if you update Psychgus.dump_file()/load_file()
80
+ def test_file()
81
+ if !TEST_ALL
82
+ skip(TEST_ALL_SKIP_MSG)
83
+ return # Justin Case
84
+ end
85
+
86
+ Tempfile.create(['Psychgus','.yaml']) do |file|
87
+ puts "Testing #{self.class.name} w/ temp file: #{file.path}"
88
+
89
+ Psychgus.dump_file(file,BURGERS_DATA,stylers: @flow_styler)
90
+
91
+ file.rewind()
92
+ lines = file.readlines().join()
93
+ assert_equal EXPECTED_BURGERS,lines
94
+
95
+ file.rewind()
96
+ data = Psych.load_file(file)
97
+ refute_equal false,data
98
+ end
99
+ end
100
+
101
+ def test_indent()
102
+ # Indent of 3 spaces
103
+ expected = <<-EOY
104
+ |---
105
+ |Burgers:
106
+ | Classic: {Sauce: [Ketchup, Mustard], Cheese: American, Bun: Sesame Seed}
107
+ | BBQ: {Sauce: Honey BBQ, Cheese: Cheddar, Bun: Kaiser}
108
+ | Fancy: {Sauce: Spicy Wasabi, Cheese: Smoked Gouda, Bun: Hawaiian}
109
+ |Toppings:
110
+ |- Mushrooms
111
+ |- [Lettuce, Onions, Pickles, Tomatoes]
112
+ |- [[Ketchup, Mustard], [Salt, Pepper]]
113
+ EOY
114
+ expected = self.class.lstrip_pipe(expected)
115
+
116
+ assert_equal expected,BURGERS_DATA.to_yaml(indent: 3,stylers: @flow_styler)
117
+ assert_equal expected,BURGERS_DATA.to_yaml({:indent=>3,:stylers=>@flow_styler})
118
+ assert_equal expected,BURGERS_DATA.to_yaml(indentation: 3,stylers: @flow_styler)
119
+ assert_equal expected,BURGERS_DATA.to_yaml({:indentation=>3,:stylers=>@flow_styler})
120
+ end
121
+
122
+ def test_node_consts()
123
+ assert_equal Psych::Nodes::Mapping::FLOW,Psychgus::MAPPING_FLOW
124
+ assert_equal Psych::Nodes::Scalar::FOLDED,Psychgus::SCALAR_FOLDED
125
+ assert_equal Psych::Nodes::Sequence::FLOW,Psychgus::SEQUENCE_FLOW
126
+ assert_equal Psych::Nodes::Stream::UTF8,Psychgus::STREAM_UTF8
127
+ end
128
+
129
+ def test_parse()
130
+ parser = Psychgus.parser(stylers: @flow_styler)
131
+ parser.parse(BURGERS_YAML)
132
+ yaml = "---\n" + parser.handler.root.to_yaml()
133
+ assert_equal EXPECTED_BURGERS,yaml
134
+
135
+ node = Psychgus.parse(BURGERS_YAML,stylers: @flow_styler)
136
+ refute_equal false,node
137
+
138
+ yaml = Psychgus.parse_stream(BURGERS_YAML,stylers: @flow_styler).to_yaml()
139
+ yaml = "---\n#{yaml}"
140
+ assert_equal EXPECTED_BURGERS,yaml
141
+ end
142
+ end
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ #--
6
+ # This file is part of Psychgus.
7
+ # Copyright (c) 2019 Jonathan Bradley Whited (@esotericpig)
8
+ #
9
+ # Psychgus is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU Lesser General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # Psychgus is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU Lesser General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU Lesser General Public License
20
+ # along with Psychgus. If not, see <http://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ require 'minitest/autorun'
25
+
26
+ require 'psychgus'
27
+
28
+ # Changing the YAML/data will break tests
29
+ class PsychgusTester < Minitest::Test
30
+ # If true, will...
31
+ # - Run tests that create temp file(s).
32
+ # - I don't like creating temp file(s) every time I run tests (which is a lot).
33
+ #
34
+ # To do this, execute:
35
+ # rake test_all
36
+ TEST_ALL = (ENV['PSYCHGUS_TEST'].to_s().strip().casecmp('all') == 0)
37
+ TEST_ALL_SKIP_MSG = %q(Execute "rake test_all" for this test)
38
+
39
+ BURGERS_YAML = <<-EOY.freeze()
40
+ Burgers:
41
+ Classic:
42
+ Sauce: [Ketchup,Mustard]
43
+ Cheese: American
44
+ Bun: Sesame Seed
45
+ BBQ:
46
+ Sauce: Honey BBQ
47
+ Cheese: Cheddar
48
+ Bun: Kaiser
49
+ Fancy:
50
+ Sauce: Spicy Wasabi
51
+ Cheese: Smoked Gouda
52
+ Bun: Hawaiian
53
+ Toppings:
54
+ - Mushrooms
55
+ - [Lettuce, Onions, Pickles, Tomatoes]
56
+ - [[Ketchup,Mustard], [Salt,Pepper]]
57
+ EOY
58
+ BURGERS_DATA = Psych.load(BURGERS_YAML).freeze()
59
+
60
+ COURSES_YAML = <<-EOY.freeze()
61
+ Courses:
62
+ COSC: [470,'Computer Science']
63
+ MUSC: [340,'Music']
64
+ ARTS: [250,'The Arts']
65
+ Schedule:
66
+ - {Course: COSC,Time: '08:00'}
67
+ - {Course: MUSC,Time: '10:30'}
68
+ - {Course: ARTS,Time: '15:10'}
69
+ - {Course: COSC,Time: '13:10'}
70
+ EOY
71
+ COURSES_DATA = Psych.load(COURSES_YAML).freeze()
72
+
73
+ DOLPHINS_YAML = <<-EOY.freeze()
74
+ Dolphins:
75
+ Common: &com {Length: ~2.5m, Weight: ~235kg}
76
+ Bottlenose: &bot {Length: ~4m, Weight: ~300kg}
77
+ Dusky: &dus {Length: ~1.7m, Weight: ~78kg}
78
+ Orca: &orc {Length: ~7m, Weight: ~3600kg}
79
+ Popular:
80
+ - *bot
81
+ - *orc
82
+ EOY
83
+ DOLPHINS_DATA = Psych.load(DOLPHINS_YAML).freeze()
84
+
85
+ # This is for "<<-" heredoc
86
+ # - Purposely not using "<<~" (tilde) for older Ruby versions
87
+ def self.lstrip_pipe(str)
88
+ return str.gsub(/^\s*\|/,'')
89
+ end
90
+ end