metaheader 1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a7f58462dc9676a28a3fb5e9e9d49c8a4608feae
4
+ data.tar.gz: 2a62e2688d2e64cf2205eadfda4796cf0e186076
5
+ SHA512:
6
+ metadata.gz: 09a917aee1880666a29b053d4836a5d7dbdb4f89134d6adc1695c3fd5a510d76de7e5b203c207b2d462dc93a3aee93863c0ee3b87450c6279789e761e8d32f7a
7
+ data.tar.gz: ed7ead26c3ca6d29a8543bc5e4fa52471310c902d2d1ae44fbe1a12cb0620dfd10dab1b8e7f9f0a5dbf974182a71bc2275eb3a847533d46b50d3e28de737165f
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg/
2
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem update bundler
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,165 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Parser for metadata header in plain-text files
2
+
3
+ [![Build Status](https://travis-ci.org/cfillion/metaheader.svg?branch=master)](https://travis-ci.org/cfillion/metaheader)
4
+ [![Coverage Status](https://coveralls.io/repos/cfillion/metaheader/badge.svg?branch=master&service=github)](https://coveralls.io/github/cfillion/metaheader?branch=master)
5
+
6
+ ## Syntax
7
+
8
+ ```
9
+ @key value
10
+
11
+ @key
12
+ value line 1
13
+ value line 2
14
+
15
+ @key
16
+ ```
17
+
18
+ Any kind of comment syntax or prefix can be used:
19
+
20
+ ```cpp
21
+ /*
22
+ * @key value
23
+ */
24
+ ```
25
+
26
+ An alternative syntax is also supported:
27
+
28
+ ```
29
+ Key Name: Value
30
+ ```
31
+
32
+ Parsing stops at the first empty line (ignoring white space).
33
+
34
+ ## Usage
35
+
36
+ ```ruby
37
+ require 'metaheader'
38
+
39
+ input = '@key value'
40
+ mh = MetaHeader.new input
41
+
42
+ # alternatively:
43
+ # mh = MetaHeader.from_file path
44
+
45
+ # mark unknown keys as invalid
46
+ # mh.strict = true
47
+
48
+ # set @key as optional
49
+ errors = mh.validate :key => MetaHeader::OPTIONAL
50
+
51
+ # or set @key as required:
52
+ # mh.validate :key => MetaHeader::REQUIRED
53
+ #
54
+ # ensure @key contains a valid value with a regex
55
+ # mh.validate :key => /^\w{2,}$/
56
+
57
+ value = mh[:key]
58
+ ```
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:test]
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = FileList['test/test_*.rb']
7
+ end
@@ -0,0 +1,3 @@
1
+ class MetaHeader
2
+ VERSION = "1.0"
3
+ end
data/lib/metaheader.rb ADDED
@@ -0,0 +1,173 @@
1
+ # @test Hello World
2
+
3
+ require 'metaheader/version'
4
+
5
+ class MetaHeader
6
+ class Parser
7
+ def self.each(&b)
8
+ ObjectSpace.each_object(Class).select { |klass| klass < self }.each &b
9
+ end
10
+
11
+ def initialize(mh)
12
+ @mh = mh
13
+ end
14
+
15
+ def header
16
+ @mh
17
+ end
18
+ end
19
+
20
+ REQUIRED = Object.new.freeze
21
+ OPTIONAL = Object.new.freeze
22
+
23
+ Tag = Struct.new :name, :value
24
+
25
+ attr_accessor :strict
26
+
27
+ REGEX = /\A(?<prefix>.*?)
28
+ (?:@(?<key>\w+)|(?<key>[\w][\w\s]*?)\s*:)
29
+ (?:\s+(?<value>[^\n]+))?
30
+ \Z/x.freeze
31
+
32
+ def self.from_file(file)
33
+ self.new File.read(file)
34
+ end
35
+
36
+ def initialize(input)
37
+ @strict = false
38
+ @data = {}
39
+
40
+ @last_key = nil
41
+ @last_prefix = String.new
42
+
43
+ input.each_line {|line|
44
+ if line.strip.empty?
45
+ break
46
+ else
47
+ self.<< line
48
+ end
49
+ }
50
+
51
+ Parser.each {|klass|
52
+ parser = klass.new self
53
+ parser.parse input
54
+ }
55
+ end
56
+
57
+ def <<(line)
58
+ # multiline value must have the same prefix
59
+ if @last_key && line.index(@last_prefix) == 0
60
+ # remove the line prefix
61
+ mline = line[@last_prefix.size..-1]
62
+ stripped = mline.strip
63
+
64
+ indent_level = mline.index stripped
65
+
66
+ if indent_level > 0
67
+ tag = @data[@last_key]
68
+
69
+ if tag.value.is_a? String
70
+ tag.value += "\n"
71
+ else
72
+ tag.value = String.new
73
+ end
74
+
75
+ tag.value += stripped
76
+
77
+ return
78
+ else
79
+ @last_key = nil
80
+ end
81
+ end
82
+
83
+ return unless match = REGEX.match(line)
84
+
85
+ # single line
86
+ @last_prefix = match[:prefix]
87
+ @last_key = match[:key].downcase.gsub(/[^\w]/, '_').to_sym
88
+
89
+ value = match[:value] || true
90
+ @data[@last_key] = Tag.new match[:key].freeze, value
91
+ end
92
+
93
+ def [](key)
94
+ tag = @data[key] and tag.value
95
+ end
96
+
97
+ def []=(key, value)
98
+ @data[key] ||= Tag.new key
99
+ @data[key].value = value
100
+ end
101
+
102
+ def size
103
+ @data.size
104
+ end
105
+
106
+ def empty?
107
+ @data.empty?
108
+ end
109
+
110
+ def to_h
111
+ Hash[@data.map {|v| [v.first, v.last.value] }]
112
+ end
113
+
114
+ def inspect
115
+ to_h.inspect
116
+ end
117
+
118
+ def validate(rules)
119
+ errors = Array.new
120
+
121
+ if @strict
122
+ @data.each_key {|key|
123
+ errors << 'unknown tag "%s"' % key unless rules.has_key? key
124
+ }
125
+ end
126
+
127
+ rules.each_pair {|key, rule|
128
+ if key_errors = validate_key(key, rule)
129
+ errors.concat key_errors
130
+ end
131
+ }
132
+
133
+ errors.empty? ? nil : errors
134
+ end
135
+
136
+ def validate_key(key, rules)
137
+ rules = Array(rules)
138
+ return if rules.empty?
139
+
140
+ errors = Array.new
141
+
142
+ unless @data.has_key? key
143
+ if rules.include? OPTIONAL
144
+ return nil
145
+ else
146
+ return ['missing tag "%s"' % key]
147
+ end
148
+ end
149
+
150
+ tag = @data[key]
151
+ value = tag.value
152
+ value = String.new if value == true
153
+
154
+ rules.each {|rule|
155
+ case rule
156
+ when REQUIRED, OPTIONAL
157
+ # do nothing
158
+ when Regexp
159
+ unless rule.match value
160
+ errors << 'invalid value for tag "%s"' % tag.name
161
+ end
162
+ when Proc
163
+ if error = rule[value]
164
+ errors << 'invalid value for tag "%s": %s' % [tag.name, error]
165
+ end
166
+ else
167
+ raise ArgumentError
168
+ end
169
+ }
170
+
171
+ errors.empty? ? nil : errors
172
+ end
173
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path '../lib', __FILE__
3
+ $LOAD_PATH.unshift lib unless $LOAD_PATH.include? lib
4
+
5
+ require 'metaheader/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "metaheader"
9
+ spec.version = MetaHeader::VERSION
10
+ spec.authors = ["cfillion"]
11
+ spec.email = ["metaheader@cfillion.tk"]
12
+ spec.summary = %q{Parser for metadata headers in plain-text files}
13
+ spec.homepage = "https://github.com/cfillion/metaheader"
14
+ spec.license = "LGPL-3.0+"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.10'
22
+ spec.add_development_dependency 'coveralls', '~> 0.8'
23
+ spec.add_development_dependency 'minitest', '~> 5.8'
24
+ spec.add_development_dependency 'rake'
25
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,9 @@
1
+ if ENV['CI']
2
+ require 'coveralls'
3
+
4
+ Coveralls::Output.silent = true
5
+ Coveralls.wear!
6
+ end
7
+
8
+ require 'metaheader'
9
+ require 'minitest/autorun'
@@ -0,0 +1,5 @@
1
+ @run_custom
2
+ @hello world
3
+ end header
4
+
5
+ start content
@@ -0,0 +1,219 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class CustomParser < MetaHeader::Parser
4
+ def self.reset
5
+ @@called = false
6
+ end
7
+
8
+ def self.called?
9
+ @@called
10
+ end
11
+
12
+ def self.input
13
+ @@input
14
+ end
15
+
16
+ def self.instance
17
+ @@instance
18
+ end
19
+
20
+ def parse(input)
21
+ return unless header[:run_custom]
22
+
23
+ header[:hello] = header[:hello].to_s * 2
24
+
25
+ @@input = input
26
+ @@instance = header
27
+ @@called = true
28
+ end
29
+ end
30
+
31
+ class TestParser < MiniTest::Test
32
+ def setup
33
+ CustomParser.reset
34
+ end
35
+
36
+ def test_basic_parser
37
+ mh = MetaHeader.new '@hello world'
38
+
39
+ assert_equal 'world', mh[:hello]
40
+ assert_equal 1, mh.size
41
+ end
42
+
43
+ def test_set_value
44
+ mh = MetaHeader.new String.new
45
+
46
+ assert_empty mh
47
+ mh[:hello] = 'world'
48
+ assert_equal 'world', mh[:hello]
49
+ refute_empty mh
50
+
51
+ mh[:hello] = 'bacon'
52
+ assert_equal 'bacon', mh[:hello]
53
+ assert_equal 1, mh.size
54
+ end
55
+
56
+ def test_unrequired_value
57
+ mh = MetaHeader.new '@hello'
58
+ assert_equal true, mh[:hello]
59
+ end
60
+
61
+ def test_ignore_prefix
62
+ mh = MetaHeader.new '-- @chunky bacon'
63
+ assert_equal 'bacon', mh[:chunky]
64
+ end
65
+
66
+ def test_multiline
67
+ mh = MetaHeader.new <<-IN
68
+ -- @chunky bacon
69
+ -- @hello world
70
+ IN
71
+
72
+ assert_equal 'world', mh[:hello]
73
+ assert_equal 'bacon', mh[:chunky]
74
+ assert_equal 2, mh.size
75
+ end
76
+
77
+ def test_break_empty_line
78
+ mh = MetaHeader.new <<-IN
79
+ -- @hello world
80
+
81
+ @chunky bacon
82
+ IN
83
+
84
+ assert_equal 'world', mh[:hello]
85
+ assert_nil mh[:chunky]
86
+ end
87
+
88
+ def test_ignore_c_comment_tokens
89
+ mh = MetaHeader.new <<-IN
90
+ /*
91
+ -- @hello world
92
+ */
93
+ /*
94
+ @chunky bacon
95
+ */
96
+ IN
97
+
98
+ assert_equal 'world', mh[:hello]
99
+ assert_equal 'bacon', mh[:chunky]
100
+ assert_equal 2, mh.size
101
+ end
102
+
103
+ def test_multiline
104
+ mh = MetaHeader.new <<-IN
105
+ @test Lorem
106
+ Ipsum
107
+ IN
108
+
109
+ assert_equal "Lorem\nIpsum", mh[:test]
110
+ assert_equal 1, mh.size
111
+ end
112
+
113
+ def test_multiline_variant
114
+ mh = MetaHeader.new <<-IN
115
+ @test
116
+ Lorem
117
+ Ipsum
118
+ IN
119
+
120
+ assert_equal "Lorem\nIpsum", mh[:test]
121
+ end
122
+
123
+ def test_multiline_prefix
124
+ mh = MetaHeader.new <<-IN
125
+ -- @test Lorem
126
+ -- Ipsum
127
+ IN
128
+
129
+ assert_equal "Lorem\nIpsum", mh[:test]
130
+ assert_equal 1, mh.size
131
+ end
132
+
133
+ def test_multiline_wrong_indent
134
+ mh = MetaHeader.new <<-IN
135
+ @test Lorem
136
+ Ipsum
137
+ Test
138
+ IN
139
+
140
+ assert_equal 1, mh.size
141
+ assert_equal "Lorem", mh[:test]
142
+ end
143
+
144
+ def test_multiline_sub_alternate_syntax
145
+ mh = MetaHeader.new <<-IN
146
+ @test Lorem
147
+ Ipsum:
148
+ Dolor: sit amet
149
+ IN
150
+
151
+ assert_equal "Lorem\nIpsum:\nDolor: sit amet", mh[:test]
152
+ assert_equal 1, mh.size
153
+ end
154
+
155
+ def test_read_file
156
+ path = File.expand_path '../../lib/metaheader.rb', __FILE__
157
+ mh = MetaHeader.from_file path
158
+
159
+ assert_equal 'Hello World', mh[:test]
160
+ assert_equal 1, mh.size
161
+ end
162
+
163
+ def test_to_hash
164
+ mh = MetaHeader.new '@key value'
165
+ expected = {:key => 'value'}
166
+
167
+ assert_equal expected, mh.to_h
168
+ end
169
+
170
+ def test_alternate_syntax
171
+ mh = MetaHeader.new 'Key Test: value'
172
+ expected = {:key_test => 'value'}
173
+
174
+ assert_equal expected, mh.to_h
175
+ end
176
+
177
+ def test_alternate_syntax_prefix
178
+ mh = MetaHeader.new '-- Key Test: Value'
179
+ expected = {:key_test => 'Value'}
180
+
181
+ assert_equal expected, mh.to_h
182
+ end
183
+
184
+ def test_alternate_syntax_trailing_space
185
+ mh = MetaHeader.new ' Key Test : Value'
186
+ expected = {:key_test => 'Value'}
187
+
188
+ assert_equal expected, mh.to_h
189
+ end
190
+
191
+ def test_inspect
192
+ mh = MetaHeader.new '@hello world'
193
+ expected = {:hello => 'world'}
194
+
195
+ assert_equal expected.inspect, mh.inspect
196
+ end
197
+
198
+ def test_transform_from_text
199
+ input = "@run_custom\nHello\n\nWorld".freeze
200
+
201
+ mh = MetaHeader.new input
202
+
203
+ assert CustomParser.called?
204
+ assert_same input, CustomParser.input
205
+ assert_same mh, CustomParser.instance
206
+ end
207
+
208
+ def test_transform_from_file
209
+ path = File.expand_path '../input/custom_parser', __FILE__
210
+ called = false
211
+
212
+ mh = MetaHeader.from_file path
213
+ assert_equal 'worldworld', mh[:hello]
214
+
215
+ assert CustomParser.called?
216
+ assert_equal File.read(path), CustomParser.input
217
+ assert_same mh, CustomParser.instance
218
+ end
219
+ end
@@ -0,0 +1,115 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class TestValidator < MiniTest::Test
4
+ def setup
5
+ @mh = MetaHeader.new <<-IN
6
+ @hello world
7
+ @chunky bacon
8
+ IN
9
+ end
10
+
11
+ def test_unknown_strict
12
+ @mh.strict = true
13
+ actual = @mh.validate Hash.new
14
+
15
+ expected = [
16
+ 'unknown tag "hello"',
17
+ 'unknown tag "chunky"',
18
+ ]
19
+
20
+ assert_equal expected, actual
21
+ end
22
+
23
+ def test_unknown_tolerant
24
+ refute @mh.strict
25
+ actual = @mh.validate Hash.new
26
+
27
+ assert_nil actual
28
+ end
29
+
30
+ def test_optional
31
+ actual = @mh.validate :hello => MetaHeader::OPTIONAL,
32
+ :chunky => MetaHeader::OPTIONAL
33
+
34
+ assert_nil actual
35
+ end
36
+
37
+ def test_required
38
+ actual = @mh.validate :version => MetaHeader::REQUIRED,
39
+ :hello => MetaHeader::OPTIONAL, :chunky => MetaHeader::OPTIONAL
40
+
41
+ expected = [
42
+ 'missing tag "version"',
43
+ ]
44
+
45
+ assert_equal expected, actual
46
+ end
47
+
48
+ def test_regex
49
+ actual = @mh.validate :hello => /\d+/, :chunky => MetaHeader::OPTIONAL
50
+
51
+ expected = [
52
+ 'invalid value for tag "hello"',
53
+ ]
54
+
55
+ assert_equal expected, actual
56
+ end
57
+
58
+ def test_use_original_format
59
+ @mh = MetaHeader.new 'HeLlO: world'
60
+ actual = @mh.validate :hello => /\d+/
61
+
62
+ expected = [
63
+ 'invalid value for tag "HeLlO"',
64
+ ]
65
+
66
+ assert_equal expected, actual
67
+ end
68
+
69
+ def test_regex_missing
70
+ actual = @mh.validate :version => /\d+/,
71
+ :hello => MetaHeader::REQUIRED, :chunky => MetaHeader::OPTIONAL
72
+
73
+ expected = [
74
+ 'missing tag "version"',
75
+ ]
76
+
77
+ assert_equal expected, actual
78
+ end
79
+
80
+ def test_regex_optional
81
+ actual = @mh.validate :version => [MetaHeader::OPTIONAL, /\d+/],
82
+ :hello => MetaHeader::REQUIRED, :chunky => MetaHeader::OPTIONAL
83
+
84
+ assert_nil actual
85
+ end
86
+
87
+ def test_regex_no_value
88
+ @mh = MetaHeader.new '@hello'
89
+ actual = @mh.validate :hello => [MetaHeader::OPTIONAL, /.+/]
90
+
91
+ expected = [
92
+ 'invalid value for tag "hello"',
93
+ ]
94
+
95
+ assert_equal expected, actual
96
+ end
97
+
98
+ def test_custom_validator
99
+ valid = @mh.validate :hello => Proc.new {|value| value == 'world' && nil }
100
+ assert_nil valid
101
+
102
+ expected = [
103
+ 'invalid value for tag "hello": Hello World!',
104
+ ]
105
+
106
+ invalid = @mh.validate :hello => Proc.new {|value| 'Hello World!' }
107
+ assert_equal expected, invalid
108
+ end
109
+
110
+ def test_invalid_rule
111
+ assert_raises ArgumentError do
112
+ @mh.validate_key :hello, :hello => Object.new
113
+ end
114
+ end
115
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metaheader
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - cfillion
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: coveralls
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - metaheader@cfillion.tk
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - lib/metaheader.rb
83
+ - lib/metaheader/version.rb
84
+ - metaheader.gemspec
85
+ - test/helper.rb
86
+ - test/input/custom_parser
87
+ - test/test_parser.rb
88
+ - test/test_validator.rb
89
+ homepage: https://github.com/cfillion/metaheader
90
+ licenses:
91
+ - LGPL-3.0+
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.5.1
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Parser for metadata headers in plain-text files
113
+ test_files:
114
+ - test/helper.rb
115
+ - test/input/custom_parser
116
+ - test/test_parser.rb
117
+ - test/test_validator.rb