larsklevan-json 1.5.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.
Files changed (136) hide show
  1. data/CHANGES +188 -0
  2. data/COPYING +58 -0
  3. data/COPYING-json-jruby +57 -0
  4. data/GPL +340 -0
  5. data/README +358 -0
  6. data/README-json-jruby.markdown +33 -0
  7. data/Rakefile +401 -0
  8. data/TODO +1 -0
  9. data/VERSION +1 -0
  10. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
  11. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
  12. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
  13. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
  14. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
  15. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
  16. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
  17. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
  18. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
  19. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
  20. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
  21. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
  22. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
  23. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
  24. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
  25. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
  26. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
  27. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
  28. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
  29. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
  30. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
  31. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
  32. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
  33. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
  34. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
  35. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
  36. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
  37. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
  38. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
  39. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
  40. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
  41. data/benchmarks/generator2_benchmark.rb +222 -0
  42. data/benchmarks/generator_benchmark.rb +224 -0
  43. data/benchmarks/ohai.json +1216 -0
  44. data/benchmarks/ohai.ruby +1 -0
  45. data/benchmarks/parser2_benchmark.rb +251 -0
  46. data/benchmarks/parser_benchmark.rb +259 -0
  47. data/bin/edit_json.rb +9 -0
  48. data/bin/prettify_json.rb +75 -0
  49. data/data/example.json +1 -0
  50. data/data/index.html +38 -0
  51. data/data/prototype.js +4184 -0
  52. data/ext/json/ext/generator/extconf.rb +20 -0
  53. data/ext/json/ext/generator/generator.c +1424 -0
  54. data/ext/json/ext/generator/generator.h +197 -0
  55. data/ext/json/ext/parser/extconf.rb +16 -0
  56. data/ext/json/ext/parser/parser.c +1969 -0
  57. data/ext/json/ext/parser/parser.h +78 -0
  58. data/ext/json/ext/parser/parser.rl +826 -0
  59. data/install.rb +26 -0
  60. data/java/lib/bytelist-1.0.6.jar +0 -0
  61. data/java/lib/jcodings.jar +0 -0
  62. data/java/src/json/ext/ByteListTranscoder.java +167 -0
  63. data/java/src/json/ext/Generator.java +441 -0
  64. data/java/src/json/ext/GeneratorMethods.java +231 -0
  65. data/java/src/json/ext/GeneratorService.java +42 -0
  66. data/java/src/json/ext/GeneratorState.java +473 -0
  67. data/java/src/json/ext/OptionsReader.java +119 -0
  68. data/java/src/json/ext/Parser.java +2295 -0
  69. data/java/src/json/ext/Parser.rl +825 -0
  70. data/java/src/json/ext/ParserService.java +34 -0
  71. data/java/src/json/ext/RuntimeInfo.java +119 -0
  72. data/java/src/json/ext/StringDecoder.java +166 -0
  73. data/java/src/json/ext/StringEncoder.java +116 -0
  74. data/java/src/json/ext/Utils.java +89 -0
  75. data/json-java.gemspec +20 -0
  76. data/lib/json.rb +10 -0
  77. data/lib/json/Array.xpm +21 -0
  78. data/lib/json/FalseClass.xpm +21 -0
  79. data/lib/json/Hash.xpm +21 -0
  80. data/lib/json/Key.xpm +73 -0
  81. data/lib/json/NilClass.xpm +21 -0
  82. data/lib/json/Numeric.xpm +28 -0
  83. data/lib/json/String.xpm +96 -0
  84. data/lib/json/TrueClass.xpm +21 -0
  85. data/lib/json/add/core.rb +147 -0
  86. data/lib/json/add/rails.rb +8 -0
  87. data/lib/json/common.rb +419 -0
  88. data/lib/json/editor.rb +1369 -0
  89. data/lib/json/ext.rb +28 -0
  90. data/lib/json/json.xpm +1499 -0
  91. data/lib/json/pure.rb +15 -0
  92. data/lib/json/pure/generator.rb +446 -0
  93. data/lib/json/pure/parser.rb +320 -0
  94. data/lib/json/version.rb +8 -0
  95. data/tests/fixtures/fail1.json +1 -0
  96. data/tests/fixtures/fail10.json +1 -0
  97. data/tests/fixtures/fail11.json +1 -0
  98. data/tests/fixtures/fail12.json +1 -0
  99. data/tests/fixtures/fail13.json +1 -0
  100. data/tests/fixtures/fail14.json +1 -0
  101. data/tests/fixtures/fail18.json +1 -0
  102. data/tests/fixtures/fail19.json +1 -0
  103. data/tests/fixtures/fail2.json +1 -0
  104. data/tests/fixtures/fail20.json +1 -0
  105. data/tests/fixtures/fail21.json +1 -0
  106. data/tests/fixtures/fail22.json +1 -0
  107. data/tests/fixtures/fail23.json +1 -0
  108. data/tests/fixtures/fail24.json +1 -0
  109. data/tests/fixtures/fail25.json +1 -0
  110. data/tests/fixtures/fail27.json +2 -0
  111. data/tests/fixtures/fail28.json +2 -0
  112. data/tests/fixtures/fail3.json +1 -0
  113. data/tests/fixtures/fail4.json +1 -0
  114. data/tests/fixtures/fail5.json +1 -0
  115. data/tests/fixtures/fail6.json +1 -0
  116. data/tests/fixtures/fail7.json +1 -0
  117. data/tests/fixtures/fail8.json +1 -0
  118. data/tests/fixtures/fail9.json +1 -0
  119. data/tests/fixtures/pass1.json +56 -0
  120. data/tests/fixtures/pass15.json +1 -0
  121. data/tests/fixtures/pass16.json +1 -0
  122. data/tests/fixtures/pass17.json +1 -0
  123. data/tests/fixtures/pass2.json +1 -0
  124. data/tests/fixtures/pass26.json +1 -0
  125. data/tests/fixtures/pass3.json +6 -0
  126. data/tests/setup_variant.rb +11 -0
  127. data/tests/test_json.rb +390 -0
  128. data/tests/test_json_addition.rb +167 -0
  129. data/tests/test_json_encoding.rb +65 -0
  130. data/tests/test_json_fixtures.rb +35 -0
  131. data/tests/test_json_generate.rb +185 -0
  132. data/tests/test_json_string_matching.rb +40 -0
  133. data/tests/test_json_unicode.rb +72 -0
  134. data/tools/fuzz.rb +139 -0
  135. data/tools/server.rb +61 -0
  136. metadata +209 -0
data/lib/json/pure.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'json/common'
2
+ require 'json/pure/parser'
3
+ require 'json/pure/generator'
4
+
5
+ module JSON
6
+ # This module holds all the modules/classes that implement JSON's
7
+ # functionality in pure ruby.
8
+ module Pure
9
+ $DEBUG and warn "Using Pure library for JSON."
10
+ JSON.parser = Parser
11
+ JSON.generator = Generator
12
+ end
13
+
14
+ JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
15
+ end
@@ -0,0 +1,446 @@
1
+ module JSON
2
+ MAP = {
3
+ "\x0" => '\u0000',
4
+ "\x1" => '\u0001',
5
+ "\x2" => '\u0002',
6
+ "\x3" => '\u0003',
7
+ "\x4" => '\u0004',
8
+ "\x5" => '\u0005',
9
+ "\x6" => '\u0006',
10
+ "\x7" => '\u0007',
11
+ "\b" => '\b',
12
+ "\t" => '\t',
13
+ "\n" => '\n',
14
+ "\xb" => '\u000b',
15
+ "\f" => '\f',
16
+ "\r" => '\r',
17
+ "\xe" => '\u000e',
18
+ "\xf" => '\u000f',
19
+ "\x10" => '\u0010',
20
+ "\x11" => '\u0011',
21
+ "\x12" => '\u0012',
22
+ "\x13" => '\u0013',
23
+ "\x14" => '\u0014',
24
+ "\x15" => '\u0015',
25
+ "\x16" => '\u0016',
26
+ "\x17" => '\u0017',
27
+ "\x18" => '\u0018',
28
+ "\x19" => '\u0019',
29
+ "\x1a" => '\u001a',
30
+ "\x1b" => '\u001b',
31
+ "\x1c" => '\u001c',
32
+ "\x1d" => '\u001d',
33
+ "\x1e" => '\u001e',
34
+ "\x1f" => '\u001f',
35
+ '"' => '\"',
36
+ '\\' => '\\\\',
37
+ } # :nodoc:
38
+
39
+ # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
40
+ # UTF16 big endian characters as \u????, and return it.
41
+ if defined?(::Encoding)
42
+ def utf8_to_json(string) # :nodoc:
43
+ string = string.dup
44
+ string << '' # XXX workaround: avoid buffer sharing
45
+ string.force_encoding(::Encoding::ASCII_8BIT)
46
+ string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
47
+ string.gsub!("</", '<\/') # avoid "</script>"
48
+ string.force_encoding(::Encoding::UTF_8)
49
+ string
50
+ end
51
+
52
+ def utf8_to_json_ascii(string) # :nodoc:
53
+ string = string.dup
54
+ string << '' # XXX workaround: avoid buffer sharing
55
+ string.force_encoding(::Encoding::ASCII_8BIT)
56
+ string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
57
+ string.gsub!(/(
58
+ (?:
59
+ [\xc2-\xdf][\x80-\xbf] |
60
+ [\xe0-\xef][\x80-\xbf]{2} |
61
+ [\xf0-\xf4][\x80-\xbf]{3}
62
+ )+ |
63
+ [\x80-\xc1\xf5-\xff] # invalid
64
+ )/nx) { |c|
65
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
66
+ s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
67
+ s.gsub!(/.{4}/n, '\\\\u\&')
68
+ }
69
+ string.gsub!("</", '<\/') # avoid "</script>"
70
+ string.force_encoding(::Encoding::UTF_8)
71
+ string
72
+ rescue => e
73
+ raise GeneratorError, "Caught #{e.class}: #{e}"
74
+ end
75
+ else
76
+ def utf8_to_json(string) # :nodoc:
77
+ string = string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
78
+ string.gsub!("</", '<\/') # avoid "</script>"
79
+ string
80
+ end
81
+
82
+ def utf8_to_json_ascii(string) # :nodoc:
83
+ string = string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
84
+ string.gsub!(/(
85
+ (?:
86
+ [\xc2-\xdf][\x80-\xbf] |
87
+ [\xe0-\xef][\x80-\xbf]{2} |
88
+ [\xf0-\xf4][\x80-\xbf]{3}
89
+ )+ |
90
+ [\x80-\xc1\xf5-\xff] # invalid
91
+ )/nx) { |c|
92
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
93
+ s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
94
+ s.gsub!(/.{4}/n, '\\\\u\&')
95
+ }
96
+ string.gsub!("</", '<\/') # avoid "</script>"
97
+ string
98
+ rescue => e
99
+ raise GeneratorError, "Caught #{e.class}: #{e}"
100
+ end
101
+ end
102
+ module_function :utf8_to_json, :utf8_to_json_ascii
103
+
104
+ module Pure
105
+ module Generator
106
+ # This class is used to create State instances, that are use to hold data
107
+ # while generating a JSON text from a a Ruby data structure.
108
+ class State
109
+ # Creates a State object from _opts_, which ought to be Hash to create
110
+ # a new State instance configured by _opts_, something else to create
111
+ # an unconfigured instance. If _opts_ is a State object, it is just
112
+ # returned.
113
+ def self.from_state(opts)
114
+ case
115
+ when self === opts
116
+ opts
117
+ when opts.respond_to?(:to_hash)
118
+ new(opts.to_hash)
119
+ when opts.respond_to?(:to_h)
120
+ new(opts.to_h)
121
+ else
122
+ SAFE_STATE_PROTOTYPE.dup
123
+ end
124
+ end
125
+
126
+ # Instantiates a new State object, configured by _opts_.
127
+ #
128
+ # _opts_ can have the following keys:
129
+ #
130
+ # * *indent*: a string used to indent levels (default: ''),
131
+ # * *space*: a string that is put after, a : or , delimiter (default: ''),
132
+ # * *space_before*: a string that is put before a : pair delimiter (default: ''),
133
+ # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
134
+ # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
135
+ # * *check_circular*: is deprecated now, use the :max_nesting option instead,
136
+ # * *max_nesting*: sets the maximum level of data structure nesting in
137
+ # the generated JSON, max_nesting = 0 if no maximum should be checked.
138
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
139
+ # generated, otherwise an exception is thrown, if these values are
140
+ # encountered. This options defaults to false.
141
+ def initialize(opts = {})
142
+ @indent = ''
143
+ @space = ''
144
+ @space_before = ''
145
+ @object_nl = ''
146
+ @array_nl = ''
147
+ @allow_nan = false
148
+ @ascii_only = false
149
+ configure opts
150
+ end
151
+
152
+ # This string is used to indent levels in the JSON text.
153
+ attr_accessor :indent
154
+
155
+ # This string is used to insert a space between the tokens in a JSON
156
+ # string.
157
+ attr_accessor :space
158
+
159
+ # This string is used to insert a space before the ':' in JSON objects.
160
+ attr_accessor :space_before
161
+
162
+ # This string is put at the end of a line that holds a JSON object (or
163
+ # Hash).
164
+ attr_accessor :object_nl
165
+
166
+ # This string is put at the end of a line that holds a JSON array.
167
+ attr_accessor :array_nl
168
+
169
+ # This integer returns the maximum level of data structure nesting in
170
+ # the generated JSON, max_nesting = 0 if no maximum is checked.
171
+ attr_accessor :max_nesting
172
+
173
+ # This integer returns the current depth data structure nesting in the
174
+ # generated JSON.
175
+ attr_accessor :depth
176
+
177
+ def check_max_nesting # :nodoc:
178
+ return if @max_nesting.zero?
179
+ current_nesting = depth + 1
180
+ current_nesting > @max_nesting and
181
+ raise NestingError, "nesting of #{current_nesting} is too deep"
182
+ end
183
+
184
+ # Returns true, if circular data structures are checked,
185
+ # otherwise returns false.
186
+ def check_circular?
187
+ !@max_nesting.zero?
188
+ end
189
+
190
+ # Returns true if NaN, Infinity, and -Infinity should be considered as
191
+ # valid JSON and output.
192
+ def allow_nan?
193
+ @allow_nan
194
+ end
195
+
196
+ def ascii_only?
197
+ @ascii_only
198
+ end
199
+
200
+ # Configure this State instance with the Hash _opts_, and return
201
+ # itself.
202
+ def configure(opts)
203
+ @indent = opts[:indent] if opts.key?(:indent)
204
+ @space = opts[:space] if opts.key?(:space)
205
+ @space_before = opts[:space_before] if opts.key?(:space_before)
206
+ @object_nl = opts[:object_nl] if opts.key?(:object_nl)
207
+ @array_nl = opts[:array_nl] if opts.key?(:array_nl)
208
+ @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
209
+ @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
210
+ @depth = opts[:depth] || 0
211
+ if !opts.key?(:max_nesting) # defaults to 19
212
+ @max_nesting = 19
213
+ elsif opts[:max_nesting]
214
+ @max_nesting = opts[:max_nesting]
215
+ else
216
+ @max_nesting = 0
217
+ end
218
+ self
219
+ end
220
+
221
+ # Returns the configuration instance variables as a hash, that can be
222
+ # passed to the configure method.
223
+ def to_h
224
+ result = {}
225
+ for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting ascii_only depth]
226
+ result[iv.intern] = instance_variable_get("@#{iv}")
227
+ end
228
+ result
229
+ end
230
+
231
+ # Generates a valid JSON document from object +obj+ and returns the
232
+ # result. If no valid JSON document can be created this method raises a
233
+ # GeneratorError exception.
234
+ def generate(obj)
235
+ result = obj.to_json(self)
236
+ if result !~ /\A\s*(?:\[.*\]|\{.*\})\s*\Z/m
237
+ raise GeneratorError, "only generation of JSON objects or arrays allowed"
238
+ end
239
+ result
240
+ end
241
+
242
+ # Return the value returned by method +name+.
243
+ def [](name)
244
+ __send__ name
245
+ end
246
+ end
247
+
248
+ module GeneratorMethods
249
+ module Object
250
+ # Converts this object to a string (calling #to_s), converts
251
+ # it to a JSON string, and returns the result. This is a fallback, if no
252
+ # special method #to_json was defined for some object.
253
+ def to_json(*) to_s.to_json end
254
+ end
255
+
256
+ module Hash
257
+ # Returns a JSON string containing a JSON object, that is unparsed from
258
+ # this Hash instance.
259
+ # _state_ is a JSON::State object, that can also be used to configure the
260
+ # produced JSON string output further.
261
+ # _depth_ is used to find out nesting depth, to indent accordingly.
262
+ def to_json(state = nil, *)
263
+ state = State.from_state(state)
264
+ state.check_max_nesting
265
+ json_transform(state)
266
+ end
267
+
268
+ private
269
+
270
+ def json_shift(state)
271
+ state.object_nl.empty? or return ''
272
+ state.indent * state.depth
273
+ end
274
+
275
+ def json_transform(state)
276
+ delim = ','
277
+ delim << state.object_nl
278
+ result = '{'
279
+ result << state.object_nl
280
+ depth = state.depth += 1
281
+ first = true
282
+ indent = !state.object_nl.empty?
283
+ each { |key,value|
284
+ result << delim unless first
285
+ result << state.indent * depth if indent
286
+ result << key.to_s.to_json(state)
287
+ result << state.space_before
288
+ result << ':'
289
+ result << state.space
290
+ result << value.to_json(state)
291
+ first = false
292
+ }
293
+ depth = state.depth -= 1
294
+ result << state.object_nl
295
+ result << state.indent * depth if indent if indent
296
+ result << '}'
297
+ result
298
+ end
299
+ end
300
+
301
+ module Array
302
+ # Returns a JSON string containing a JSON array, that is unparsed from
303
+ # this Array instance.
304
+ # _state_ is a JSON::State object, that can also be used to configure the
305
+ # produced JSON string output further.
306
+ def to_json(state = nil, *)
307
+ state = State.from_state(state)
308
+ state.check_max_nesting
309
+ json_transform(state)
310
+ end
311
+
312
+ private
313
+
314
+ def json_transform(state)
315
+ delim = ','
316
+ delim << state.array_nl
317
+ result = '['
318
+ result << state.array_nl
319
+ depth = state.depth += 1
320
+ first = true
321
+ indent = !state.array_nl.empty?
322
+ each { |value|
323
+ result << delim unless first
324
+ result << state.indent * depth if indent
325
+ result << value.to_json(state)
326
+ first = false
327
+ }
328
+ depth = state.depth -= 1
329
+ result << state.array_nl
330
+ result << state.indent * depth if indent
331
+ result << ']'
332
+ end
333
+ end
334
+
335
+ module Integer
336
+ # Returns a JSON string representation for this Integer number.
337
+ def to_json(*) to_s end
338
+ end
339
+
340
+ module Float
341
+ # Returns a JSON string representation for this Float number.
342
+ def to_json(state = nil, *)
343
+ state = State.from_state(state)
344
+ case
345
+ when infinite?
346
+ if state.allow_nan?
347
+ to_s
348
+ else
349
+ raise GeneratorError, "#{self} not allowed in JSON"
350
+ end
351
+ when nan?
352
+ if state.allow_nan?
353
+ to_s
354
+ else
355
+ raise GeneratorError, "#{self} not allowed in JSON"
356
+ end
357
+ else
358
+ to_s
359
+ end
360
+ end
361
+ end
362
+
363
+ module String
364
+ if defined?(::Encoding)
365
+ # This string should be encoded with UTF-8 A call to this method
366
+ # returns a JSON string encoded with UTF16 big endian characters as
367
+ # \u????.
368
+ def to_json(state = nil, *args)
369
+ state = State.from_state(state)
370
+ if encoding == ::Encoding::UTF_8
371
+ string = self
372
+ else
373
+ string = encode(::Encoding::UTF_8)
374
+ end
375
+ if state.ascii_only?
376
+ '"' << JSON.utf8_to_json_ascii(string) << '"'
377
+ else
378
+ '"' << JSON.utf8_to_json(string) << '"'
379
+ end
380
+ end
381
+ else
382
+ # This string should be encoded with UTF-8 A call to this method
383
+ # returns a JSON string encoded with UTF16 big endian characters as
384
+ # \u????.
385
+ def to_json(state = nil, *args)
386
+ state = State.from_state(state)
387
+ if state.ascii_only?
388
+ '"' << JSON.utf8_to_json_ascii(self) << '"'
389
+ else
390
+ '"' << JSON.utf8_to_json(self) << '"'
391
+ end
392
+ end
393
+ end
394
+
395
+ # Module that holds the extinding methods if, the String module is
396
+ # included.
397
+ module Extend
398
+ # Raw Strings are JSON Objects (the raw bytes are stored in an
399
+ # array for the key "raw"). The Ruby String can be created by this
400
+ # module method.
401
+ def json_create(o)
402
+ o['raw'].pack('C*')
403
+ end
404
+ end
405
+
406
+ # Extends _modul_ with the String::Extend module.
407
+ def self.included(modul)
408
+ modul.extend Extend
409
+ end
410
+
411
+ # This method creates a raw object hash, that can be nested into
412
+ # other data structures and will be unparsed as a raw string. This
413
+ # method should be used, if you want to convert raw strings to JSON
414
+ # instead of UTF-8 strings, e. g. binary data.
415
+ def to_json_raw_object
416
+ {
417
+ JSON.create_id => self.class.name,
418
+ 'raw' => self.unpack('C*'),
419
+ }
420
+ end
421
+
422
+ # This method creates a JSON text from the result of
423
+ # a call to to_json_raw_object of this String.
424
+ def to_json_raw(*args)
425
+ to_json_raw_object.to_json(*args)
426
+ end
427
+ end
428
+
429
+ module TrueClass
430
+ # Returns a JSON string for true: 'true'.
431
+ def to_json(*) 'true' end
432
+ end
433
+
434
+ module FalseClass
435
+ # Returns a JSON string for false: 'false'.
436
+ def to_json(*) 'false' end
437
+ end
438
+
439
+ module NilClass
440
+ # Returns a JSON string for nil: 'null'.
441
+ def to_json(*) 'null' end
442
+ end
443
+ end
444
+ end
445
+ end
446
+ end