metaheader 1.1.1 → 1.2
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 +6 -1
- data/lib/metaheader/version.rb +1 -1
- data/lib/metaheader.rb +58 -16
- data/test/test_parser.rb +50 -2
- data/test/test_validator.rb +12 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b27a892f14adfb3c27237943a6092a25e7976b4a
|
4
|
+
data.tar.gz: 066516c6ee0af9a85544ef3ab226c249d2ed6d78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0062129b4f626c499d89d340f6a43eb5f4a65ecf15632c186c9e3dbae68f5799c719e19d30b7c6835f5c98ccc7baf936fb5c0734a53e776d0d871ffa23bf29c7
|
7
|
+
data.tar.gz: 99f9068fbc6118c4bab541d6c96b8344ad80838f73990d9197ca0d2231a18af454975134ddf46afe1613c38842cd8bbd383d6e190f97c323507a51f0ee7e49d8
|
data/README.md
CHANGED
@@ -14,6 +14,10 @@
|
|
14
14
|
value line 2
|
15
15
|
|
16
16
|
@key
|
17
|
+
@key true
|
18
|
+
|
19
|
+
@nokey
|
20
|
+
@key false
|
17
21
|
```
|
18
22
|
|
19
23
|
Any kind of comment syntax or prefix can be used:
|
@@ -50,9 +54,10 @@ mh = MetaHeader.new input
|
|
50
54
|
errors = mh.validate key: MetaHeader::REQUIRED
|
51
55
|
|
52
56
|
# other validators are available:
|
57
|
+
# mh.validate key: MetaHeader::BOOLEAN
|
53
58
|
# mh.validate key: MetaHeader::OPTIONAL
|
54
59
|
# mh.validate key: MetaHeader::SINGLELINE
|
55
|
-
# mh.validate key: MetaHeader::
|
60
|
+
# mh.validate key: MetaHeader::VALUE
|
56
61
|
# mh.validate key: /^\w{2,}$/
|
57
62
|
# mh.validate key: proc {|value| 'return nil or error' }
|
58
63
|
|
data/lib/metaheader/version.rb
CHANGED
data/lib/metaheader.rb
CHANGED
@@ -28,10 +28,11 @@ class MetaHeader
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
BOOLEAN = Object.new.freeze
|
32
32
|
OPTIONAL = Object.new.freeze
|
33
|
-
|
33
|
+
REQUIRED = Object.new.freeze
|
34
34
|
SINGLELINE = Object.new.freeze
|
35
|
+
VALUE = Object.new.freeze
|
35
36
|
|
36
37
|
# Whether to fail validation if unknown tags are encoutered.
|
37
38
|
# @see #validate
|
@@ -71,15 +72,23 @@ class MetaHeader
|
|
71
72
|
end
|
72
73
|
|
73
74
|
# Returns the value of a tag by its name, or nil if not found.
|
75
|
+
# @param key [Symbol] tag name
|
76
|
+
# @param default [Object] value to return if key doesn't exist
|
74
77
|
# @return [Object, nil]
|
75
|
-
def [](key)
|
76
|
-
tag = @data[key]
|
78
|
+
def [](key, default = nil)
|
79
|
+
if tag = @data[key]
|
80
|
+
tag.value
|
81
|
+
else
|
82
|
+
default
|
83
|
+
end
|
77
84
|
end
|
78
85
|
|
79
86
|
# Replaces the value of a tag.
|
80
87
|
# @param value the new value
|
81
88
|
# @return value
|
82
89
|
def []=(key, value)
|
90
|
+
raise ArgumentError, 'value cannot be nil' if value.nil?
|
91
|
+
|
83
92
|
@data[key] ||= Tag.new key
|
84
93
|
@data[key].value = value
|
85
94
|
end
|
@@ -96,10 +105,23 @@ class MetaHeader
|
|
96
105
|
@data.empty?
|
97
106
|
end
|
98
107
|
|
108
|
+
# Whether a tag was found in the input.
|
109
|
+
# @param tag [Symbol] the tag to lookup
|
110
|
+
# @return [Boolean]
|
111
|
+
def has?(tag)
|
112
|
+
@data.has_key? tag.to_sym
|
113
|
+
end
|
114
|
+
|
115
|
+
# Removes a given tag from the list.
|
116
|
+
# @param tag [Symbol] the tag to remove
|
117
|
+
def delete(tag)
|
118
|
+
@data.delete tag
|
119
|
+
end
|
120
|
+
|
99
121
|
# Make a hash from the parsed data
|
100
122
|
# @return [Hash]
|
101
123
|
def to_h
|
102
|
-
Hash[@data.map {|
|
124
|
+
Hash[@data.map {|name, tag| [name, tag.value] }]
|
103
125
|
end
|
104
126
|
|
105
127
|
# Makes a human-readable representation of the current instance.
|
@@ -116,10 +138,11 @@ class MetaHeader
|
|
116
138
|
# chunky: proc {|value| 'not bacon' unless value == 'bacon' }
|
117
139
|
# @param rules [Hash] tag_name => rule or array_of_rules
|
118
140
|
# @return [Array, nil] error list or nil
|
119
|
-
# @see
|
141
|
+
# @see BOOLEAN
|
120
142
|
# @see OPTIONAL
|
121
|
-
# @see
|
143
|
+
# @see REQUIRED
|
122
144
|
# @see SINGLELINE
|
145
|
+
# @see VALUE
|
123
146
|
def validate(rules)
|
124
147
|
errors = Array.new
|
125
148
|
|
@@ -148,6 +171,8 @@ private
|
|
148
171
|
\Z/x.freeze
|
149
172
|
|
150
173
|
def parse(line)
|
174
|
+
line.rstrip!
|
175
|
+
|
151
176
|
# multiline value must have the same prefix
|
152
177
|
if @last_key && line.index(@last_prefix) == 0
|
153
178
|
# remove the line prefix
|
@@ -159,12 +184,8 @@ private
|
|
159
184
|
if indent_level > 0
|
160
185
|
tag = @data[@last_key]
|
161
186
|
|
162
|
-
|
163
|
-
|
164
|
-
else
|
165
|
-
tag.value = String.new
|
166
|
-
end
|
167
|
-
|
187
|
+
tag.value = @raw_value.to_s unless tag.value.is_a? String
|
188
|
+
tag.value += "\n" unless tag.value.empty?
|
168
189
|
tag.value += stripped
|
169
190
|
|
170
191
|
return
|
@@ -177,12 +198,29 @@ private
|
|
177
198
|
|
178
199
|
# single line
|
179
200
|
@last_prefix = match[:prefix]
|
180
|
-
|
201
|
+
key = match[:key].downcase.gsub(/[^\w]/, '_')
|
181
202
|
|
182
|
-
|
203
|
+
@raw_value = match[:value]
|
204
|
+
key, value = parse_value key, @raw_value
|
205
|
+
|
206
|
+
@last_key = key.to_sym
|
183
207
|
@data[@last_key] = Tag.new match[:key].freeze, value
|
184
208
|
end
|
185
209
|
|
210
|
+
def parse_value(key, value)
|
211
|
+
value ||= true
|
212
|
+
|
213
|
+
case value
|
214
|
+
when 'true'
|
215
|
+
value = true
|
216
|
+
when 'false'
|
217
|
+
value = false
|
218
|
+
when String
|
219
|
+
value = nil if value.empty?
|
220
|
+
end
|
221
|
+
|
222
|
+
[key, value]
|
223
|
+
end
|
186
224
|
|
187
225
|
def validate_key(key, rules)
|
188
226
|
rules = Array(rules)
|
@@ -212,6 +250,10 @@ private
|
|
212
250
|
if str_value.empty?
|
213
251
|
return "missing value for tag '%s'" % tag.name
|
214
252
|
end
|
253
|
+
when BOOLEAN
|
254
|
+
unless [TrueClass, FalseClass].include? tag.value.class
|
255
|
+
return "tag '%s' cannot have a value" % tag.name
|
256
|
+
end
|
215
257
|
when Regexp
|
216
258
|
unless rule.match str_value
|
217
259
|
return "invalid value for tag '%s'" % tag.name
|
@@ -221,7 +263,7 @@ private
|
|
221
263
|
return "invalid value for tag '%s': %s" % [tag.name, error]
|
222
264
|
end
|
223
265
|
else
|
224
|
-
raise ArgumentError
|
266
|
+
raise ArgumentError, "unsupported validator #{rule}"
|
225
267
|
end
|
226
268
|
}
|
227
269
|
|
data/test/test_parser.rb
CHANGED
@@ -51,13 +51,22 @@ class TestParser < MiniTest::Test
|
|
51
51
|
mh[:hello] = 'bacon'
|
52
52
|
assert_equal 'bacon', mh[:hello]
|
53
53
|
assert_equal 1, mh.size
|
54
|
+
|
55
|
+
error = assert_raises(ArgumentError) { mh[:hello] = nil }
|
56
|
+
assert_equal 'value cannot be nil', error.message
|
54
57
|
end
|
55
58
|
|
56
|
-
def
|
57
|
-
mh = MetaHeader.new
|
59
|
+
def test_implicit_boolean
|
60
|
+
mh = MetaHeader.new "@hello"
|
58
61
|
assert_equal true, mh[:hello]
|
59
62
|
end
|
60
63
|
|
64
|
+
def test_explicit_boolean
|
65
|
+
mh = MetaHeader.new "@foo true\n@bar false"
|
66
|
+
assert_equal true, mh[:foo]
|
67
|
+
assert_equal false, mh[:bar]
|
68
|
+
end
|
69
|
+
|
61
70
|
def test_ignore_prefix
|
62
71
|
mh = MetaHeader.new '-- @chunky bacon'
|
63
72
|
assert_equal 'bacon', mh[:chunky]
|
@@ -120,6 +129,18 @@ class TestParser < MiniTest::Test
|
|
120
129
|
assert_equal "Lorem\nIpsum", mh[:test]
|
121
130
|
end
|
122
131
|
|
132
|
+
def test_multiline_trailing_space
|
133
|
+
mh = MetaHeader.new <<-IN
|
134
|
+
@hello\x20
|
135
|
+
test\x20
|
136
|
+
@world\x20\x20
|
137
|
+
test\x20
|
138
|
+
IN
|
139
|
+
|
140
|
+
assert_equal 'test', mh[:hello]
|
141
|
+
assert_equal 'test', mh[:world]
|
142
|
+
end
|
143
|
+
|
123
144
|
def test_multiline_prefix
|
124
145
|
mh = MetaHeader.new <<-IN
|
125
146
|
-- @test Lorem
|
@@ -152,6 +173,15 @@ class TestParser < MiniTest::Test
|
|
152
173
|
assert_equal 1, mh.size
|
153
174
|
end
|
154
175
|
|
176
|
+
def test_multiline_explicit_boolean
|
177
|
+
mh = MetaHeader.new <<-IN
|
178
|
+
@test true
|
179
|
+
test
|
180
|
+
IN
|
181
|
+
|
182
|
+
assert_equal "true\ntest", mh[:test]
|
183
|
+
end
|
184
|
+
|
155
185
|
def test_read_file
|
156
186
|
path = File.expand_path '../input/basic_tag', __FILE__
|
157
187
|
mh = MetaHeader.from_file path
|
@@ -219,4 +249,22 @@ class TestParser < MiniTest::Test
|
|
219
249
|
assert_equal File.read(path), CustomParser.input
|
220
250
|
assert_same mh, CustomParser.instance
|
221
251
|
end
|
252
|
+
|
253
|
+
def test_has_tag
|
254
|
+
mh = MetaHeader.new '@hello'
|
255
|
+
assert_equal true, mh.has?(:hello)
|
256
|
+
assert_equal false, mh.has?(:world)
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_default_value
|
260
|
+
mh = MetaHeader.new String.new
|
261
|
+
assert_equal 'world', mh[:hello, 'world']
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_delete
|
265
|
+
mh = MetaHeader.new '@hello world'
|
266
|
+
assert mh.has?(:hello)
|
267
|
+
mh.delete :hello
|
268
|
+
refute mh.has?(:hello)
|
269
|
+
end
|
222
270
|
end
|
data/test/test_validator.rb
CHANGED
@@ -93,8 +93,18 @@ class TestValidator < MiniTest::Test
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def test_invalid_rule
|
96
|
-
|
97
|
-
|
96
|
+
obj = Object.new.freeze
|
97
|
+
|
98
|
+
error = assert_raises ArgumentError do
|
99
|
+
validate '@hello world', hello: obj
|
98
100
|
end
|
101
|
+
|
102
|
+
assert_equal "unsupported validator #{obj.inspect}", error.message
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_boolean
|
106
|
+
actual = validate "@hello true\n@hello world",
|
107
|
+
hello: MetaHeader::BOOLEAN
|
108
|
+
assert_equal ["tag 'hello' cannot have a value"], actual
|
99
109
|
end
|
100
110
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metaheader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: '1.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- cfillion
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|