json-next 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a4bc912a3a1cfbfee8f003ec071192735ec5f638
4
+ data.tar.gz: 493c00f3d34dc0c3f868f28d52e254b07686b4c5
5
+ SHA512:
6
+ metadata.gz: 717d9c8b9bdc8f63fb8abbc2de0e76b6d1355bb17edf30702c61449ff5ce9f739d1f9f3bac5c11eeb169d2488a04ef17f9624c63fdb1e614d713ab7bbdb19b1a
7
+ data.tar.gz: a57f3d1a612907827b3ae7decbff6bd55d963f214499a551fe166d6a427029d02f5a0ceee7b28ded0ee269a31282b14ca731beae9f007174ae6f7197626f1cb2
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2017-07-06
2
+
3
+ * Everything is new. First release.
@@ -0,0 +1,15 @@
1
+ HISTORY.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/json/next.rb
6
+ lib/json/next/commata.rb
7
+ lib/json/next/parser/hanson.rb
8
+ lib/json/next/parser/son.rb
9
+ lib/json/next/pattern.rb
10
+ lib/json/next/version.rb
11
+ test/helper.rb
12
+ test/test_commata.rb
13
+ test/test_parser_hanson.rb
14
+ test/test_parser_son.rb
15
+ test/test_version.rb
@@ -0,0 +1,256 @@
1
+ # jasony
2
+
3
+ jasony gem - read generation y / next generation json versions (HanSON, SON, etc.) with comments, unquoted keys, multi-line strings, trailing commas, optional commas, and more
4
+
5
+
6
+ * home :: [github.com/datatxt/jasony](https://github.com/datatxt/jasony)
7
+ * bugs :: [github.com/datatxt/jasony/issues](https://github.com/datatxt/jasony/issues)
8
+ * gem :: [rubygems.org/gems/jasony](https://rubygems.org/gems/jasony)
9
+ * rdoc :: [rubydoc.info/gems/jasony](http://rubydoc.info/gems/jasony)
10
+
11
+
12
+
13
+
14
+ ## Usage - `HANSON.parse`, `SON.parse`
15
+
16
+ [HanSON](#hanson) •
17
+ [SON](#son)
18
+
19
+
20
+ ### HanSON
21
+
22
+ _HanSON - JSON for Humans by Tim Jansen et al_
23
+
24
+ HanSON is an extension of JSON with a few simple additions to the spec:
25
+
26
+ - quotes for strings are optional if they follow JavaScript identifier rules.
27
+ - you can alternatively use backticks, as in ES6's template string literal, as quotes for strings.
28
+ A backtick-quoted string may span several lines and you are not required to escape regular quote characters,
29
+ only backticks. Backslashes still need to be escaped, and all other backslash-escape sequences work like in
30
+ regular JSON.
31
+ - for single-line strings, single quotes (`''`) are supported in addition to double quotes (`""`)
32
+ - you can use JavaScript comments, both single line (`//`) and multi-line comments (`/* */`), in all places where JSON allows whitespace.
33
+ - Commas after the last list element or object property will be ignored.
34
+
35
+
36
+ Example:
37
+
38
+ ``` js
39
+ {
40
+ listName: "Sesame Street Monsters", // note that listName needs no quotes
41
+ content: [
42
+ {
43
+ name: "Cookie Monster",
44
+ /* Note the template quotes and unescaped regular quotes in the next string */
45
+ background: `Cookie Monster used to be a
46
+ monster that ate everything, especially cookies.
47
+ These days he is forced to eat "healthy" food.`
48
+ }, {
49
+ // You can single-quote strings too:
50
+ name: 'Herry Monster',
51
+ background: `Herry Monster is a furry blue monster with a purple nose.
52
+ He's mostly retired today.`
53
+ }, // don't worry, the trailing comma will be ignored
54
+ ]
55
+ }
56
+ ```
57
+
58
+ Use `HANSON.convert` to convert HanSON text to ye old' JSON text:
59
+
60
+ ``` json
61
+ {
62
+ "listName": "Sesame Street Monsters",
63
+ "content": [
64
+ { "name": "Cookie Monster",
65
+ "background": "Cookie Monster used to be a\n ... to eat \"healthy\" food."
66
+ },
67
+ { "name": "Herry Monster",
68
+ "background": "Herry Monster is a furry blue monster with a purple nose.\n ... today."
69
+ }
70
+ ]
71
+ }
72
+ ```
73
+
74
+ Use `HANSON.parse` instead of `JSON.parse` to parse text to ruby hash / array / etc.:
75
+
76
+ ``` ruby
77
+ {
78
+ "listName" => "Sesame Street Monsters",
79
+ "content" => [
80
+ { "name" => "Cookie Monster",
81
+ "background" => "Cookie Monster used to be a\n ... to eat \"healthy\" food."
82
+ },
83
+ { "name" => "Herry Monster",
84
+ "background" => "Herry Monster is a furry blue monster with a purple nose.\n ... today."
85
+ }
86
+ ]
87
+ }
88
+ ```
89
+
90
+
91
+
92
+ ### SON
93
+
94
+ _SON - Simple Object Notation by Aleksander Gurin et al_
95
+
96
+ Simple data format similar to JSON, but with some minor changes:
97
+
98
+ - comments starts with `#` sign and ends with newline (`\n`)
99
+ - comma after an object key-value pair is optional
100
+ - comma after an array item is optional
101
+
102
+ JSON is compatible with SON in a sense that
103
+ JSON data is also SON data, but not vise versa.
104
+
105
+ Example:
106
+
107
+ ```
108
+ {
109
+ # Personal information
110
+
111
+ "name": "Alexander Grothendieck"
112
+ "fields": "mathematics"
113
+ "main_topics": [
114
+ "Etale cohomology"
115
+ "Motives"
116
+ "Topos theory"
117
+ "Schemes"
118
+ ]
119
+ "numbers": [1 2 3 4]
120
+ "mixed": [1.1 -2 true false null]
121
+ }
122
+ ```
123
+
124
+ Use `SON.convert` to convert SON text to ye old' JSON text:
125
+
126
+ ``` json
127
+ {
128
+ "name": "Alexander Grothendieck",
129
+ "fields": "mathematics",
130
+ "main_topics": [
131
+ "Etale cohomology",
132
+ "Motives",
133
+ "Topos theory",
134
+ "Schemes"
135
+ ],
136
+ "numbers": [1, 2, 3, 4],
137
+ "mixed": [1.1, -2, true, false, null]
138
+ }
139
+ ```
140
+
141
+ Use `SON.parse` instead of `JSON.parse` to parse text to ruby hash / array / etc.:
142
+
143
+ ``` ruby
144
+
145
+ {
146
+ "name" => "Alexander Grothendieck",
147
+ "fields" => "mathematics",
148
+ "main_topics" =>
149
+ ["Etale cohomology", "Motives", "Topos theory", "Schemes"],
150
+ "numbers" => [1, 2, 3, 4],
151
+ "mixed" => [1.1, -2, true, false, nil]
152
+ }
153
+ ```
154
+
155
+
156
+
157
+ ### Live Examples
158
+
159
+
160
+ ``` ruby
161
+ require 'jasony'
162
+
163
+ text1 =<<TXT
164
+ {
165
+ listName: "Sesame Street Monsters", // note that listName needs no quotes
166
+ content: [
167
+ {
168
+ name: "Cookie Monster",
169
+ /* Note the template quotes and unescaped regular quotes in the next string */
170
+ background: `Cookie Monster used to be a
171
+ monster that ate everything, especially cookies.
172
+ These days he is forced to eat "healthy" food.`
173
+ }, {
174
+ // You can single-quote strings too:
175
+ name: 'Herry Monster',
176
+ background: `Herry Monster is a furry blue monster with a purple nose.
177
+ He's mostly retired today.`
178
+ }, // don't worry, the trailing comma will be ignored
179
+ ]
180
+ }
181
+ TXT
182
+
183
+ pp HANSON.parse( text1 ) # note: is the same as JSON.parse( HANSON.convert( text ))
184
+ ```
185
+
186
+ resulting in:
187
+
188
+ ``` ruby
189
+ {
190
+ "listName" => "Sesame Street Monsters",
191
+ "content" => [
192
+ { "name" => "Cookie Monster",
193
+ "background" => "Cookie Monster used to be a\n ... to eat \"healthy\" food."
194
+ },
195
+ { "name" => "Herry Monster",
196
+ "background" => "Herry Monster is a furry blue monster with a purple nose.\n ... today."
197
+ }
198
+ ]
199
+ }
200
+ ```
201
+
202
+ and
203
+
204
+ ``` ruby
205
+
206
+ text2 =<<TXT
207
+ {
208
+ # Personal information
209
+
210
+ "name": "Alexander Grothendieck"
211
+ "fields": "mathematics"
212
+ "main_topics": [
213
+ "Etale cohomology"
214
+ "Motives"
215
+ "Topos theory"
216
+ "Schemes"
217
+ ]
218
+ "numbers": [1 2 3 4]
219
+ "mixed": [1.1 -2 true false null]
220
+ }
221
+ TXT
222
+
223
+ pp SON.parse( text2 ) # note: is the same as JSON.parse( SON.convert( text ))
224
+ ```
225
+
226
+ resulting in:
227
+
228
+ ``` ruby
229
+ {
230
+ "name" => "Alexander Grothendieck",
231
+ "fields" => "mathematics",
232
+ "main_topics" =>
233
+ ["Etale cohomology", "Motives", "Topos theory", "Schemes"],
234
+ "numbers" => [1, 2, 3, 4],
235
+ "mixed" => [1.1, -2, true, false, nil]
236
+ }
237
+ ```
238
+
239
+
240
+
241
+ ## More JSON Formats
242
+
243
+ See the [Awesome JSON (What's Next?)](https://github.com/datatxt/awesome-json-next) collection / page.
244
+
245
+
246
+
247
+ ## License
248
+
249
+ ![](https://publicdomainworks.github.io/buttons/zero88x31.png)
250
+
251
+ The `jasony` scripts are dedicated to the public domain.
252
+ Use it as you please with no restrictions whatsoever.
253
+
254
+ ## Questions? Comments?
255
+
256
+ Post them to the [wwwmake forum](http://groups.google.com/group/wwwmake). Thanks!
@@ -0,0 +1,26 @@
1
+ require 'hoe'
2
+ require './lib/json/next/version.rb'
3
+
4
+ Hoe.spec 'json-next' do
5
+
6
+ self.version = JSON::Next::VERSION
7
+
8
+ self.summary = 'json-next - read generation y / next generation json versions (HanSON, SON, etc.) with comments, unquoted keys, multi-line strings, trailing commas, optional commas, and more'
9
+ self.description = summary
10
+
11
+ self.urls = ['https://github.com/datatxt/json-next']
12
+
13
+ self.author = 'Gerald Bauer'
14
+ self.email = 'ruby-talk@ruby-lang.org'
15
+
16
+ # switch extension to .markdown for gihub formatting
17
+ self.readme_file = 'README.md'
18
+ self.history_file = 'HISTORY.md'
19
+
20
+ self.licenses = ['Public Domain']
21
+
22
+ self.spec_extras = {
23
+ required_ruby_version: '>= 1.9.2'
24
+ }
25
+
26
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ require 'json'
4
+ require 'strscan' ## StringScanner
5
+ require 'pp'
6
+
7
+
8
+ # our own code
9
+ require 'json/next/version' # note: let version always go first
10
+ require 'json/next/pattern' # shared utils for "custom" parser
11
+ require 'json/next/commata'
12
+
13
+ require 'json/next/parser/hanson'
14
+ require 'json/next/parser/son'
15
+
16
+
17
+
18
+ # say hello
19
+ puts JSON::Next.banner if defined?( $RUBYLIBS_DEBUG )
@@ -0,0 +1,171 @@
1
+ # encoding: utf-8
2
+
3
+ module JSON
4
+ module Next
5
+
6
+
7
+ ### auto-add commas for objects and arrays
8
+ class Commata
9
+
10
+
11
+ ## convenience helper
12
+ def self.convert( str, opts={} )
13
+ self.new.convert( str, opts )
14
+ end
15
+
16
+
17
+ def convert( str, opts={} )
18
+ @debug = opts.fetch( :debug, false )
19
+ @out = ""
20
+ @buffer = StringScanner.new( str )
21
+
22
+ skip_whitespaces
23
+ parse_value
24
+ @out
25
+ end
26
+
27
+
28
+ def debug?() @debug; end
29
+
30
+
31
+
32
+ def skip_whitespaces
33
+ @buffer.skip( /[ \t\n]*/ ) ## skip trailing WHITESPACE
34
+ end
35
+
36
+
37
+ def parse_string
38
+
39
+ if @buffer.peek(1) == '"' ## double quote
40
+ @buffer.getch # consume double quote
41
+ value = @buffer.scan_until( /(?=")/) ## fix: allow escaped double quote e.g. \" too!!!
42
+ @buffer.getch # consume double quote
43
+
44
+ puts %{string value >>#{value}<<} if debug?
45
+ @out << ' "'
46
+ @out << value
47
+ @out << '" '
48
+
49
+ skip_whitespaces
50
+ else
51
+ puts "!! format error: string literal - expected opening quote (\") - rest is >>#{@buffer.rest}<<"
52
+ end
53
+ end
54
+
55
+
56
+
57
+ def parse_object
58
+
59
+ if @buffer.peek(1) == '{'
60
+ @buffer.getch # consume '{'
61
+ @out << ' { '
62
+ skip_whitespaces
63
+
64
+ if @buffer.peek(1) == '}' ## empty object?
65
+ @buffer.getch # consume '{'
66
+ @out << ' } '
67
+ skip_whitespaces
68
+ return
69
+ end
70
+
71
+ loop do
72
+ parse_string
73
+ if @buffer.peek(1) == ':'
74
+ @buffer.getch # consume ':'
75
+ @out << ' : '
76
+ skip_whitespaces
77
+
78
+ parse_value
79
+ if @buffer.peek(1) == '}'
80
+ @buffer.getch # consume '}'
81
+ @out << ' } '
82
+ skip_whitespaces
83
+ return ## use break - why? why not?
84
+ else
85
+ if @buffer.peek(1) == ','
86
+ @buffer.getch # consume ','
87
+ @out << ' , '
88
+ skip_whitespaces
89
+ else
90
+ puts "object literal - auto-add comma for key-value pair" if debug?
91
+ @out << ' , '
92
+ end
93
+ end
94
+ else
95
+ puts "!! format error: object literal - expected colon (:) - rest is >>#{@buffer.rest}<<"
96
+ end
97
+ end
98
+ else
99
+ puts "!! format error: object literal - expected curly open bracket ({) - rest is >>#{@buffer.rest}<<"
100
+ end
101
+ end # method parse_object
102
+
103
+
104
+
105
+ def parse_array
106
+
107
+ if @buffer.peek(1) == '['
108
+ @buffer.getch # consume '['
109
+ @out << ' [ '
110
+ skip_whitespaces
111
+
112
+ if @buffer.peek(1) == ']' ## empty array?
113
+ @buffer.getch # consume ']'
114
+ @out << ' ] '
115
+ skip_whitespaces
116
+ return
117
+ end
118
+
119
+ loop do
120
+ parse_value
121
+ if @buffer.peek(1) == ']'
122
+ @buffer.getch # consume ']'
123
+ @out << ' ] '
124
+ skip_whitespaces
125
+ return ## use break - why? why not?
126
+ else
127
+ if @buffer.peek(1) == ','
128
+ @buffer.getch # consume ','
129
+ @out << ' , '
130
+ skip_whitespaces
131
+ else
132
+ puts "array literal - auto-add comma for value" if debug?
133
+ @out << ' , '
134
+ end
135
+ end
136
+ end
137
+ else
138
+ puts "!! format error: array literal - expected square open bracket ([) - rest is >>#{@buffer.rest}<<"
139
+ end
140
+ end # method parse_array
141
+
142
+
143
+
144
+ def parse_value
145
+ if @buffer.peek(1) == '{'
146
+ parse_object
147
+ elsif @buffer.peek(1) == '['
148
+ parse_array
149
+ elsif @buffer.peek(1) == '"'
150
+ parse_string
151
+ else
152
+ ## assume number or literal/identifier
153
+ value = @buffer.scan( /[_$a-zA-Z0-9.+\-]+/ )
154
+ puts %{literal value >>#{value}<<} if debug?
155
+ @out << " "
156
+ @out << value
157
+ @out << " "
158
+
159
+ skip_whitespaces
160
+ end
161
+
162
+ ## todo/fix: check if eof reached ?? if not report warning - more data available??
163
+ ## wrap in object ({}) or array ([])
164
+ end
165
+
166
+
167
+ end # class Commata
168
+
169
+
170
+ end # module Next
171
+ end # module JSON
@@ -0,0 +1,101 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # based on github.com/timjansen/hanson
5
+ # Thanks to Tim Jansen
6
+
7
+
8
+ module HANSON
9
+
10
+
11
+ BACKTICK_ML_QUOTE = JSON::Next::BACKTICK_ML_QUOTE
12
+ SINGLE_QUOTE = JSON::Next::SINGLE_QUOTE
13
+ DOUBLE_QUOTE = JSON::Next::DOUBLE_QUOTE
14
+
15
+ CLANG_ML_COMMENT = JSON::Next::CLANG_ML_COMMENT
16
+ CLANG_COMMENT = JSON::Next::CLANG_COMMENT
17
+
18
+ KEYWORDS = JSON::Next::KEYWORDS
19
+ IDENTIFIER = JSON::Next::IDENTIFIER
20
+ TRAILING_COMMA = JSON::Next::TRAILING_COMMA
21
+
22
+ UNESCAPE_MAP = JSON::Next::UNESCAPE_MAP
23
+ ML_ESCAPE_MAP = JSON::Next::ML_ESCAPE_MAP
24
+
25
+
26
+
27
+ def self.strip_comments( text ) ## pass 1
28
+ text.gsub( /#{BACKTICK_ML_QUOTE}|#{SINGLE_QUOTE}|#{DOUBLE_QUOTE}|#{CLANG_ML_COMMENT}|#{CLANG_COMMENT}/ox ) do |match|
29
+ ## puts "match: >>#{match}<< : #{match.class.name}"
30
+ if match[0] == ?/ ## comments start with // or /*
31
+ ## puts "!!! removing comments"
32
+ '' ## remove / strip comments
33
+ else
34
+ match
35
+ end
36
+ end
37
+ end
38
+
39
+
40
+ def self.normalize_quotes( text ) ## pass 2
41
+ text.gsub( /#{BACKTICK_ML_QUOTE}|#{SINGLE_QUOTE}|#{DOUBLE_QUOTE}/ox ) do |match|
42
+ ## puts "match: >>#{match}<< : #{match.class.name}"
43
+
44
+ m = Regexp.last_match
45
+ if m[:backtick_ml_quote]
46
+ ## puts "!!! ml_quote -- convert to double quotes"
47
+ str = m[:backtick_ml_quote]
48
+ str = str.gsub( /\\./ ) {|r| UNESCAPE_MAP[r] || r }
49
+ str = str.gsub( /[\n\r\t"]/ ) { |r| ML_ESCAPE_MAP[r] }
50
+ '"' + str + '"'
51
+ elsif m[:single_quote]
52
+ ## puts "!!! single_quote -- convert to double quotes"
53
+ str = m[:single_quote]
54
+ str = str.gsub( /\\./ ) {|r| UNESCAPE_MAP[r] || r }
55
+ str = str.gsub( /"/, %{\\"} )
56
+ '"' + str + '"'
57
+ else
58
+ match
59
+ end
60
+ end
61
+ end
62
+
63
+
64
+ def self.convert( text )
65
+
66
+ # text is the HanSON string to convert.
67
+
68
+ # todo: add keep_line_numbers options - why? why not?
69
+ # see github.com/timjansen/hanson
70
+
71
+ ## pass 1: remove/strip comments
72
+ text = strip_comments( text )
73
+
74
+ ## pass 2: requote/normalize quotes
75
+ text = normalize_quotes( text )
76
+
77
+ ## pass 3: quote unquoted and remove trailing commas
78
+ text = text.gsub( /#{KEYWORDS}|#{IDENTIFIER}|#{DOUBLE_QUOTE}|#{TRAILING_COMMA}/ox ) do |match|
79
+ ## puts "match: >>#{match}<< : #{match.class.name}"
80
+
81
+ m = Regexp.last_match
82
+ if m[:identifier]
83
+ ## puts "!!! identfier -- wrap in double quotes"
84
+ '"' + m[:identifier] + '"'
85
+ elsif m[:trailing_comma]
86
+ ## puts "!!! trailing comma -- remove"
87
+ ''
88
+ else
89
+ match
90
+ end
91
+ end
92
+
93
+ text
94
+ end
95
+
96
+
97
+ def self.parse( text )
98
+ JSON.parse( self.convert( text ) )
99
+ end
100
+
101
+ end # module HANSON
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # based on github.com/aleksandergurin/simple-object-notation
5
+ # Thanks to Aleksander Gurin
6
+
7
+
8
+ module SON
9
+
10
+
11
+ DOUBLE_QUOTE = JSON::Next::DOUBLE_QUOTE
12
+
13
+ SHELL_COMMENT = JSON::Next::SHELL_COMMENT
14
+
15
+
16
+ def self.strip_comments( text ) ## pass 1
17
+ text.gsub( /#{DOUBLE_QUOTE}|#{SHELL_COMMENT}/ox ) do |match|
18
+ ## puts "match: >>#{match}<< : #{match.class.name}"
19
+ if match[0] == ?# ## comments start with #
20
+ ## puts "!!! removing comments"
21
+ '' ## remove / strip comments
22
+ else
23
+ match
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+
30
+
31
+ def self.convert( text )
32
+
33
+ # text is the SON string to convert.
34
+
35
+ text = strip_comments( text ) ## pass 1
36
+ text = JSON::Next::Commata.convert( text ) ## pass 2 - auto-add (missing optional) commas
37
+ text
38
+ end
39
+
40
+
41
+ def self.parse( text )
42
+ JSON.parse( self.convert( text ) )
43
+ end
44
+
45
+ end # module SON
@@ -0,0 +1,127 @@
1
+ # encoding: utf-8
2
+
3
+ module JSON
4
+ module Next
5
+
6
+ ## note: regex pattern \\ needs to get escaped twice, thus, \\.
7
+ ## and for literal \\ use \\\\\.
8
+
9
+ ## todo: check for newlines [^] incl. newline ?
10
+
11
+ ## note: add named captures for "inner" unquotes string values
12
+
13
+ ###############
14
+ ##### quotes
15
+
16
+
17
+ BACKTICK_ML_QUOTE = %< ` (?<backtick_ml_quote>
18
+ (?:
19
+ \\\\. | [^`]
20
+ )*
21
+ )
22
+ `
23
+ >
24
+
25
+ ## => \\\\. -- allow backslash escapes e.g. \n \t \\ etc.
26
+ ## => [^`] -- everything except backquote
27
+
28
+ ## todo/fix - check if [^`] includes/matches newline too (yes)? -- add \n for multi-line!
29
+
30
+
31
+ SINGLE_QUOTE = %< ' (?<single_quote>
32
+ (?:
33
+ \\\\. | [^']
34
+ )*
35
+ )
36
+ '
37
+ >
38
+
39
+ DOUBLE_QUOTE = %< " (?<double_quote>
40
+ (?:
41
+ \\\\. | [^"]
42
+ )*
43
+ )
44
+ "
45
+ >
46
+
47
+
48
+ #######################
49
+ #### comments
50
+
51
+ CLANG_ML_COMMENT = %< /\\*
52
+ .*?
53
+ \\*/
54
+ >
55
+
56
+ ## use . instead of [^] - why? why not?
57
+ ## note: check if . incl. newlines too (only in multi-line (m) option - why? why not??
58
+ ## fix/todo: include newline!!! \n - for multi-line!!!
59
+
60
+ ## note: *? is NON-greedy
61
+
62
+
63
+ CLANG_COMMENT = %< //
64
+ .*?
65
+ (?:
66
+ \\n | $
67
+ )
68
+ >
69
+
70
+ ## note: check if . incl. newlines too (only in multi-line (m) option - why? why not??
71
+ ## note: *? is NON-greedy
72
+
73
+
74
+ SHELL_COMMENT = %< [#]
75
+ .*?
76
+ (?:
77
+ \\n | $
78
+ )
79
+ >
80
+
81
+ ## note: use [#] instead of # to avoid confusion with # comment in regex
82
+
83
+
84
+
85
+
86
+ KEYWORDS = %<
87
+ (?:
88
+ true | false | null
89
+ )
90
+ (?=
91
+ [^\\w_$] | $
92
+ )
93
+ >
94
+
95
+ IDENTIFIER = %<
96
+ (?<identifier>
97
+ [a-zA-Z_$]
98
+ [\\w_$]*
99
+ )
100
+ >
101
+
102
+ TRAILING_COMMA = %<
103
+ (?<trailing_comma>,)
104
+ (?=
105
+ \\s*
106
+ [}\\]]
107
+ )
108
+ >
109
+
110
+
111
+
112
+ UNESCAPE_MAP = {
113
+ %<\\"> => %<">, ## "\\\"" => "\"",
114
+ %<\\`> => %<`>, ## "\\`" => "`",
115
+ %<\\'> => %<'> ## "\\'" => "'"
116
+ }
117
+
118
+ ML_ESCAPE_MAP = {
119
+ %<\n> => %<\\n>, ## "\n" => "\\n",
120
+ %<\r> => %<\\r>, ## "\r" => "\\r",
121
+ %<\t> => %<\\t>, ## "\t" => "\\t",
122
+ %<"> => %<\\"> ## "\"" => "\\\""
123
+ }
124
+
125
+
126
+ end # module Next
127
+ end # module JSON
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module JSON
4
+ module Next
5
+
6
+ MAJOR = 1 ## todo: namespace inside version or something - why? why not??
7
+ MINOR = 1
8
+ PATCH = 0
9
+ VERSION = [MAJOR,MINOR,PATCH].join('.')
10
+
11
+ def self.version
12
+ VERSION
13
+ end
14
+
15
+ def self.banner
16
+ "json-next/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
17
+ end
18
+
19
+ def self.root
20
+ "#{File.expand_path( File.dirname(File.dirname(File.dirname(File.dirname(__FILE__)))) )}"
21
+ end
22
+
23
+ end # module Next
24
+ end # module JSON
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ ## minitest setup
4
+ require 'minitest/autorun'
5
+
6
+
7
+ $RUBYLIBS_DEBUG = true
8
+
9
+ ## our own code
10
+ require 'json/next'
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_commata.rb
6
+
7
+
8
+ require 'helper'
9
+
10
+
11
+ class TestCommata < MiniTest::Test
12
+
13
+ def test_commata
14
+
15
+ sample1a =<<TXT
16
+ {
17
+ "name": "Alexander Grothendieck"
18
+ "fields": "mathematics"
19
+ "main_topics": [
20
+ "Etale cohomology"
21
+ "Motives"
22
+ "Topos theory"
23
+ "Schemes"
24
+ ]
25
+ }
26
+ TXT
27
+
28
+ exp_sample1b = {
29
+ "name" => "Alexander Grothendieck",
30
+ "fields" => "mathematics",
31
+ "main_topics" =>
32
+ ["Etale cohomology", "Motives", "Topos theory", "Schemes"]
33
+ }
34
+
35
+
36
+ sample2a =<<TXT
37
+ {
38
+ "nested": {
39
+ "name": "Alexander Grothendieck"
40
+ "fields": "mathematics"
41
+ "array": ["one" "two"] }
42
+ "numbers": [1 2 3 4 5]
43
+ "more_numbers": [1.1 2.0 0.3 4.444 -5.1]
44
+ "mixed": [1 true false null]
45
+ }
46
+ TXT
47
+
48
+ sample2a1 =<<TXT
49
+ {
50
+ "nested": {
51
+ "name": "Alexander Grothendieck",
52
+ "fields": "mathematics",
53
+ "array": ["one", "two"] },
54
+ "numbers": [1, 2, 3, 4, 5],
55
+ "more_numbers": [1.1, 2.0, 0.3, 4.444, -5.1],
56
+ "mixed": [1, true, false, null]
57
+ }
58
+ TXT
59
+
60
+
61
+
62
+ exp_sample2b = {
63
+ "nested" => {
64
+ "name" => "Alexander Grothendieck",
65
+ "fields" => "mathematics",
66
+ "array" => ["one", "two"]
67
+ },
68
+ "numbers" => [1, 2, 3, 4, 5],
69
+ "more_numbers" => [1.1, 2.0, 0.3, 4.444, -5.1],
70
+ "mixed" => [1, true, false, nil]
71
+ }
72
+
73
+
74
+ sample1b = JSON::Next::Commata.convert( sample1a, debug: true )
75
+ puts sample1b
76
+
77
+ assert_equal exp_sample1b, JSON.parse( sample1b )
78
+
79
+
80
+ sample2b = JSON::Next::Commata.convert( sample2a, debug: true )
81
+ puts sample2b
82
+
83
+ assert_equal exp_sample2b, JSON.parse( sample2b )
84
+
85
+
86
+ sample2b1 = JSON::Next::Commata.convert( sample2a1, debug: true )
87
+ puts sample2b1
88
+
89
+ assert_equal exp_sample2b, JSON.parse( sample2b1 )
90
+ end
91
+
92
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_parser_hanson.rb
6
+
7
+
8
+ require 'helper'
9
+
10
+
11
+ class TestParser < MiniTest::Test
12
+
13
+ def test_hanson
14
+ exp_sample1 = {
15
+ "listName"=>"Sesame Street Monsters",
16
+ "content"=>
17
+ [{"name"=>"Cookie Monster",
18
+ "background"=> "Cookie Monster used to be a\n monster that ate everything, especially cookies.\n These days he is forced to eat \"healthy\" food."
19
+ },
20
+ {"name"=>"Herry Monster",
21
+ "background"=> "Herry Monster is a furry blue monster with a purple nose.\n He's mostly retired today."
22
+ }
23
+ ]}
24
+
25
+ sample1 =<<TXT
26
+ {
27
+ listName: "Sesame Street Monsters", // note that listName needs no quotes
28
+ content: [
29
+ {
30
+ name: "Cookie Monster",
31
+ /* Note the template quotes and unescaped regular quotes in the next string */
32
+ background: `Cookie Monster used to be a
33
+ monster that ate everything, especially cookies.
34
+ These days he is forced to eat "healthy" food.`
35
+ }, {
36
+ // You can single-quote strings too:
37
+ name: 'Herry Monster',
38
+ background: `Herry Monster is a furry blue monster with a purple nose.
39
+ He's mostly retired today.`
40
+ }, // don't worry, the trailing comma will be ignored
41
+ ]
42
+ }
43
+ TXT
44
+
45
+ puts HANSON.convert( sample1 )
46
+
47
+ pp HANSON.parse( sample1 )
48
+
49
+ assert_equal exp_sample1, HANSON.parse( sample1 )
50
+ end
51
+
52
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_parser_son.rb
6
+
7
+
8
+ require 'helper'
9
+
10
+
11
+ class TestParserSon < MiniTest::Test
12
+
13
+ def test_son
14
+ exp_sample1 = {
15
+ "name"=>"Alexander Grothendieck",
16
+ "fields"=>"mathematics",
17
+ "main_topics"=>
18
+ ["Etale cohomology", "Motives", "Topos theory", "Schemes"]
19
+ }
20
+
21
+ sample1 =<<TXT
22
+ {
23
+ # Personal information
24
+
25
+ "name": "Alexander Grothendieck"
26
+ "fields": "mathematics"
27
+ "main_topics": [
28
+ "Etale cohomology"
29
+ "Motives"
30
+ "Topos theory"
31
+ "Schemes"
32
+ ]
33
+ }
34
+ TXT
35
+
36
+ puts SON.convert( sample1 )
37
+
38
+ assert_equal exp_sample1, SON.parse( sample1 )
39
+ end
40
+
41
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_version.rb
6
+
7
+
8
+ require 'helper'
9
+
10
+
11
+ class TestVersion < MiniTest::Test
12
+
13
+
14
+ def test_version
15
+
16
+ pp JSON::Next::UNESCAPE_MAP
17
+ pp JSON::Next::ML_ESCAPE_MAP
18
+
19
+ pp JSON::Next::BACKTICK_ML_QUOTE
20
+ puts JSON::Next::BACKTICK_ML_QUOTE
21
+ pp JSON::Next::SINGLE_QUOTE
22
+ puts JSON::Next::SINGLE_QUOTE
23
+ pp JSON::Next::DOUBLE_QUOTE
24
+ puts JSON::Next::DOUBLE_QUOTE
25
+
26
+ pp JSON::Next::CLANG_ML_COMMENT
27
+ puts JSON::Next::CLANG_ML_COMMENT
28
+ pp JSON::Next::CLANG_COMMENT
29
+ puts JSON::Next::CLANG_COMMENT
30
+
31
+
32
+ puts JSON::Next::VERSION
33
+ assert true
34
+ ## assume everything ok if get here
35
+ end
36
+
37
+ end # class TestVersion
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json-next
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gerald Bauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rdoc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hoe
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.15'
41
+ description: json-next - read generation y / next generation json versions (HanSON,
42
+ SON, etc.) with comments, unquoted keys, multi-line strings, trailing commas, optional
43
+ commas, and more
44
+ email: ruby-talk@ruby-lang.org
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files:
48
+ - HISTORY.md
49
+ - Manifest.txt
50
+ - README.md
51
+ files:
52
+ - HISTORY.md
53
+ - Manifest.txt
54
+ - README.md
55
+ - Rakefile
56
+ - lib/json/next.rb
57
+ - lib/json/next/commata.rb
58
+ - lib/json/next/parser/hanson.rb
59
+ - lib/json/next/parser/son.rb
60
+ - lib/json/next/pattern.rb
61
+ - lib/json/next/version.rb
62
+ - test/helper.rb
63
+ - test/test_commata.rb
64
+ - test/test_parser_hanson.rb
65
+ - test/test_parser_son.rb
66
+ - test/test_version.rb
67
+ homepage: https://github.com/datatxt/json-next
68
+ licenses:
69
+ - Public Domain
70
+ metadata: {}
71
+ post_install_message:
72
+ rdoc_options:
73
+ - "--main"
74
+ - README.md
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 1.9.2
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 2.6.7
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: json-next - read generation y / next generation json versions (HanSON, SON,
93
+ etc.) with comments, unquoted keys, multi-line strings, trailing commas, optional
94
+ commas, and more
95
+ test_files: []