zig 0.0.1

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.
@@ -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