~ubuntu-branches/ubuntu/wily/tdiary/wily

« back to all changes in this revision

Viewing changes to vendor/json_pure-1.7.7/lib/json/pure/generator.rb

  • Committer: Package Import Robot
  • Author(s): Hideki Yamane
  • Date: 2013-05-19 16:14:01 UTC
  • mfrom: (12.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20130519161401-hf5oyr8g8a94fsew
Tags: 3.2.2-2
Upload to unstable 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.force_encoding(::Encoding::ASCII_8BIT)
 
45
      string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
 
46
      string.force_encoding(::Encoding::UTF_8)
 
47
      string
 
48
    end
 
49
 
 
50
    def utf8_to_json_ascii(string) # :nodoc:
 
51
      string = string.dup
 
52
      string.force_encoding(::Encoding::ASCII_8BIT)
 
53
      string.gsub!(/["\\\x0-\x1f]/n) { MAP[$&] }
 
54
      string.gsub!(/(
 
55
                      (?:
 
56
                        [\xc2-\xdf][\x80-\xbf]    |
 
57
                        [\xe0-\xef][\x80-\xbf]{2} |
 
58
                        [\xf0-\xf4][\x80-\xbf]{3}
 
59
                      )+ |
 
60
                      [\x80-\xc1\xf5-\xff]       # invalid
 
61
                    )/nx) { |c|
 
62
                      c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
 
63
                      s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
 
64
                      s.force_encoding(::Encoding::ASCII_8BIT)
 
65
                      s.gsub!(/.{4}/n, '\\\\u\&')
 
66
                      s.force_encoding(::Encoding::UTF_8)
 
67
                    }
 
68
      string.force_encoding(::Encoding::UTF_8)
 
69
      string
 
70
    rescue => e
 
71
      raise GeneratorError.wrap(e)
 
72
    end
 
73
  else
 
74
    def utf8_to_json(string) # :nodoc:
 
75
      string.gsub(/["\\\x0-\x1f]/n) { MAP[$&] }
 
76
    end
 
77
 
 
78
    def utf8_to_json_ascii(string) # :nodoc:
 
79
      string = string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
 
80
      string.gsub!(/(
 
81
                      (?:
 
82
                        [\xc2-\xdf][\x80-\xbf]    |
 
83
                        [\xe0-\xef][\x80-\xbf]{2} |
 
84
                        [\xf0-\xf4][\x80-\xbf]{3}
 
85
                      )+ |
 
86
                      [\x80-\xc1\xf5-\xff]       # invalid
 
87
                    )/nx) { |c|
 
88
        c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
 
89
        s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
 
90
        s.gsub!(/.{4}/n, '\\\\u\&')
 
91
      }
 
92
      string
 
93
    rescue => e
 
94
      raise GeneratorError.wrap(e)
 
95
    end
 
96
  end
 
97
  module_function :utf8_to_json, :utf8_to_json_ascii
 
98
 
 
99
  module Pure
 
100
    module Generator
 
101
      # This class is used to create State instances, that are use to hold data
 
102
      # while generating a JSON text from a Ruby data structure.
 
103
      class State
 
104
        # Creates a State object from _opts_, which ought to be Hash to create
 
105
        # a new State instance configured by _opts_, something else to create
 
106
        # an unconfigured instance. If _opts_ is a State object, it is just
 
107
        # returned.
 
108
        def self.from_state(opts)
 
109
          case
 
110
          when self === opts
 
111
            opts
 
112
          when opts.respond_to?(:to_hash)
 
113
            new(opts.to_hash)
 
114
          when opts.respond_to?(:to_h)
 
115
            new(opts.to_h)
 
116
          else
 
117
            SAFE_STATE_PROTOTYPE.dup
 
118
          end
 
119
        end
 
120
 
 
121
        # Instantiates a new State object, configured by _opts_.
 
122
        #
 
123
        # _opts_ can have the following keys:
 
124
        #
 
125
        # * *indent*: a string used to indent levels (default: ''),
 
126
        # * *space*: a string that is put after, a : or , delimiter (default: ''),
 
127
        # * *space_before*: a string that is put before a : pair delimiter (default: ''),
 
128
        # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
 
129
        # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
 
130
        # * *check_circular*: is deprecated now, use the :max_nesting option instead,
 
131
        # * *max_nesting*: sets the maximum level of data structure nesting in
 
132
        #   the generated JSON, max_nesting = 0 if no maximum should be checked.
 
133
        # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
 
134
        #   generated, otherwise an exception is thrown, if these values are
 
135
        #   encountered. This options defaults to false.
 
136
        # * *quirks_mode*: Enables quirks_mode for parser, that is for example
 
137
        #   generating single JSON values instead of documents is possible.
 
138
        def initialize(opts = {})
 
139
          @indent                = ''
 
140
          @space                 = ''
 
141
          @space_before          = ''
 
142
          @object_nl             = ''
 
143
          @array_nl              = ''
 
144
          @allow_nan             = false
 
145
          @ascii_only            = false
 
146
          @quirks_mode           = false
 
147
          @buffer_initial_length = 1024
 
148
          configure opts
 
149
        end
 
150
 
 
151
        # This string is used to indent levels in the JSON text.
 
152
        attr_accessor :indent
 
153
 
 
154
        # This string is used to insert a space between the tokens in a JSON
 
155
        # string.
 
156
        attr_accessor :space
 
157
 
 
158
        # This string is used to insert a space before the ':' in JSON objects.
 
159
        attr_accessor :space_before
 
160
 
 
161
        # This string is put at the end of a line that holds a JSON object (or
 
162
        # Hash).
 
163
        attr_accessor :object_nl
 
164
 
 
165
        # This string is put at the end of a line that holds a JSON array.
 
166
        attr_accessor :array_nl
 
167
 
 
168
        # This integer returns the maximum level of data structure nesting in
 
169
        # the generated JSON, max_nesting = 0 if no maximum is checked.
 
170
        attr_accessor :max_nesting
 
171
 
 
172
        # If this attribute is set to true, quirks mode is enabled, otherwise
 
173
        # it's disabled.
 
174
        attr_accessor :quirks_mode
 
175
 
 
176
        # :stopdoc:
 
177
        attr_reader :buffer_initial_length
 
178
 
 
179
        def buffer_initial_length=(length)
 
180
          if length > 0
 
181
            @buffer_initial_length = length
 
182
          end
 
183
        end
 
184
        # :startdoc:
 
185
 
 
186
        # This integer returns the current depth data structure nesting in the
 
187
        # generated JSON.
 
188
        attr_accessor :depth
 
189
 
 
190
        def check_max_nesting # :nodoc:
 
191
          return if @max_nesting.zero?
 
192
          current_nesting = depth + 1
 
193
          current_nesting > @max_nesting and
 
194
            raise NestingError, "nesting of #{current_nesting} is too deep"
 
195
        end
 
196
 
 
197
        # Returns true, if circular data structures are checked,
 
198
        # otherwise returns false.
 
199
        def check_circular?
 
200
          !@max_nesting.zero?
 
201
        end
 
202
 
 
203
        # Returns true if NaN, Infinity, and -Infinity should be considered as
 
204
        # valid JSON and output.
 
205
        def allow_nan?
 
206
          @allow_nan
 
207
        end
 
208
 
 
209
        # Returns true, if only ASCII characters should be generated. Otherwise
 
210
        # returns false.
 
211
        def ascii_only?
 
212
          @ascii_only
 
213
        end
 
214
 
 
215
        # Returns true, if quirks mode is enabled. Otherwise returns false.
 
216
        def quirks_mode?
 
217
          @quirks_mode
 
218
        end
 
219
 
 
220
        # Configure this State instance with the Hash _opts_, and return
 
221
        # itself.
 
222
        def configure(opts)
 
223
          for key, value in opts
 
224
            instance_variable_set "@#{key}", value
 
225
          end
 
226
          @indent                = opts[:indent] if opts.key?(:indent)
 
227
          @space                 = opts[:space] if opts.key?(:space)
 
228
          @space_before          = opts[:space_before] if opts.key?(:space_before)
 
229
          @object_nl             = opts[:object_nl] if opts.key?(:object_nl)
 
230
          @array_nl              = opts[:array_nl] if opts.key?(:array_nl)
 
231
          @allow_nan             = !!opts[:allow_nan] if opts.key?(:allow_nan)
 
232
          @ascii_only            = opts[:ascii_only] if opts.key?(:ascii_only)
 
233
          @depth                 = opts[:depth] || 0
 
234
          @quirks_mode           = opts[:quirks_mode] if opts.key?(:quirks_mode)
 
235
          @buffer_initial_length ||= opts[:buffer_initial_length]
 
236
 
 
237
          if !opts.key?(:max_nesting) # defaults to 100
 
238
            @max_nesting = 100
 
239
          elsif opts[:max_nesting]
 
240
            @max_nesting = opts[:max_nesting]
 
241
          else
 
242
            @max_nesting = 0
 
243
          end
 
244
          self
 
245
        end
 
246
        alias merge configure
 
247
 
 
248
        # Returns the configuration instance variables as a hash, that can be
 
249
        # passed to the configure method.
 
250
        def to_h
 
251
          result = {}
 
252
          for iv in instance_variables
 
253
            iv = iv.to_s[1..-1]
 
254
            result[iv.to_sym] = self[iv]
 
255
          end
 
256
          result
 
257
        end
 
258
 
 
259
        alias to_hash to_h
 
260
 
 
261
        # Generates a valid JSON document from object +obj+ and returns the
 
262
        # result. If no valid JSON document can be created this method raises a
 
263
        # GeneratorError exception.
 
264
        def generate(obj)
 
265
          result = obj.to_json(self)
 
266
          unless @quirks_mode
 
267
            unless result =~ /\A\s*\[/ && result =~ /\]\s*\Z/ ||
 
268
              result =~ /\A\s*\{/ && result =~ /\}\s*\Z/
 
269
            then
 
270
              raise GeneratorError, "only generation of JSON objects or arrays allowed"
 
271
            end
 
272
          end
 
273
          result
 
274
        end
 
275
 
 
276
        # Return the value returned by method +name+.
 
277
        def [](name)
 
278
          if respond_to?(name)
 
279
            __send__(name)
 
280
          else
 
281
            instance_variable_get("@#{name}")
 
282
          end
 
283
        end
 
284
 
 
285
        def []=(name, value)
 
286
          if respond_to?(name_writer = "#{name}=")
 
287
            __send__ name_writer, value
 
288
          else
 
289
            instance_variable_set "@#{name}", value
 
290
          end
 
291
        end
 
292
      end
 
293
 
 
294
      module GeneratorMethods
 
295
        module Object
 
296
          # Converts this object to a string (calling #to_s), converts
 
297
          # it to a JSON string, and returns the result. This is a fallback, if no
 
298
          # special method #to_json was defined for some object.
 
299
          def to_json(*) to_s.to_json end
 
300
        end
 
301
 
 
302
        module Hash
 
303
          # Returns a JSON string containing a JSON object, that is unparsed from
 
304
          # this Hash instance.
 
305
          # _state_ is a JSON::State object, that can also be used to configure the
 
306
          # produced JSON string output further.
 
307
          # _depth_ is used to find out nesting depth, to indent accordingly.
 
308
          def to_json(state = nil, *)
 
309
            state = State.from_state(state)
 
310
            state.check_max_nesting
 
311
            json_transform(state)
 
312
          end
 
313
 
 
314
          private
 
315
 
 
316
          def json_shift(state)
 
317
            state.object_nl.empty? or return ''
 
318
            state.indent * state.depth
 
319
          end
 
320
 
 
321
          def json_transform(state)
 
322
            delim = ','
 
323
            delim << state.object_nl
 
324
            result = '{'
 
325
            result << state.object_nl
 
326
            depth = state.depth += 1
 
327
            first = true
 
328
            indent = !state.object_nl.empty?
 
329
            each { |key,value|
 
330
              result << delim unless first
 
331
              result << state.indent * depth if indent
 
332
              result << key.to_s.to_json(state)
 
333
              result << state.space_before
 
334
              result << ':'
 
335
              result << state.space
 
336
              result << value.to_json(state)
 
337
              first = false
 
338
            }
 
339
            depth = state.depth -= 1
 
340
            result << state.object_nl
 
341
            result << state.indent * depth if indent if indent
 
342
            result << '}'
 
343
            result
 
344
          end
 
345
        end
 
346
 
 
347
        module Array
 
348
          # Returns a JSON string containing a JSON array, that is unparsed from
 
349
          # this Array instance.
 
350
          # _state_ is a JSON::State object, that can also be used to configure the
 
351
          # produced JSON string output further.
 
352
          def to_json(state = nil, *)
 
353
            state = State.from_state(state)
 
354
            state.check_max_nesting
 
355
            json_transform(state)
 
356
          end
 
357
 
 
358
          private
 
359
 
 
360
          def json_transform(state)
 
361
            delim = ','
 
362
            delim << state.array_nl
 
363
            result = '['
 
364
            result << state.array_nl
 
365
            depth = state.depth += 1
 
366
            first = true
 
367
            indent = !state.array_nl.empty?
 
368
            each { |value|
 
369
              result << delim unless first
 
370
              result << state.indent * depth if indent
 
371
              result << value.to_json(state)
 
372
              first = false
 
373
            }
 
374
            depth = state.depth -= 1
 
375
            result << state.array_nl
 
376
            result << state.indent * depth if indent
 
377
            result << ']'
 
378
          end
 
379
        end
 
380
 
 
381
        module Integer
 
382
          # Returns a JSON string representation for this Integer number.
 
383
          def to_json(*) to_s end
 
384
        end
 
385
 
 
386
        module Float
 
387
          # Returns a JSON string representation for this Float number.
 
388
          def to_json(state = nil, *)
 
389
            state = State.from_state(state)
 
390
            case
 
391
            when infinite?
 
392
              if state.allow_nan?
 
393
                to_s
 
394
              else
 
395
                raise GeneratorError, "#{self} not allowed in JSON"
 
396
              end
 
397
            when nan?
 
398
              if state.allow_nan?
 
399
                to_s
 
400
              else
 
401
                raise GeneratorError, "#{self} not allowed in JSON"
 
402
              end
 
403
            else
 
404
              to_s
 
405
            end
 
406
          end
 
407
        end
 
408
 
 
409
        module String
 
410
          if defined?(::Encoding)
 
411
            # This string should be encoded with UTF-8 A call to this method
 
412
            # returns a JSON string encoded with UTF16 big endian characters as
 
413
            # \u????.
 
414
            def to_json(state = nil, *args)
 
415
              state = State.from_state(state)
 
416
              if encoding == ::Encoding::UTF_8
 
417
                string = self
 
418
              else
 
419
                string = encode(::Encoding::UTF_8)
 
420
              end
 
421
              if state.ascii_only?
 
422
                '"' << JSON.utf8_to_json_ascii(string) << '"'
 
423
              else
 
424
                '"' << JSON.utf8_to_json(string) << '"'
 
425
              end
 
426
            end
 
427
          else
 
428
            # This string should be encoded with UTF-8 A call to this method
 
429
            # returns a JSON string encoded with UTF16 big endian characters as
 
430
            # \u????.
 
431
            def to_json(state = nil, *args)
 
432
              state = State.from_state(state)
 
433
              if state.ascii_only?
 
434
                '"' << JSON.utf8_to_json_ascii(self) << '"'
 
435
              else
 
436
                '"' << JSON.utf8_to_json(self) << '"'
 
437
              end
 
438
            end
 
439
          end
 
440
 
 
441
          # Module that holds the extinding methods if, the String module is
 
442
          # included.
 
443
          module Extend
 
444
            # Raw Strings are JSON Objects (the raw bytes are stored in an
 
445
            # array for the key "raw"). The Ruby String can be created by this
 
446
            # module method.
 
447
            def json_create(o)
 
448
              o['raw'].pack('C*')
 
449
            end
 
450
          end
 
451
 
 
452
          # Extends _modul_ with the String::Extend module.
 
453
          def self.included(modul)
 
454
            modul.extend Extend
 
455
          end
 
456
 
 
457
          # This method creates a raw object hash, that can be nested into
 
458
          # other data structures and will be unparsed as a raw string. This
 
459
          # method should be used, if you want to convert raw strings to JSON
 
460
          # instead of UTF-8 strings, e. g. binary data.
 
461
          def to_json_raw_object
 
462
            {
 
463
              JSON.create_id  => self.class.name,
 
464
              'raw'           => self.unpack('C*'),
 
465
            }
 
466
          end
 
467
 
 
468
          # This method creates a JSON text from the result of
 
469
          # a call to to_json_raw_object of this String.
 
470
          def to_json_raw(*args)
 
471
            to_json_raw_object.to_json(*args)
 
472
          end
 
473
        end
 
474
 
 
475
        module TrueClass
 
476
          # Returns a JSON string for true: 'true'.
 
477
          def to_json(*) 'true' end
 
478
        end
 
479
 
 
480
        module FalseClass
 
481
          # Returns a JSON string for false: 'false'.
 
482
          def to_json(*) 'false' end
 
483
        end
 
484
 
 
485
        module NilClass
 
486
          # Returns a JSON string for nil: 'null'.
 
487
          def to_json(*) 'null' end
 
488
        end
 
489
      end
 
490
    end
 
491
  end
 
492
end