zig 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +21 -0
- data/Rakefile +8 -0
- data/bin/format +12 -0
- data/data/example.json +830 -0
- data/data/example.zig +676 -0
- data/lib/zig.rb +21 -0
- data/lib/zig/formatter.rb +45 -0
- data/lib/zig/lines.rb +17 -0
- data/lib/zig/parser.rb +48 -0
- data/lib/zig/version.rb +3 -0
- data/test/zig_test.rb +164 -0
- data/zig.gemspec +19 -0
- metadata +62 -0
data/lib/zig.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "zig/version"
|
2
|
+
require "zig/lines"
|
3
|
+
require "zig/parser"
|
4
|
+
require "zig/formatter"
|
5
|
+
|
6
|
+
require "stringio"
|
7
|
+
|
8
|
+
module ZIG
|
9
|
+
|
10
|
+
def self.parse(string)
|
11
|
+
lines = Lines.new(StringIO.new(string))
|
12
|
+
start = lines.current || raise("cannot parse empty document")
|
13
|
+
lines.next
|
14
|
+
Parser.parse_value(0, lines, start)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.print(data)
|
18
|
+
Formatter.print_value("", data)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class ZIG::Formatter
|
2
|
+
|
3
|
+
INDENT = " " * 2
|
4
|
+
|
5
|
+
def self.print_hash(indent, hash)
|
6
|
+
print "{\n"
|
7
|
+
indent = indent + INDENT
|
8
|
+
hash.each do |key, value|
|
9
|
+
print indent + key.to_s + ": "
|
10
|
+
print_value(indent, value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.print_array(indent, array)
|
15
|
+
print "[\n"
|
16
|
+
indent = indent + INDENT
|
17
|
+
array.each do |v|
|
18
|
+
print indent
|
19
|
+
print_value(indent, v)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.print_multiline_string(indent, string)
|
24
|
+
print "\"\n"
|
25
|
+
indent = indent + INDENT
|
26
|
+
string.split("\n").each do |line|
|
27
|
+
print indent + line.lstrip + "\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.print_value(indent, value)
|
32
|
+
case value
|
33
|
+
when Hash then print_hash(indent, value)
|
34
|
+
when Array then print_array(indent, value)
|
35
|
+
when String
|
36
|
+
if value.include?("\n")
|
37
|
+
print_multiline_string(indent, value)
|
38
|
+
else
|
39
|
+
print "'#{value}'\n"
|
40
|
+
end
|
41
|
+
else print value.inspect + "\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/zig/lines.rb
ADDED
data/lib/zig/parser.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
class ZIG::Parser
|
2
|
+
|
3
|
+
INDENT = 2
|
4
|
+
|
5
|
+
FULL_LINE = /^( *)(.*)$/
|
6
|
+
KEY_VALUE = /^([^:]+):(.*)$/
|
7
|
+
STRING = /^'(.*)'$/
|
8
|
+
INTEGER = /^-?\d+$/
|
9
|
+
FLOAT = /^-?\d+\.\d+([eE][+-]?\d+)?$/
|
10
|
+
|
11
|
+
def self.parse_object(indent, lines, object)
|
12
|
+
loop do
|
13
|
+
return object if lines.empty?
|
14
|
+
spaces, value = lines.current.scan(FULL_LINE).flatten
|
15
|
+
return object if spaces.size < indent
|
16
|
+
raise "[line #{lines.num}] illegal indent" if spaces.size > indent
|
17
|
+
lines.next
|
18
|
+
if object.is_a?(Hash)
|
19
|
+
key, value = value.scan(KEY_VALUE).flatten
|
20
|
+
raise "[line #{lines.num}] missing key" if key.nil?
|
21
|
+
object[key.strip.to_sym] = parse_value(indent, lines, value)
|
22
|
+
elsif object.is_a?(Array)
|
23
|
+
object << parse_value(indent, lines, value)
|
24
|
+
else
|
25
|
+
object << "\n" unless object.empty?
|
26
|
+
object << value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parse_value(indent, lines, text)
|
32
|
+
text = text.strip
|
33
|
+
case text
|
34
|
+
when 'nil' then nil
|
35
|
+
when 'true' then true
|
36
|
+
when 'false' then false
|
37
|
+
when '{' then parse_object(indent + INDENT, lines, {})
|
38
|
+
when '[' then parse_object(indent + INDENT, lines, [])
|
39
|
+
when '"' then parse_object(indent + INDENT, lines, "")
|
40
|
+
when STRING then $1
|
41
|
+
when INTEGER then text.to_i
|
42
|
+
when FLOAT then text.to_f
|
43
|
+
else
|
44
|
+
raise "[line #{lines.num}] illegal value: #{text}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/lib/zig/version.rb
ADDED
data/test/zig_test.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "minitest/autorun"
|
3
|
+
require "zig"
|
4
|
+
|
5
|
+
describe ZIG do
|
6
|
+
|
7
|
+
describe "empty" do
|
8
|
+
it "should reject an empty document" do
|
9
|
+
assert_raises(RuntimeError) { ZIG.parse("") }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "literals" do
|
14
|
+
it "should parse nil" do
|
15
|
+
assert_equal nil, ZIG.parse("nil")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should parse true" do
|
19
|
+
assert_equal true, ZIG.parse("true")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should parse false" do
|
23
|
+
assert_equal false, ZIG.parse("false")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should reject other literals" do
|
27
|
+
assert_raises(RuntimeError) { ZIG.parse("foo") }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "integers" do
|
32
|
+
it "should parse zero" do
|
33
|
+
assert_equal 0, ZIG.parse("0")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should parse positive integers" do
|
37
|
+
assert_equal 7, ZIG.parse("7")
|
38
|
+
assert_equal 23, ZIG.parse("23")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should parse negative integers" do
|
42
|
+
assert_equal -7, ZIG.parse("-7")
|
43
|
+
assert_equal -23, ZIG.parse("-23")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "floats" do
|
48
|
+
it "should parse zero" do
|
49
|
+
assert_equal 0.0, ZIG.parse("0.0")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should parse positive floats" do
|
53
|
+
assert_equal 0.07, ZIG.parse("0.07")
|
54
|
+
assert_equal 23.9, ZIG.parse("23.9")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should parse negative floats" do
|
58
|
+
assert_equal -0.07, ZIG.parse("-0.07")
|
59
|
+
assert_equal -23.9, ZIG.parse("-23.9")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should parse pi" do
|
63
|
+
assert_equal 3.14159265359, ZIG.parse("3.14159265359")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should parse exponential notation" do
|
67
|
+
assert_equal 2.3e-10, ZIG.parse("2.3e-10")
|
68
|
+
assert_equal 2.3e10, ZIG.parse("2.3e+10")
|
69
|
+
assert_equal 2.3e10, ZIG.parse("2.3e10")
|
70
|
+
assert_equal 2.3e10, ZIG.parse("2.3E10")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "strings" do
|
75
|
+
it "should parse simple strings" do
|
76
|
+
assert_equal "foo bar", ZIG.parse("'foo bar'")
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should parse unicode strings" do
|
80
|
+
assert_equal "Übung macht den Meister", ZIG.parse("'Übung macht den Meister'")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "multiline strings" do
|
85
|
+
it "should parse multiline strings" do
|
86
|
+
doc =
|
87
|
+
%{"
|
88
|
+
one house
|
89
|
+
two houses
|
90
|
+
three houses}
|
91
|
+
assert_equal "one house\ntwo houses\nthree houses", ZIG.parse(doc)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
describe "lists" do
|
97
|
+
it "should parse an empty list" do
|
98
|
+
assert_equal [], ZIG.parse("[")
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should parse a list of simple values" do
|
102
|
+
doc =
|
103
|
+
"[
|
104
|
+
1
|
105
|
+
2
|
106
|
+
3"
|
107
|
+
assert_equal [1, 2, 3], ZIG.parse(doc)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should parse a list of complex values" do
|
111
|
+
doc =
|
112
|
+
"[
|
113
|
+
[
|
114
|
+
23
|
115
|
+
42
|
116
|
+
[
|
117
|
+
{
|
118
|
+
a: 1
|
119
|
+
b: 2"
|
120
|
+
assert_equal [[23, 42], [], {a: 1, b: 2}], ZIG.parse(doc)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "hashes" do
|
125
|
+
it "should parse an empty hash" do
|
126
|
+
assert_equal Hash.new, ZIG.parse("{")
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should parse a hash with simple values" do
|
130
|
+
doc =
|
131
|
+
"{
|
132
|
+
a: 1
|
133
|
+
b: 2
|
134
|
+
c: 3"
|
135
|
+
assert_equal Hash[a: 1, b: 2, c: 3], ZIG.parse(doc)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should parse a hash with complex values" do
|
139
|
+
doc =
|
140
|
+
"{
|
141
|
+
x: {
|
142
|
+
a: 1
|
143
|
+
b: 2
|
144
|
+
y: {
|
145
|
+
z: [
|
146
|
+
true
|
147
|
+
false"
|
148
|
+
assert_equal Hash[x: {a: 1, b: 2}, y: {}, z: [true, false]], ZIG.parse(doc)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should reject empty keys" do
|
152
|
+
doc =
|
153
|
+
"{
|
154
|
+
a: 1
|
155
|
+
: 2
|
156
|
+
c: 3"
|
157
|
+
assert_raises(RuntimeError) { ZIG.parse(doc) }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "comments" do
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
data/zig.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'zig/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "zig"
|
8
|
+
gem.version = ZIG::VERSION
|
9
|
+
gem.authors = ["Tim Lossen"]
|
10
|
+
gem.email = ["tim@lossen.de"]
|
11
|
+
gem.description = %q{A parser for the ZIG data format.}
|
12
|
+
gem.summary = %q{A parser for the ZIG data format.}
|
13
|
+
gem.homepage = "https://github.com/tlossen/zig"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^test/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zig
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tim Lossen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-07 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A parser for the ZIG data format.
|
15
|
+
email:
|
16
|
+
- tim@lossen.de
|
17
|
+
executables:
|
18
|
+
- format
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- Gemfile
|
24
|
+
- LICENSE.txt
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- bin/format
|
28
|
+
- data/example.json
|
29
|
+
- data/example.zig
|
30
|
+
- lib/zig.rb
|
31
|
+
- lib/zig/formatter.rb
|
32
|
+
- lib/zig/lines.rb
|
33
|
+
- lib/zig/parser.rb
|
34
|
+
- lib/zig/version.rb
|
35
|
+
- test/zig_test.rb
|
36
|
+
- zig.gemspec
|
37
|
+
homepage: https://github.com/tlossen/zig
|
38
|
+
licenses: []
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.8.24
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: A parser for the ZIG data format.
|
61
|
+
test_files:
|
62
|
+
- test/zig_test.rb
|