yps 0.1.0 → 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.
- checksums.yaml +4 -4
- data/README.md +80 -7
- data/lib/yps/parser.rb +4 -0
- data/lib/yps/version.rb +1 -1
- data/lib/yps/visitor.rb +66 -0
- data/lib/yps.rb +75 -35
- metadata +7 -4
- data/lib/yps/visitors.rb +0 -37
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0aaa3d8a3ac39f8b0890701d45db64be1d9bbdad6d95d67bdf5a0bd4cac4c841
|
|
4
|
+
data.tar.gz: 9ef25972d03876b137661e62d366641c2392fd47465f6628ab2c1c99f685be65
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 64f564d9d9e5509cccf28cbcb274f8bb2bab852b5e00d87954c11564cf22b20e9b24073a11b78a7ac6fa5d3a2255830245b42ac3b30cde8005c5441d28684048
|
|
7
|
+
data.tar.gz: 75f09a3bf9c5eab84240c14fd0a28d2386f3c58aa31a33b2cd4add9244a6e6184e64368aa65dfb27eefb1150e2d3d46c4cec1fddd6002356f5e45caed2975cae
|
data/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
# YPS: YAML Positioning System
|
|
9
9
|
|
|
10
|
-
YPS is a gem
|
|
10
|
+
YPS is a gem that parses YAML and adds position information (file name, line, and column) to each parsed element.
|
|
11
11
|
This is useful for error reporting and debugging, allowing developers to precisely locate an issue within the original YAML file.
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
@@ -26,12 +26,33 @@ gem install yps
|
|
|
26
26
|
|
|
27
27
|
## Usage
|
|
28
28
|
|
|
29
|
-
You can use the methods below to load
|
|
29
|
+
You can use the methods below to load YAML content into Ruby objects with position information (file name, line, and column).
|
|
30
30
|
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* `YPS.
|
|
34
|
-
*
|
|
31
|
+
* Load the given YAML string into Ruby objects with position information
|
|
32
|
+
* `YPS.safe_load`
|
|
33
|
+
* `YPS.load`
|
|
34
|
+
* `YPS.safe_load_stream`
|
|
35
|
+
* `YPS.load_stream`
|
|
36
|
+
|
|
37
|
+
* Load the YAML read from the given file path into Ruby objects with position information
|
|
38
|
+
* `YPS.safe_load_file`
|
|
39
|
+
* `YPS.load_file`
|
|
40
|
+
* `YPS.safe_load_stream_file`
|
|
41
|
+
* `YPS.load_stream_file`
|
|
42
|
+
|
|
43
|
+
For YAML that contains multiple documents, the following methods load only the first document.
|
|
44
|
+
|
|
45
|
+
* `YPS.safe_load`
|
|
46
|
+
* `YPS.load`
|
|
47
|
+
* `YPS.safe_load_file`
|
|
48
|
+
* `YPS.load_file`
|
|
49
|
+
|
|
50
|
+
In contrast, the following methods load all documents and return them as a list.
|
|
51
|
+
|
|
52
|
+
* `YPS.safe_load_stream`
|
|
53
|
+
* `YPS.load_stream`
|
|
54
|
+
* `YPS.safe_load_stream_file`
|
|
55
|
+
* `YPS.load_stream_file`
|
|
35
56
|
|
|
36
57
|
Parsed objects, except for hash keys, have their own position information.
|
|
37
58
|
You can use the `position` method to get position information in the original YAML of the receiver object.
|
|
@@ -57,14 +78,66 @@ yaml['children'].each do |child|
|
|
|
57
78
|
puts "#{key}: #{value} (#{value.position})"
|
|
58
79
|
end
|
|
59
80
|
end
|
|
81
|
+
|
|
82
|
+
yaml = YPS.load_stream(<<~'YAML')
|
|
83
|
+
- 0
|
|
84
|
+
- 1
|
|
85
|
+
---
|
|
86
|
+
- foo
|
|
87
|
+
- bar
|
|
88
|
+
YAML
|
|
89
|
+
|
|
90
|
+
# output
|
|
91
|
+
# 0 (filename: unknown line 1 column 3)
|
|
92
|
+
# 1 (filename: unknown line 2 column 3)
|
|
93
|
+
# foo (filename: unknown line 4 column 3)
|
|
94
|
+
# bar (filename: unknown line 5 column 3)
|
|
95
|
+
yaml.each do |list|
|
|
96
|
+
list.each do |item|
|
|
97
|
+
puts "#{item} (#{item.position})"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Handling of `false` and `nil` values
|
|
103
|
+
|
|
104
|
+
By default, all objects, including `false` and `nil`, are wrapped in a wrapper class.
|
|
105
|
+
Note that wrapped `false` and `nil` values will not be treated as falsy.
|
|
106
|
+
You can use the `unwrapped_classes` option to avoid this situation.
|
|
107
|
+
Objects belonging to classes specified by this option are returned unwrapped but will not have access to their position information.
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
yaml = YPS.load(<<~'YAML')
|
|
111
|
+
- false
|
|
112
|
+
- null
|
|
113
|
+
YAML
|
|
114
|
+
|
|
115
|
+
# output
|
|
116
|
+
# false
|
|
117
|
+
# nil
|
|
118
|
+
puts (yaml[0] || 'foo').inspect
|
|
119
|
+
puts (yaml[1] || 'bar').inspect
|
|
120
|
+
|
|
121
|
+
yaml = YPS.load(<<~'YAML', unwrapped_classes: [FalseClass, NilClass])
|
|
122
|
+
- false
|
|
123
|
+
- null
|
|
124
|
+
YAML
|
|
125
|
+
|
|
126
|
+
# output
|
|
127
|
+
# "foo"
|
|
128
|
+
# "bar"
|
|
129
|
+
puts (yaml[0] || 'foo').inspect
|
|
130
|
+
puts (yaml[1] || 'bar').inspect
|
|
60
131
|
```
|
|
61
132
|
|
|
133
|
+
For more details about these APIs, please visit [here](https://taichi-ishitani.github.io/yps/).
|
|
134
|
+
|
|
62
135
|
## Contributing
|
|
63
136
|
|
|
64
137
|
Bug reports and pull requests are welcome on GitHub at https://github.com/taichi-ishitani/yps.
|
|
65
138
|
|
|
66
139
|
* [Issue Tracker](https://github.com/taichi-ishitani/yps/issues)
|
|
67
|
-
* [Pull
|
|
140
|
+
* [Pull Request](https://github.com/taichi-ishitani/yps/pulls)
|
|
68
141
|
* [Discussion](https://github.com/taichi-ishitani/yps/discussions)
|
|
69
142
|
|
|
70
143
|
## Copyright & License
|
data/lib/yps/parser.rb
CHANGED
data/lib/yps/version.rb
CHANGED
data/lib/yps/visitor.rb
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YPS # :nodoc: all
|
|
4
|
+
module Visitor
|
|
5
|
+
using NodeExtension
|
|
6
|
+
|
|
7
|
+
module Common
|
|
8
|
+
def initialize( # rubocop:disable Metrics/ParameterLists
|
|
9
|
+
scanner, class_loader, unwrapped_classes, value_class,
|
|
10
|
+
symbolize_names:, freeze:
|
|
11
|
+
)
|
|
12
|
+
super(scanner, class_loader, symbolize_names:, freeze:)
|
|
13
|
+
@unwrapped_classes = unwrapped_classes
|
|
14
|
+
@value_class = value_class
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def accept(node)
|
|
18
|
+
object = super
|
|
19
|
+
if unwrap?(object, node)
|
|
20
|
+
object
|
|
21
|
+
else
|
|
22
|
+
create_wrapped_object(object, node)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def create_wrapped_object(object, node)
|
|
29
|
+
pos = Position.new(node.filename, node.start_line + 1, node.start_column + 1)
|
|
30
|
+
obj = @value_class.new(object, pos)
|
|
31
|
+
@freeze && obj.freeze || obj
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def unwrap?(object, node)
|
|
35
|
+
node.document? ||
|
|
36
|
+
node.mapping_key? ||
|
|
37
|
+
@unwrapped_classes.any? { |klass| object.instance_of?(klass) }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class ToRuby < Psych::Visitors::ToRuby
|
|
42
|
+
include Common
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class NoAliasRuby < Psych::Visitors::NoAliasRuby
|
|
46
|
+
include Common
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.create( # rubocop:disable Metrics/ParameterLists
|
|
50
|
+
permitted_classes, permitted_symbols, unwrapped_classes,
|
|
51
|
+
aliases, symbolize_names, freeze, strict_integer, value_class
|
|
52
|
+
)
|
|
53
|
+
class_loader = Psych::ClassLoader::Restricted.new(
|
|
54
|
+
permitted_classes.map(&:to_s), permitted_symbols.map(&:to_s)
|
|
55
|
+
)
|
|
56
|
+
scanner =
|
|
57
|
+
if RUBY_VERSION >= '3.2.0'
|
|
58
|
+
Psych::ScalarScanner.new(class_loader, strict_integer:)
|
|
59
|
+
else
|
|
60
|
+
Psych::ScalarScanner.new(class_loader)
|
|
61
|
+
end
|
|
62
|
+
(aliases && ToRuby || NoAliasRuby)
|
|
63
|
+
.new(scanner, class_loader, unwrapped_classes, value_class, symbolize_names:, freeze:)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
data/lib/yps.rb
CHANGED
|
@@ -7,7 +7,7 @@ require_relative 'yps/version'
|
|
|
7
7
|
require_relative 'yps/value'
|
|
8
8
|
require_relative 'yps/node_extension'
|
|
9
9
|
require_relative 'yps/parser'
|
|
10
|
-
require_relative 'yps/
|
|
10
|
+
require_relative 'yps/visitor'
|
|
11
11
|
|
|
12
12
|
##
|
|
13
13
|
# = YPS: YAML Positioning Sysmte
|
|
@@ -22,6 +22,8 @@ module YPS
|
|
|
22
22
|
# Safely load the YAML string in +yaml+ and add position information (file name line and column)
|
|
23
23
|
# to each parsed objects except for hash keys.
|
|
24
24
|
#
|
|
25
|
+
# Load the 1st documetns only if the given YAML contains multiple documents.
|
|
26
|
+
#
|
|
25
27
|
# Parsed objects will be wrapped by YPS::Value class to add the accessor returning the position information.
|
|
26
28
|
# You can use the +value_class+ to specify your own wrapper class.
|
|
27
29
|
#
|
|
@@ -35,6 +37,9 @@ module YPS
|
|
|
35
37
|
# Array containing additional classes allowed to be loaded.
|
|
36
38
|
# +permitted_symbols+::
|
|
37
39
|
# Array containing Symbols allowed to be loaded. By default, any symbol can be loaded.
|
|
40
|
+
# +unwrapped_classes+::
|
|
41
|
+
# Array containing classes whose objects are not wrapped with the wrapper class.
|
|
42
|
+
# By default, all objects are wrapped.
|
|
38
43
|
# +aliases+::
|
|
39
44
|
# Aliases can be used if set to true. By default, aliases are not allowed.
|
|
40
45
|
# +filename+::
|
|
@@ -55,31 +60,20 @@ module YPS
|
|
|
55
60
|
# See also Psych.safe_load[https://docs.ruby-lang.org/en/master/Psych.html#method-c-safe_load].
|
|
56
61
|
def safe_load( # rubocop:disable Metrics/ParameterLists
|
|
57
62
|
yaml,
|
|
58
|
-
permitted_classes: [], permitted_symbols: [],
|
|
59
|
-
filename: nil, fallback: nil, symbolize_names: false,
|
|
60
|
-
strict_integer: false, value_class: Value
|
|
63
|
+
permitted_classes: [], permitted_symbols: [], unwrapped_classes: [],
|
|
64
|
+
aliases: false, filename: nil, fallback: nil, symbolize_names: false,
|
|
65
|
+
freeze: false, strict_integer: false, value_class: Value
|
|
61
66
|
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
if RUBY_VERSION >= '3.2.0'
|
|
71
|
-
Psych::ScalarScanner.new(class_loader, strict_integer:)
|
|
72
|
-
else
|
|
73
|
-
Psych::ScalarScanner.new(class_loader)
|
|
74
|
-
end
|
|
75
|
-
visitor =
|
|
76
|
-
if aliases
|
|
77
|
-
Visitors::ToRuby.new(scanner, class_loader, value_class, symbolize_names:, freeze:)
|
|
78
|
-
else
|
|
79
|
-
Visitors::NoAliasRuby.new(scanner, class_loader, value_class, symbolize_names:, freeze:)
|
|
80
|
-
end
|
|
67
|
+
Parser.parse(yaml, filename) do |node|
|
|
68
|
+
visitor =
|
|
69
|
+
Visitor.create(
|
|
70
|
+
permitted_classes, permitted_symbols, unwrapped_classes,
|
|
71
|
+
aliases, symbolize_names, freeze, strict_integer, value_class
|
|
72
|
+
)
|
|
73
|
+
return visitor.accept(node)
|
|
74
|
+
end
|
|
81
75
|
|
|
82
|
-
|
|
76
|
+
fallback
|
|
83
77
|
end
|
|
84
78
|
|
|
85
79
|
##
|
|
@@ -95,9 +89,7 @@ module YPS
|
|
|
95
89
|
#
|
|
96
90
|
# See also YPS.safe_load
|
|
97
91
|
def safe_load_file(filename, **kwargs)
|
|
98
|
-
|
|
99
|
-
safe_load(f, filename:, **kwargs)
|
|
100
|
-
end
|
|
92
|
+
open_file(filename) { |f| safe_load(f, filename:, **kwargs) }
|
|
101
93
|
end
|
|
102
94
|
|
|
103
95
|
##
|
|
@@ -105,19 +97,67 @@ module YPS
|
|
|
105
97
|
#
|
|
106
98
|
# See also YPS.load
|
|
107
99
|
def load_file(filename, **kwargs)
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
open_file(filename) { |f| load(f, filename:, **kwargs) }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
DEFAULT_VALUE = Object.new.freeze
|
|
104
|
+
private_constant :DEFAULT_VALUE
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
# Similar to +YPS.safe_load+, but load all documents given in +yaml+ and return them as a list.
|
|
108
|
+
#
|
|
109
|
+
# See also YPS.safe_load
|
|
110
|
+
def safe_load_stream( # rubocop:disable Metrics/ParameterLists
|
|
111
|
+
yaml,
|
|
112
|
+
permitted_classes: [], permitted_symbols: [], unwrapped_classes: [],
|
|
113
|
+
aliases: false, filename: nil, fallback: DEFAULT_VALUE, symbolize_names: false,
|
|
114
|
+
freeze: false, strict_integer: false, value_class: Value
|
|
115
|
+
)
|
|
116
|
+
visitor = nil
|
|
117
|
+
results = []
|
|
118
|
+
Parser.parse(yaml, filename) do |node|
|
|
119
|
+
visitor ||=
|
|
120
|
+
Visitor.create(
|
|
121
|
+
permitted_classes, permitted_symbols, unwrapped_classes,
|
|
122
|
+
aliases, symbolize_names, freeze, strict_integer, value_class
|
|
123
|
+
)
|
|
124
|
+
results << visitor.accept(node)
|
|
110
125
|
end
|
|
126
|
+
return fallback if results.empty? && !fallback.equal?(DEFAULT_VALUE)
|
|
127
|
+
|
|
128
|
+
results
|
|
111
129
|
end
|
|
112
130
|
|
|
113
|
-
|
|
131
|
+
##
|
|
132
|
+
# Similar to +YPS.safe_load_sream+, but Symbol is allowed to be loaded by default.
|
|
133
|
+
#
|
|
134
|
+
# See also YPS.safe_load_stream
|
|
135
|
+
def load_stream(yaml, permitted_classes: [Symbol], **kwargs)
|
|
136
|
+
safe_load_stream(yaml, permitted_classes:, **kwargs)
|
|
137
|
+
end
|
|
114
138
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
139
|
+
##
|
|
140
|
+
# Similar to +YPS.safe_load_stream+,
|
|
141
|
+
# but the YAML string is read from the file specified by the +filename+ argument.
|
|
142
|
+
#
|
|
143
|
+
# See also YPS.safe_load_stream
|
|
144
|
+
def safe_load_stream_file(filename, **kwargs)
|
|
145
|
+
open_file(filename) { |f| safe_load_stream(f, filename:, **kwargs) }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
##
|
|
149
|
+
# Similar to +YPS.load_stream+,
|
|
150
|
+
# but the YAML string is read from the file specified by the +filename+ argument.
|
|
151
|
+
#
|
|
152
|
+
# See also YPS.load_stream
|
|
153
|
+
def load_stream_file(filename, **kwargs)
|
|
154
|
+
open_file(filename) { |f| load_stream(f, filename:, **kwargs) }
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
private
|
|
119
158
|
|
|
120
|
-
|
|
159
|
+
def open_file(filename, &)
|
|
160
|
+
File.open(filename, 'r:bom|utf-8', &)
|
|
121
161
|
end
|
|
122
162
|
end
|
|
123
163
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yps
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Taichi Ishitani
|
|
@@ -29,14 +29,17 @@ files:
|
|
|
29
29
|
- lib/yps/parser.rb
|
|
30
30
|
- lib/yps/value.rb
|
|
31
31
|
- lib/yps/version.rb
|
|
32
|
-
- lib/yps/
|
|
32
|
+
- lib/yps/visitor.rb
|
|
33
33
|
homepage: https://github.com/taichi-ishitani/yps
|
|
34
34
|
licenses:
|
|
35
35
|
- MIT
|
|
36
36
|
metadata:
|
|
37
|
+
bug_tracker_uri: https://github.com/taichi-ishitani/yps/issues
|
|
38
|
+
changelog_uri: https://github.com/taichi-ishitani/yps/releases
|
|
39
|
+
documentation_uri: https://taichi-ishitani.github.io/yps/
|
|
37
40
|
homepage_uri: https://github.com/taichi-ishitani/yps
|
|
38
|
-
source_code_uri: https://github.com/taichi-ishitani/yps
|
|
39
41
|
rubygems_mfa_required: 'true'
|
|
42
|
+
source_code_uri: https://github.com/taichi-ishitani/yps
|
|
40
43
|
rdoc_options:
|
|
41
44
|
- "--main"
|
|
42
45
|
- README.md
|
|
@@ -57,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
57
60
|
- !ruby/object:Gem::Version
|
|
58
61
|
version: '0'
|
|
59
62
|
requirements: []
|
|
60
|
-
rubygems_version:
|
|
63
|
+
rubygems_version: 4.0.3
|
|
61
64
|
specification_version: 4
|
|
62
65
|
summary: 'YPS: YAML Positioning System'
|
|
63
66
|
test_files: []
|
data/lib/yps/visitors.rb
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module YPS # :nodoc: all
|
|
4
|
-
module Visitors
|
|
5
|
-
using NodeExtension
|
|
6
|
-
|
|
7
|
-
module Common
|
|
8
|
-
def initialize(scanner, class_loader, value_class, symbolize_names:, freeze:)
|
|
9
|
-
super(scanner, class_loader, symbolize_names:, freeze:)
|
|
10
|
-
@value_class = value_class
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def accept(node)
|
|
14
|
-
object = super
|
|
15
|
-
create_wrapped_object(object, node)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
def create_wrapped_object(object, node)
|
|
21
|
-
return object if node.document? || node.mapping_key?
|
|
22
|
-
|
|
23
|
-
pos = Position.new(node.filename, node.start_line + 1, node.start_column + 1)
|
|
24
|
-
obj = @value_class.new(object, pos)
|
|
25
|
-
@freeze && obj.freeze || obj
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
class ToRuby < Psych::Visitors::ToRuby
|
|
30
|
-
include Common
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
class NoAliasRuby < Psych::Visitors::NoAliasRuby
|
|
34
|
-
include Common
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|