zig 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,17 @@
1
+ module ZIG
2
+ class Lines
3
+ attr_reader :current, :num
4
+
5
+ def initialize(file)
6
+ @file, @current, @num = file, file.gets, 1
7
+ end
8
+
9
+ def empty?
10
+ @current.nil?
11
+ end
12
+
13
+ def next
14
+ @current, @num = @file.gets, @num + 1
15
+ end
16
+ end
17
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module ZIG
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -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