psychgus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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