zig 0.0.2 → 0.0.3
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/.gitignore +1 -0
- data/README.md +15 -10
- data/bin/zig +48 -0
- data/lib/zig.rb +7 -5
- data/lib/zig/formatter.rb +17 -17
- data/lib/zig/lines.rb +10 -12
- data/lib/zig/parser.rb +16 -9
- data/lib/zig/syntax_error.rb +2 -0
- data/lib/zig/version.rb +1 -1
- data/test/zig_test.rb +27 -4
- metadata +6 -5
- data/bin/format +0 -12
data/.gitignore
CHANGED
data/README.md
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
# ZIG
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Zig is a simple data format. It is designed to be edited by hand.
|
|
4
4
|
It is also pretty easy to parse and generate, though.
|
|
5
|
+
You can think of Zig as an alternate, indentation-based
|
|
6
|
+
syntax for JSON.
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Here is a short example:
|
|
8
|
+
Here is a short example that shows all data structures:
|
|
9
9
|
|
|
10
10
|
```
|
|
11
11
|
{
|
|
12
12
|
type: 'error'
|
|
13
|
+
subtype: nil
|
|
14
|
+
description: "
|
|
15
|
+
Check your Internet connection. Restart any router, modem,
|
|
16
|
+
or other network devices you may be using.
|
|
13
17
|
color: {
|
|
14
18
|
r: 255
|
|
15
19
|
g: 192
|
|
16
20
|
b: 0
|
|
17
|
-
description: "
|
|
18
|
-
Check your Internet connection. Restart any router, modem,
|
|
19
|
-
or other network devices you may be using.
|
|
20
21
|
# TODO: do we need these any more?
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
flags: [
|
|
23
|
+
true
|
|
24
|
+
false
|
|
25
|
+
true
|
|
24
26
|
```
|
|
27
|
+
|
|
28
|
+
In order of appearance: hash, string, nil, multiline string, number,
|
|
29
|
+
comment, list, boolean.
|
data/bin/zig
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require "zig"
|
|
3
|
+
require "optparse"
|
|
4
|
+
|
|
5
|
+
def fail_with(message)
|
|
6
|
+
$stderr.puts message
|
|
7
|
+
exit 1
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def parse_zig(file)
|
|
11
|
+
ZIG::Parser.parse_document(ZIG::Lines.new(File.open(file)))
|
|
12
|
+
rescue ZIG::SyntaxError => e
|
|
13
|
+
fail_with(e.message)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def parse_json(file)
|
|
17
|
+
require "json"
|
|
18
|
+
JSON.parse(File.read(file))
|
|
19
|
+
rescue JSON::ParserError => e
|
|
20
|
+
fail_with(e.message)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
output = nil
|
|
24
|
+
OptionParser.new do |opts|
|
|
25
|
+
opts.on("-o", "--output [format]", "convert to output format") do |format|
|
|
26
|
+
output = format
|
|
27
|
+
end
|
|
28
|
+
end.parse!
|
|
29
|
+
|
|
30
|
+
_, ending = ARGV[0].split(".")
|
|
31
|
+
data = case ending
|
|
32
|
+
when "zig"
|
|
33
|
+
parse_zig(ARGV[0])
|
|
34
|
+
when "json"
|
|
35
|
+
parse_json(ARGV[0])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
case output
|
|
39
|
+
when nil
|
|
40
|
+
# no output
|
|
41
|
+
when "zig"
|
|
42
|
+
puts ZIG.generate(data)
|
|
43
|
+
when "json"
|
|
44
|
+
require "json"
|
|
45
|
+
puts JSON.pretty_generate(data)
|
|
46
|
+
else
|
|
47
|
+
fail_with("unknown format: #{output}")
|
|
48
|
+
end
|
data/lib/zig.rb
CHANGED
|
@@ -2,6 +2,7 @@ require "zig/version"
|
|
|
2
2
|
require "zig/lines"
|
|
3
3
|
require "zig/parser"
|
|
4
4
|
require "zig/formatter"
|
|
5
|
+
require "zig/syntax_error"
|
|
5
6
|
|
|
6
7
|
require "stringio"
|
|
7
8
|
|
|
@@ -9,13 +10,14 @@ module ZIG
|
|
|
9
10
|
|
|
10
11
|
def self.parse(string)
|
|
11
12
|
lines = Lines.new(StringIO.new(string))
|
|
12
|
-
|
|
13
|
-
lines.next
|
|
14
|
-
Parser.parse_value(0, lines, start)
|
|
13
|
+
Parser.parse_document(lines)
|
|
15
14
|
end
|
|
16
15
|
|
|
17
|
-
def self.
|
|
18
|
-
|
|
16
|
+
def self.generate(data)
|
|
17
|
+
out = StringIO.new
|
|
18
|
+
Formatter.print_value(out, "", data)
|
|
19
|
+
out.rewind
|
|
20
|
+
out.read
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
end
|
data/lib/zig/formatter.rb
CHANGED
|
@@ -2,43 +2,43 @@ class ZIG::Formatter
|
|
|
2
2
|
|
|
3
3
|
INDENT = " " * 2
|
|
4
4
|
|
|
5
|
-
def self.print_hash(indent, hash)
|
|
6
|
-
|
|
5
|
+
def self.print_hash(out, indent, hash)
|
|
6
|
+
out.write("{\n")
|
|
7
7
|
indent = indent + INDENT
|
|
8
8
|
hash.each do |key, value|
|
|
9
|
-
|
|
10
|
-
print_value(indent, value)
|
|
9
|
+
out.write(indent + key.to_s + ": ")
|
|
10
|
+
print_value(out, indent, value)
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def self.print_array(indent, array)
|
|
15
|
-
|
|
14
|
+
def self.print_array(out, indent, array)
|
|
15
|
+
out.write("[\n")
|
|
16
16
|
indent = indent + INDENT
|
|
17
17
|
array.each do |v|
|
|
18
|
-
|
|
19
|
-
print_value(indent, v)
|
|
18
|
+
out.write(indent)
|
|
19
|
+
print_value(out, indent, v)
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def self.print_multiline_string(indent, string)
|
|
24
|
-
|
|
23
|
+
def self.print_multiline_string(out, indent, string)
|
|
24
|
+
out.write("\"\n")
|
|
25
25
|
indent = indent + INDENT
|
|
26
26
|
string.split("\n").each do |line|
|
|
27
|
-
|
|
27
|
+
out.write(indent + line.lstrip + "\n")
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def self.print_value(indent, value)
|
|
31
|
+
def self.print_value(out, indent, value)
|
|
32
32
|
case value
|
|
33
|
-
when Hash then print_hash(indent, value)
|
|
34
|
-
when Array then print_array(indent, value)
|
|
33
|
+
when Hash then print_hash(out, indent, value)
|
|
34
|
+
when Array then print_array(out, indent, value)
|
|
35
35
|
when String
|
|
36
36
|
if value.include?("\n")
|
|
37
|
-
print_multiline_string(indent, value)
|
|
37
|
+
print_multiline_string(out, indent, value)
|
|
38
38
|
else
|
|
39
|
-
|
|
39
|
+
out.write("'#{value}'\n")
|
|
40
40
|
end
|
|
41
|
-
else
|
|
41
|
+
else out.write(value.inspect + "\n")
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
data/lib/zig/lines.rb
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
attr_reader :current, :num
|
|
1
|
+
class ZIG::Lines
|
|
2
|
+
attr_reader :current, :num
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
def initialize(file)
|
|
5
|
+
@file, @current, @num = file, file.gets, 1
|
|
6
|
+
end
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
def empty?
|
|
9
|
+
@current.nil?
|
|
10
|
+
end
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
12
|
+
def next
|
|
13
|
+
@current, @num = @file.gets, @num + 1
|
|
16
14
|
end
|
|
17
15
|
end
|
data/lib/zig/parser.rb
CHANGED
|
@@ -13,20 +13,19 @@ class ZIG::Parser
|
|
|
13
13
|
return object if lines.empty?
|
|
14
14
|
spaces, value = lines.current.scan(FULL_LINE).flatten
|
|
15
15
|
return object if spaces.size < indent
|
|
16
|
-
raise "[line #{lines.num}] illegal indent" if spaces.size > indent
|
|
16
|
+
raise ZIG::SyntaxError, "[line #{lines.num}] illegal indent" if spaces.size > indent
|
|
17
17
|
lines.next
|
|
18
18
|
if object.is_a?(String)
|
|
19
19
|
object << "\n" unless object.empty?
|
|
20
20
|
object << value
|
|
21
|
+
elsif object.is_a?(Array)
|
|
22
|
+
next if value[0] == '#'
|
|
23
|
+
object << parse_value(indent, lines, value)
|
|
21
24
|
else
|
|
22
25
|
next if value[0] == '#'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
object[key.strip.to_sym] = parse_value(indent, lines, value)
|
|
27
|
-
else
|
|
28
|
-
object << parse_value(indent, lines, value)
|
|
29
|
-
end
|
|
26
|
+
key, value = value.scan(KEY_VALUE).flatten
|
|
27
|
+
raise ZIG::SyntaxError, "[line #{lines.num - 1}] missing key" if key.nil?
|
|
28
|
+
object[key.strip.to_sym] = parse_value(indent, lines, value)
|
|
30
29
|
end
|
|
31
30
|
end
|
|
32
31
|
end
|
|
@@ -44,8 +43,16 @@ class ZIG::Parser
|
|
|
44
43
|
when INTEGER then text.to_i
|
|
45
44
|
when FLOAT then text.to_f
|
|
46
45
|
else
|
|
47
|
-
raise "[line #{lines.num}] illegal value: #{text}"
|
|
46
|
+
raise ZIG::SyntaxError, "[line #{lines.num}] illegal value: #{text}"
|
|
48
47
|
end
|
|
49
48
|
end
|
|
50
49
|
|
|
50
|
+
def self.parse_document(lines)
|
|
51
|
+
raise ZIG::SyntaxError, "cannot parse empty document" if lines.empty?
|
|
52
|
+
lines.next while lines.current[0] == '#'
|
|
53
|
+
start = lines.current
|
|
54
|
+
lines.next
|
|
55
|
+
return parse_value(0, lines, start)
|
|
56
|
+
end
|
|
57
|
+
|
|
51
58
|
end
|
data/lib/zig/version.rb
CHANGED
data/test/zig_test.rb
CHANGED
|
@@ -6,7 +6,7 @@ describe ZIG do
|
|
|
6
6
|
|
|
7
7
|
describe "empty" do
|
|
8
8
|
it "should reject an empty document" do
|
|
9
|
-
assert_raises(
|
|
9
|
+
assert_raises(ZIG::SyntaxError) { ZIG.parse("") }
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -24,7 +24,7 @@ describe ZIG do
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
it "should reject other literals" do
|
|
27
|
-
assert_raises(
|
|
27
|
+
assert_raises(ZIG::SyntaxError) { ZIG.parse("foo") }
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -107,6 +107,15 @@ describe ZIG do
|
|
|
107
107
|
assert_equal [1, 2, 3], ZIG.parse(doc)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
+
it "should parse nested empty lists" do
|
|
111
|
+
doc =
|
|
112
|
+
"[
|
|
113
|
+
[
|
|
114
|
+
[
|
|
115
|
+
["
|
|
116
|
+
assert_equal [[], [], []], ZIG.parse(doc)
|
|
117
|
+
end
|
|
118
|
+
|
|
110
119
|
it "should parse a list of complex values" do
|
|
111
120
|
doc =
|
|
112
121
|
"[
|
|
@@ -154,16 +163,29 @@ describe ZIG do
|
|
|
154
163
|
a: 1
|
|
155
164
|
: 2
|
|
156
165
|
c: 3"
|
|
157
|
-
assert_raises(
|
|
166
|
+
assert_raises(ZIG::SyntaxError) { ZIG.parse(doc) }
|
|
158
167
|
end
|
|
159
168
|
end
|
|
160
169
|
|
|
161
170
|
describe "comments" do
|
|
171
|
+
it "should skip comment lines at the start of a document" do
|
|
172
|
+
doc =
|
|
173
|
+
"# IMPORTANT
|
|
174
|
+
{
|
|
175
|
+
a: 1
|
|
176
|
+
b: 2
|
|
177
|
+
c: 3"
|
|
178
|
+
assert_equal Hash[a: 1, b: 2, c: 3], ZIG.parse(doc)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
162
183
|
it "should skip comment lines inside hashes" do
|
|
163
184
|
doc =
|
|
164
185
|
"{
|
|
165
186
|
a: 1
|
|
166
187
|
#b: 2
|
|
188
|
+
#b: 2
|
|
167
189
|
c: 3"
|
|
168
190
|
assert_equal Hash[a: 1, c: 3], ZIG.parse(doc)
|
|
169
191
|
end
|
|
@@ -173,6 +195,7 @@ describe ZIG do
|
|
|
173
195
|
"[
|
|
174
196
|
'one'
|
|
175
197
|
#'two'
|
|
198
|
+
#'two'
|
|
176
199
|
'three'"
|
|
177
200
|
assert_equal %w[one three], ZIG.parse(doc)
|
|
178
201
|
end
|
|
@@ -191,7 +214,7 @@ describe ZIG do
|
|
|
191
214
|
a: 1
|
|
192
215
|
# TODO: check c
|
|
193
216
|
c: 3"
|
|
194
|
-
assert_raises(
|
|
217
|
+
assert_raises(ZIG::SyntaxError) { ZIG.parse(doc) }
|
|
195
218
|
end
|
|
196
219
|
|
|
197
220
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: zig
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,13 +9,13 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-11-
|
|
12
|
+
date: 2012-11-11 00:00:00.000000000 Z
|
|
13
13
|
dependencies: []
|
|
14
14
|
description: A parser for the ZIG data format.
|
|
15
15
|
email:
|
|
16
16
|
- tim@lossen.de
|
|
17
17
|
executables:
|
|
18
|
-
-
|
|
18
|
+
- zig
|
|
19
19
|
extensions: []
|
|
20
20
|
extra_rdoc_files: []
|
|
21
21
|
files:
|
|
@@ -24,13 +24,14 @@ files:
|
|
|
24
24
|
- LICENSE.txt
|
|
25
25
|
- README.md
|
|
26
26
|
- Rakefile
|
|
27
|
-
- bin/
|
|
27
|
+
- bin/zig
|
|
28
28
|
- data/example.json
|
|
29
29
|
- data/example.zig
|
|
30
30
|
- lib/zig.rb
|
|
31
31
|
- lib/zig/formatter.rb
|
|
32
32
|
- lib/zig/lines.rb
|
|
33
33
|
- lib/zig/parser.rb
|
|
34
|
+
- lib/zig/syntax_error.rb
|
|
34
35
|
- lib/zig/version.rb
|
|
35
36
|
- test/zig_test.rb
|
|
36
37
|
- zig.gemspec
|
|
@@ -54,7 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
54
55
|
version: '0'
|
|
55
56
|
requirements: []
|
|
56
57
|
rubyforge_project:
|
|
57
|
-
rubygems_version: 1.8.
|
|
58
|
+
rubygems_version: 1.8.24
|
|
58
59
|
signing_key:
|
|
59
60
|
specification_version: 3
|
|
60
61
|
summary: A parser for the ZIG data format.
|