json-expect-parser 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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +202 -0
- data/Rakefile +6 -0
- data/benchmark/comparison.rb +47 -0
- data/example/pipe.rb +26 -0
- data/example/simple.rb +38 -0
- data/example/stdin.rb +8 -0
- data/example/string.rb +10 -0
- data/json-expect-parser.gemspec +25 -0
- data/lib/json/expect/parser.rb +350 -0
- data/lib/json/expect/parser/version.rb +7 -0
- data/mrbgem.rake +8 -0
- data/mrblib +1 -0
- data/test/parser.rb +12 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3a6dda865f0de7159d92fba2db57f98f9220bb68
|
4
|
+
data.tar.gz: aec146fb010f935f35b1ab79a3caa1cf7b2c4bab
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f734a7edd681dd9a15ce6d65bfe0464dc693ef9594a541d039bd364d5c6dced4639a168734f4b8f881e426c7c162325dc7250c77ed1e11061aebdd226e57bd6
|
7
|
+
data.tar.gz: 4fbdeaffdfa23c1829459f6fe086554dd7ef87cc76e492c3c6c18c7cbef9ac3f02653267835efdadad30d7feb22681de734695177105028048dca344ecac90aa
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 ksss
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
json-expect-parser
|
2
|
+
===
|
3
|
+
|
4
|
+
An alternative JSON parser.
|
5
|
+
|
6
|
+
## Synopsis
|
7
|
+
|
8
|
+
t.json
|
9
|
+
|
10
|
+
```json
|
11
|
+
[
|
12
|
+
{
|
13
|
+
"id": 1,
|
14
|
+
"name": "ksss",
|
15
|
+
"admin": true
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"id": 2,
|
19
|
+
"name": "foo",
|
20
|
+
"admin": false
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"id": 3,
|
24
|
+
"name": "bar",
|
25
|
+
"admin": false
|
26
|
+
}
|
27
|
+
]
|
28
|
+
```
|
29
|
+
|
30
|
+
```rb
|
31
|
+
require 'json/expect/parser'
|
32
|
+
|
33
|
+
File.open("t.json") do |io|
|
34
|
+
expect = JSON::Expect::Parser.new(io)
|
35
|
+
expect.array do
|
36
|
+
expect.object do
|
37
|
+
case expect.key
|
38
|
+
when "id"
|
39
|
+
p expect.integer #=> 1, 2, 3
|
40
|
+
when "name"
|
41
|
+
p expect.string #=> "ksss", "foo", "bar"
|
42
|
+
when "admin"
|
43
|
+
p expect.boolean #=> true, false, false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
## Explicitly parse
|
51
|
+
|
52
|
+
json-expect-parser parse JSON explicitly.
|
53
|
+
|
54
|
+
```rb
|
55
|
+
expect = JSON::Expect::Parser.new(%([10, 20, 30]))
|
56
|
+
expect.array { p expect.integer } #=> 10, 20, 30
|
57
|
+
```
|
58
|
+
|
59
|
+
If get unexpected value, It failed.
|
60
|
+
|
61
|
+
```rb
|
62
|
+
expect = JSON::Expect::Parser.new(%([10, 20, 30]))
|
63
|
+
expect.array { p expect.string }
|
64
|
+
#=> JSON::Expect::ParseError: expected "\"" but was "1"
|
65
|
+
```
|
66
|
+
|
67
|
+
## API
|
68
|
+
|
69
|
+
### object
|
70
|
+
|
71
|
+
```rb
|
72
|
+
expect = JSON::Expect::Parser.new(%({"a": 10, "b": 20}))
|
73
|
+
|
74
|
+
expect.object
|
75
|
+
#=> #<Enumerator: #<JSON::Expect::Parser ...>>
|
76
|
+
|
77
|
+
expect.object do
|
78
|
+
expect.key #=> "a", "b"
|
79
|
+
expect.integer #=> 10, 20
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
### array
|
84
|
+
|
85
|
+
```rb
|
86
|
+
expect = JSON::Expect::Parser.new(%(["foo", "bar", "baz"]))
|
87
|
+
|
88
|
+
expect.array
|
89
|
+
#=> #<Enumerator: #<JSON::Expect::Parser ...>>
|
90
|
+
|
91
|
+
expect.array do
|
92
|
+
expect.string #=> "foo", "bar", "baz"
|
93
|
+
end
|
94
|
+
|
95
|
+
expect.rewind
|
96
|
+
|
97
|
+
expect.array.map { expect.string }
|
98
|
+
#=> ["foo", "bar", "baz"]
|
99
|
+
```
|
100
|
+
|
101
|
+
### integer
|
102
|
+
|
103
|
+
```rb
|
104
|
+
expect = JSON::Expect::Parser.new(%(100))
|
105
|
+
expect.integer #=> 100
|
106
|
+
```
|
107
|
+
|
108
|
+
### number(alias float)
|
109
|
+
|
110
|
+
```rb
|
111
|
+
expect = JSON::Expect::Parser.new(%(1.1))
|
112
|
+
expect.float #=> 1.1
|
113
|
+
```
|
114
|
+
|
115
|
+
### string
|
116
|
+
|
117
|
+
```rb
|
118
|
+
expect = JSON::Expect::Parser.new(%("foo"))
|
119
|
+
expect.string #=> "foo"
|
120
|
+
```
|
121
|
+
|
122
|
+
### key
|
123
|
+
|
124
|
+
Use in `object` then get object key string
|
125
|
+
|
126
|
+
### boolean
|
127
|
+
|
128
|
+
```rb
|
129
|
+
expect = JSON::Expect::Parser.new(%("true"))
|
130
|
+
expect.boolean #=> true
|
131
|
+
```
|
132
|
+
|
133
|
+
### null
|
134
|
+
|
135
|
+
```rb
|
136
|
+
expect = JSON::Expect::Parser.new(%("null"))
|
137
|
+
expect.null #=> nil
|
138
|
+
```
|
139
|
+
|
140
|
+
### object_or_null
|
141
|
+
|
142
|
+
```rb
|
143
|
+
expect = JSON::Expect::Parser.new(%([{"a": 1}, null]))
|
144
|
+
expect.array do
|
145
|
+
expect.object_or_null do
|
146
|
+
expect.key #=> "a"
|
147
|
+
expect.integer #=> 1
|
148
|
+
end
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
152
|
+
### array_or_null
|
153
|
+
|
154
|
+
```rb
|
155
|
+
expect = JSON::Expect::Parser.new(%([[1, 2, 3], null]))
|
156
|
+
expect.array do
|
157
|
+
expect.array_or_null do
|
158
|
+
expect.integer #=> 1, 2, 3
|
159
|
+
end
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
### null_or
|
164
|
+
|
165
|
+
```rb
|
166
|
+
expect = JSON::Expect::Parser.new(%({"a": "foo", "b": null}))
|
167
|
+
expect.object do
|
168
|
+
expect.key #=> "a", "b"
|
169
|
+
expect.null_or { expect.string } #=> "foo", nil
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
### value(alias parse)
|
174
|
+
|
175
|
+
```rb
|
176
|
+
expect = JSON::Expect::Parser.new(%([[true, false], null, 1, "foo"]))
|
177
|
+
expect.value
|
178
|
+
#=> [[true, false], nil, 1.0, "foo"]
|
179
|
+
```
|
180
|
+
|
181
|
+
### rewind
|
182
|
+
|
183
|
+
```rb
|
184
|
+
expect = JSON::Expect::Parser.new(%("foo"))
|
185
|
+
expect.string #=> "foo"
|
186
|
+
expect.string #=> "foo"
|
187
|
+
#=> JSON::Expect::ParseError: expected "\"" but was nil
|
188
|
+
expect.rewind
|
189
|
+
expect.string #=> "foo"
|
190
|
+
```
|
191
|
+
|
192
|
+
# Benchmark
|
193
|
+
|
194
|
+
```
|
195
|
+
8320.0kb
|
196
|
+
38420.0kb
|
197
|
+
ruby t.rb 0.19s user 0.06s system 98% cpu 0.257 total
|
198
|
+
|
199
|
+
8124.0kb
|
200
|
+
10732.0kb
|
201
|
+
ruby j.rb 0.83s user 0.06s system 99% cpu 0.891 total
|
202
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
require 'get_process_mem'
|
5
|
+
require 'json/pure/parser'
|
6
|
+
require 'json/ext/parser'
|
7
|
+
require 'json/expect/parser'
|
8
|
+
|
9
|
+
puts "ruby v#{RUBY_VERSION}"
|
10
|
+
puts `uname -v`
|
11
|
+
|
12
|
+
b = []
|
13
|
+
30000.times do
|
14
|
+
b << %({"abcdefg": 123456, "hijklmn": "fooooooooooooooo", "opqrstu": -123.456})
|
15
|
+
end
|
16
|
+
json = "[#{b.join(",")}]"
|
17
|
+
puts "#{json.length / 1024}KB json string"
|
18
|
+
|
19
|
+
puts
|
20
|
+
|
21
|
+
[
|
22
|
+
['JSON::Ext::Parser', -> { JSON::Ext::Parser.new(json).parse }],
|
23
|
+
['JSON::Pure::Parser', -> { JSON::Pure::Parser.new(json).parse }],
|
24
|
+
['JSON::Expect::Parser', -> {
|
25
|
+
e = JSON::Expect::Parser.new(json)
|
26
|
+
e.array do
|
27
|
+
e.object do
|
28
|
+
e.key
|
29
|
+
e.integer
|
30
|
+
e.key
|
31
|
+
e.string
|
32
|
+
e.key
|
33
|
+
e.float
|
34
|
+
end
|
35
|
+
end
|
36
|
+
}],
|
37
|
+
].each do |name, proc|
|
38
|
+
GC.start
|
39
|
+
Process.wait fork {
|
40
|
+
puts "=== #{name} ==="
|
41
|
+
mem = GetProcessMem.new.kb
|
42
|
+
print "time: "
|
43
|
+
puts Benchmark.realtime(&proc)
|
44
|
+
puts "memory: #{GetProcessMem.new.kb - mem}KB"
|
45
|
+
puts
|
46
|
+
}
|
47
|
+
end
|
data/example/pipe.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'json/expect/parser'
|
3
|
+
|
4
|
+
IO.pipe do |r, w|
|
5
|
+
t = Thread.new do
|
6
|
+
expect = JSON::Expect::Parser.new(r, buffer_size: 1)
|
7
|
+
expect.array do
|
8
|
+
puts expect.integer
|
9
|
+
end
|
10
|
+
end
|
11
|
+
w.write "["
|
12
|
+
w.write "10,"
|
13
|
+
sleep 1
|
14
|
+
w.write "20,"
|
15
|
+
sleep 1
|
16
|
+
w.write "30"
|
17
|
+
sleep 1
|
18
|
+
w.write "]"
|
19
|
+
w.close
|
20
|
+
t.join
|
21
|
+
end
|
22
|
+
__END__
|
23
|
+
$ bundle ex ruby example/pipe.rb
|
24
|
+
10
|
25
|
+
20
|
26
|
+
30
|
data/example/simple.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'json/expect/parser'
|
3
|
+
|
4
|
+
values = []
|
5
|
+
expect = JSON::Expect::Parser.new(DATA)
|
6
|
+
expect.array do
|
7
|
+
expect.object do
|
8
|
+
case expect.key
|
9
|
+
when "id"
|
10
|
+
values << expect.integer
|
11
|
+
when "name"
|
12
|
+
values << expect.string
|
13
|
+
when "admin"
|
14
|
+
values << expect.boolean
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
p values
|
19
|
+
# $ bundle ex ruby example/simple.rb
|
20
|
+
# [1, "ksss", true, 2, "foo", false, 3, "bar", false]
|
21
|
+
__END__
|
22
|
+
[
|
23
|
+
{
|
24
|
+
"id": 1,
|
25
|
+
"name": "ksss",
|
26
|
+
"admin": true
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"id": 2,
|
30
|
+
"name": "foo",
|
31
|
+
"admin": false
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"id": 3,
|
35
|
+
"name": "bar",
|
36
|
+
"admin": false
|
37
|
+
}
|
38
|
+
]
|
data/example/stdin.rb
ADDED
data/example/string.rb
ADDED
@@ -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
|
+
require 'json/expect/parser/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "json-expect-parser"
|
8
|
+
spec.version = JSON::Expect::Parser::VERSION
|
9
|
+
spec.authors = ["ksss"]
|
10
|
+
spec.email = ["co000ri@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "JSON expect parser"
|
13
|
+
spec.description = "An alternative JSON parser"
|
14
|
+
spec.homepage = "https://github.com/ksss/json-expect-parser"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{_test.rb}) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "json"
|
21
|
+
spec.add_development_dependency "get_process_mem"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rgot"
|
25
|
+
end
|
@@ -0,0 +1,350 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
module Expect
|
5
|
+
ParseError = Class.new(StandardError)
|
6
|
+
class Buffer
|
7
|
+
def initialize(input, size)
|
8
|
+
unless 0 < size
|
9
|
+
raise ArgumentError, "negative buffer_size"
|
10
|
+
end
|
11
|
+
@io = case input
|
12
|
+
when String
|
13
|
+
StringIO.new(input)
|
14
|
+
when IO, StringIO
|
15
|
+
input
|
16
|
+
else
|
17
|
+
raise ArgumentError, "#{input.class} is not supported"
|
18
|
+
end
|
19
|
+
@string = String.new
|
20
|
+
@index = 0
|
21
|
+
@size = size
|
22
|
+
end
|
23
|
+
|
24
|
+
def fetch(len = 0)
|
25
|
+
if str = @io.read(@size + len)
|
26
|
+
@string = @string[@index..-1] << str
|
27
|
+
@index = 0
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def next(len = 1)
|
34
|
+
if @string.length - @index < len
|
35
|
+
if str = @io.read(@size + len)
|
36
|
+
@string = @string[@index..-1] << str
|
37
|
+
@index = 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
if @string.length <= @index
|
42
|
+
nil
|
43
|
+
else
|
44
|
+
r = @string[@index, len]
|
45
|
+
@index += r.length
|
46
|
+
r
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def back(len = 1)
|
51
|
+
@index -= len
|
52
|
+
end
|
53
|
+
|
54
|
+
def scan(regexp)
|
55
|
+
if m = regexp.match(@string, @index)
|
56
|
+
@index += m[0].length
|
57
|
+
m[0]
|
58
|
+
else
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def next_without_whitespace
|
64
|
+
while ch = self.next
|
65
|
+
case ch
|
66
|
+
when " ", "\t", "\n", "\r"
|
67
|
+
else
|
68
|
+
return ch
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def rewind
|
74
|
+
@string.clear
|
75
|
+
@index = 0
|
76
|
+
@io.rewind
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class Parser
|
81
|
+
NUM_FIRST = /\A-|\d/
|
82
|
+
# from json/pure
|
83
|
+
STRING = /"(?:[^\x0-\x1f"\\] |
|
84
|
+
# escaped special characters:
|
85
|
+
\\["\\\/bfnrt] |
|
86
|
+
\\u[0-9a-fA-F]{4} |
|
87
|
+
# match all but escaped special characters:
|
88
|
+
\\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*
|
89
|
+
"/nx
|
90
|
+
INTEGER = /\A-?0|-?[1-9]\d*/
|
91
|
+
FLOAT = /\A-?
|
92
|
+
(?:0|[1-9]\d*)
|
93
|
+
(?:
|
94
|
+
\.\d+(?i:e[+-]?\d+) |
|
95
|
+
\.\d+ |
|
96
|
+
(?i:e[+-]?\d+)
|
97
|
+
)?
|
98
|
+
/x
|
99
|
+
|
100
|
+
def initialize(input, opts = {})
|
101
|
+
buffer_size = if opts[:buffer_size]
|
102
|
+
opts[:buffer_size]
|
103
|
+
else
|
104
|
+
4092
|
105
|
+
end
|
106
|
+
@count_stack = []
|
107
|
+
@buffer = Buffer.new(input, buffer_size)
|
108
|
+
end
|
109
|
+
|
110
|
+
def object
|
111
|
+
return to_enum(:object) unless block_given?
|
112
|
+
|
113
|
+
expect_char("{")
|
114
|
+
count_up
|
115
|
+
@count_stack.push(0)
|
116
|
+
while true
|
117
|
+
case ch = @buffer.next_without_whitespace
|
118
|
+
when "}"
|
119
|
+
check_tail
|
120
|
+
break @count_stack.pop
|
121
|
+
when "\""
|
122
|
+
@buffer.back(ch.length)
|
123
|
+
before_count = current_count
|
124
|
+
yield
|
125
|
+
raise ParseError, "nothing expectation in block" unless before_count != current_count
|
126
|
+
check_tail
|
127
|
+
else
|
128
|
+
raise ParseError, "expected \"}\" or \"\"\" but was #{ch.inspect}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def array
|
134
|
+
return to_enum(:array) unless block_given?
|
135
|
+
|
136
|
+
expect_char("[")
|
137
|
+
count_up
|
138
|
+
@count_stack.push(0)
|
139
|
+
while true
|
140
|
+
case ch = @buffer.next_without_whitespace
|
141
|
+
when "]"
|
142
|
+
check_tail
|
143
|
+
break @count_stack.pop
|
144
|
+
when nil
|
145
|
+
raise ParseError, "expected any array item but EOF"
|
146
|
+
else
|
147
|
+
@buffer.back(ch.length)
|
148
|
+
before_count = current_count
|
149
|
+
yield
|
150
|
+
raise ParseError, "nothing expectation in block" unless before_count != current_count
|
151
|
+
check_tail
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def key
|
157
|
+
expect_char("\"")
|
158
|
+
@buffer.back
|
159
|
+
until m = @buffer.scan(STRING)
|
160
|
+
if @buffer.fetch.nil?
|
161
|
+
raise ParseError, "expected \"\"\" but was EOF"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
expect_char(":")
|
165
|
+
m[1..-2]
|
166
|
+
end
|
167
|
+
|
168
|
+
def string
|
169
|
+
expect_char("\"")
|
170
|
+
@buffer.back
|
171
|
+
until m = @buffer.scan(STRING)
|
172
|
+
if @buffer.fetch.nil?
|
173
|
+
raise ParseError, "expected \"\"\" but was EOF"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
count_up
|
177
|
+
check_tail
|
178
|
+
m[1..-2]
|
179
|
+
end
|
180
|
+
|
181
|
+
def integer
|
182
|
+
buffer = @buffer.next_without_whitespace
|
183
|
+
if NUM_FIRST =~ buffer
|
184
|
+
i = @buffer.next(16)
|
185
|
+
buffer << i if i
|
186
|
+
while m = INTEGER.match(buffer)
|
187
|
+
break if m[0].length != buffer.length
|
188
|
+
i = @buffer.next(16)
|
189
|
+
break unless i
|
190
|
+
buffer << i
|
191
|
+
end
|
192
|
+
raise ParseError, "expected integer but was #{buffer.inspect}" unless m
|
193
|
+
@buffer.back(buffer.length - m[0].length)
|
194
|
+
count_up
|
195
|
+
check_tail
|
196
|
+
m[0].to_i
|
197
|
+
else
|
198
|
+
raise ParseError, "expected integer but was #{buffer.inspect}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def number
|
203
|
+
buffer = @buffer.next_without_whitespace
|
204
|
+
if NUM_FIRST =~ buffer
|
205
|
+
i = @buffer.next(16)
|
206
|
+
buffer << i if i
|
207
|
+
if buffer[-1] == "."
|
208
|
+
i = @buffer.next(16)
|
209
|
+
raise ParseError, "expected number after \".\" but nothing" unless i
|
210
|
+
buffer << i
|
211
|
+
end
|
212
|
+
while m = FLOAT.match(buffer)
|
213
|
+
break if m[0].length != buffer.length
|
214
|
+
i = @buffer.next(16)
|
215
|
+
break unless i
|
216
|
+
buffer << i
|
217
|
+
end
|
218
|
+
raise ParseError, "expected number but was #{buffer.inspect}" unless m
|
219
|
+
@buffer.back(buffer.length - m[0].length)
|
220
|
+
count_up
|
221
|
+
check_tail
|
222
|
+
m[0].to_f
|
223
|
+
else
|
224
|
+
raise ParseError, "expected number but was #{buffer.inspect}"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
alias float number
|
228
|
+
|
229
|
+
def boolean
|
230
|
+
case ch = @buffer.next_without_whitespace
|
231
|
+
when "t"
|
232
|
+
if "rue" == (rue = @buffer.next(3))
|
233
|
+
count_up
|
234
|
+
check_tail
|
235
|
+
true
|
236
|
+
else
|
237
|
+
raise ParseError, "expected true or false but was \"#{ch}#{rue}\""
|
238
|
+
end
|
239
|
+
when "f"
|
240
|
+
if "alse" == (alse = @buffer.next(4))
|
241
|
+
count_up
|
242
|
+
check_tail
|
243
|
+
false
|
244
|
+
else
|
245
|
+
raise ParseError, "expected true or false but was \"#{ch}#{alse}\""
|
246
|
+
end
|
247
|
+
else
|
248
|
+
raise ParseError, "expected true or false but was \"#{ch}\""
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def null
|
253
|
+
case ch = @buffer.next_without_whitespace
|
254
|
+
when "n"
|
255
|
+
if "ull" == (ull = @buffer.next(3))
|
256
|
+
count_up
|
257
|
+
check_tail
|
258
|
+
nil
|
259
|
+
else
|
260
|
+
raise ParseError, "expected null but was \"#{ch}#{ull}\""
|
261
|
+
end
|
262
|
+
else
|
263
|
+
raise ParseError, "expected null but was #{ch.inspect}"
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def object_or_null
|
268
|
+
null_or { object { yield } }
|
269
|
+
end
|
270
|
+
|
271
|
+
def array_or_null
|
272
|
+
null_or { array { yield } }
|
273
|
+
end
|
274
|
+
|
275
|
+
def null_or
|
276
|
+
ch = @buffer.next_without_whitespace
|
277
|
+
@buffer.back
|
278
|
+
if ch == 'n'
|
279
|
+
null
|
280
|
+
else
|
281
|
+
yield
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def value
|
286
|
+
ch = @buffer.next_without_whitespace
|
287
|
+
@buffer.back
|
288
|
+
case ch
|
289
|
+
when "["
|
290
|
+
array.map { value }
|
291
|
+
when "{"
|
292
|
+
Hash[object.map { [key, value] }]
|
293
|
+
when "n"
|
294
|
+
null
|
295
|
+
when "t", "f"
|
296
|
+
boolean
|
297
|
+
when "\""
|
298
|
+
string
|
299
|
+
when NUM_FIRST
|
300
|
+
number
|
301
|
+
else
|
302
|
+
raise ParseError, "expected any value but was #{ch.inspect}"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
alias parse value
|
306
|
+
|
307
|
+
def rewind
|
308
|
+
@buffer.rewind
|
309
|
+
end
|
310
|
+
|
311
|
+
private
|
312
|
+
|
313
|
+
def count_up
|
314
|
+
if !@count_stack.empty?
|
315
|
+
@count_stack[-1] += 1
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def current_count
|
320
|
+
@count_stack[-1]
|
321
|
+
end
|
322
|
+
|
323
|
+
def check_tail
|
324
|
+
case ch = @buffer.next_without_whitespace
|
325
|
+
when ","
|
326
|
+
raise ParseError, "unexpected \",\"" if @count_stack.empty?
|
327
|
+
ch = @buffer.next_without_whitespace
|
328
|
+
raise ParseError, "expected next token but was EOF" unless ch
|
329
|
+
case ch
|
330
|
+
when "]", "}", ","
|
331
|
+
raise ParseError, "expected next token but was #{ch.inspect}"
|
332
|
+
else
|
333
|
+
@buffer.back
|
334
|
+
end
|
335
|
+
when nil
|
336
|
+
else
|
337
|
+
@buffer.back
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def expect_char(expect)
|
342
|
+
actual = @buffer.next_without_whitespace
|
343
|
+
unless actual == expect
|
344
|
+
raise ParseError, "expected #{expect.inspect} but was #{actual.inspect}"
|
345
|
+
end
|
346
|
+
actual
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
data/mrbgem.rake
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
MRuby::Gem::Specification.new('json-expect-parser') do |spec|
|
2
|
+
spec.license = 'MIT'
|
3
|
+
spec.author = 'mruby developers'
|
4
|
+
spec.summary = 'A JSON Parser'
|
5
|
+
spec.add_dependency('mruby-string-ext', core: 'mruby-string-ext')
|
6
|
+
spec.add_dependency('mruby-stringio')
|
7
|
+
spec.add_dependency('mruby-onig-regexp')
|
8
|
+
end
|
data/mrblib
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
lib
|
data/test/parser.rb
ADDED
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json-expect-parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ksss
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-08-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: get_process_mem
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.11'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.11'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rgot
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: An alternative JSON parser
|
84
|
+
email:
|
85
|
+
- co000ri@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- Gemfile
|
92
|
+
- LICENSE.txt
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- benchmark/comparison.rb
|
96
|
+
- example/pipe.rb
|
97
|
+
- example/simple.rb
|
98
|
+
- example/stdin.rb
|
99
|
+
- example/string.rb
|
100
|
+
- json-expect-parser.gemspec
|
101
|
+
- lib/json/expect/parser.rb
|
102
|
+
- lib/json/expect/parser/version.rb
|
103
|
+
- mrbgem.rake
|
104
|
+
- mrblib
|
105
|
+
- test/parser.rb
|
106
|
+
homepage: https://github.com/ksss/json-expect-parser
|
107
|
+
licenses:
|
108
|
+
- MIT
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.5.1
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: JSON expect parser
|
130
|
+
test_files: []
|