fire_and_forget 0.2.0 → 0.3.0

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.
@@ -1,441 +0,0 @@
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.force_encoding(::Encoding::UTF_8)
48
- string
49
- end
50
-
51
- def utf8_to_json_ascii(string) # :nodoc:
52
- string = string.dup
53
- string << '' # XXX workaround: avoid buffer sharing
54
- string.force_encoding(::Encoding::ASCII_8BIT)
55
- string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
56
- string.gsub!(/(
57
- (?:
58
- [\xc2-\xdf][\x80-\xbf] |
59
- [\xe0-\xef][\x80-\xbf]{2} |
60
- [\xf0-\xf4][\x80-\xbf]{3}
61
- )+ |
62
- [\x80-\xc1\xf5-\xff] # invalid
63
- )/nx) { |c|
64
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
65
- s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
66
- s.gsub!(/.{4}/n, '\\\\u\&')
67
- }
68
- string.force_encoding(::Encoding::UTF_8)
69
- string
70
- rescue => e
71
- raise GeneratorError, "Caught #{e.class}: #{e}"
72
- end
73
- else
74
- def utf8_to_json(string) # :nodoc:
75
- string.gsub(/["\\\x0-\x1f]/) { 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, "Caught #{e.class}: #{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 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
- def initialize(opts = {})
137
- @indent = ''
138
- @space = ''
139
- @space_before = ''
140
- @object_nl = ''
141
- @array_nl = ''
142
- @allow_nan = false
143
- @ascii_only = false
144
- configure opts
145
- end
146
-
147
- # This string is used to indent levels in the JSON text.
148
- attr_accessor :indent
149
-
150
- # This string is used to insert a space between the tokens in a JSON
151
- # string.
152
- attr_accessor :space
153
-
154
- # This string is used to insert a space before the ':' in JSON objects.
155
- attr_accessor :space_before
156
-
157
- # This string is put at the end of a line that holds a JSON object (or
158
- # Hash).
159
- attr_accessor :object_nl
160
-
161
- # This string is put at the end of a line that holds a JSON array.
162
- attr_accessor :array_nl
163
-
164
- # This integer returns the maximum level of data structure nesting in
165
- # the generated JSON, max_nesting = 0 if no maximum is checked.
166
- attr_accessor :max_nesting
167
-
168
- # This integer returns the current depth data structure nesting in the
169
- # generated JSON.
170
- attr_accessor :depth
171
-
172
- def check_max_nesting # :nodoc:
173
- return if @max_nesting.zero?
174
- current_nesting = depth + 1
175
- current_nesting > @max_nesting and
176
- raise NestingError, "nesting of #{current_nesting} is too deep"
177
- end
178
-
179
- # Returns true, if circular data structures are checked,
180
- # otherwise returns false.
181
- def check_circular?
182
- !@max_nesting.zero?
183
- end
184
-
185
- # Returns true if NaN, Infinity, and -Infinity should be considered as
186
- # valid JSON and output.
187
- def allow_nan?
188
- @allow_nan
189
- end
190
-
191
- def ascii_only?
192
- @ascii_only
193
- end
194
-
195
- # Configure this State instance with the Hash _opts_, and return
196
- # itself.
197
- def configure(opts)
198
- @indent = opts[:indent] if opts.key?(:indent)
199
- @space = opts[:space] if opts.key?(:space)
200
- @space_before = opts[:space_before] if opts.key?(:space_before)
201
- @object_nl = opts[:object_nl] if opts.key?(:object_nl)
202
- @array_nl = opts[:array_nl] if opts.key?(:array_nl)
203
- @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
204
- @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
205
- @depth = opts[:depth] || 0
206
- if !opts.key?(:max_nesting) # defaults to 19
207
- @max_nesting = 19
208
- elsif opts[:max_nesting]
209
- @max_nesting = opts[:max_nesting]
210
- else
211
- @max_nesting = 0
212
- end
213
- self
214
- end
215
-
216
- # Returns the configuration instance variables as a hash, that can be
217
- # passed to the configure method.
218
- def to_h
219
- result = {}
220
- for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting ascii_only depth]
221
- result[iv.intern] = instance_variable_get("@#{iv}")
222
- end
223
- result
224
- end
225
-
226
- # Generates a valid JSON document from object +obj+ and returns the
227
- # result. If no valid JSON document can be created this method raises a
228
- # GeneratorError exception.
229
- def generate(obj)
230
- result = obj.to_json(self)
231
- if result !~ /\A\s*(?:\[.*\]|\{.*\})\s*\Z/m
232
- raise GeneratorError, "only generation of JSON objects or arrays allowed"
233
- end
234
- result
235
- end
236
-
237
- # Return the value returned by method +name+.
238
- def [](name)
239
- __send__ name
240
- end
241
- end
242
-
243
- module GeneratorMethods
244
- module Object
245
- # Converts this object to a string (calling #to_s), converts
246
- # it to a JSON string, and returns the result. This is a fallback, if no
247
- # special method #to_json was defined for some object.
248
- def to_json(*) to_s.to_json end
249
- end
250
-
251
- module Hash
252
- # Returns a JSON string containing a JSON object, that is unparsed from
253
- # this Hash instance.
254
- # _state_ is a JSON::State object, that can also be used to configure the
255
- # produced JSON string output further.
256
- # _depth_ is used to find out nesting depth, to indent accordingly.
257
- def to_json(state = nil, *)
258
- state = State.from_state(state)
259
- state.check_max_nesting
260
- json_transform(state)
261
- end
262
-
263
- private
264
-
265
- def json_shift(state)
266
- state.object_nl.empty? or return ''
267
- state.indent * state.depth
268
- end
269
-
270
- def json_transform(state)
271
- delim = ','
272
- delim << state.object_nl
273
- result = '{'
274
- result << state.object_nl
275
- depth = state.depth += 1
276
- first = true
277
- indent = !state.object_nl.empty?
278
- each { |key,value|
279
- result << delim unless first
280
- result << state.indent * depth if indent
281
- result << key.to_s.to_json(state)
282
- result << state.space_before
283
- result << ':'
284
- result << state.space
285
- result << value.to_json(state)
286
- first = false
287
- }
288
- depth = state.depth -= 1
289
- result << state.object_nl
290
- result << state.indent * depth if indent if indent
291
- result << '}'
292
- result
293
- end
294
- end
295
-
296
- module Array
297
- # Returns a JSON string containing a JSON array, that is unparsed from
298
- # this Array instance.
299
- # _state_ is a JSON::State object, that can also be used to configure the
300
- # produced JSON string output further.
301
- def to_json(state = nil, *)
302
- state = State.from_state(state)
303
- state.check_max_nesting
304
- json_transform(state)
305
- end
306
-
307
- private
308
-
309
- def json_transform(state)
310
- delim = ','
311
- delim << state.array_nl
312
- result = '['
313
- result << state.array_nl
314
- depth = state.depth += 1
315
- first = true
316
- indent = !state.array_nl.empty?
317
- each { |value|
318
- result << delim unless first
319
- result << state.indent * depth if indent
320
- result << value.to_json(state)
321
- first = false
322
- }
323
- depth = state.depth -= 1
324
- result << state.array_nl
325
- result << state.indent * depth if indent
326
- result << ']'
327
- end
328
- end
329
-
330
- module Integer
331
- # Returns a JSON string representation for this Integer number.
332
- def to_json(*) to_s end
333
- end
334
-
335
- module Float
336
- # Returns a JSON string representation for this Float number.
337
- def to_json(state = nil, *)
338
- state = State.from_state(state)
339
- case
340
- when infinite?
341
- if state.allow_nan?
342
- to_s
343
- else
344
- raise GeneratorError, "#{self} not allowed in JSON"
345
- end
346
- when nan?
347
- if state.allow_nan?
348
- to_s
349
- else
350
- raise GeneratorError, "#{self} not allowed in JSON"
351
- end
352
- else
353
- to_s
354
- end
355
- end
356
- end
357
-
358
- module String
359
- if defined?(::Encoding)
360
- # This string should be encoded with UTF-8 A call to this method
361
- # returns a JSON string encoded with UTF16 big endian characters as
362
- # \u????.
363
- def to_json(state = nil, *args)
364
- state = State.from_state(state)
365
- if encoding == ::Encoding::UTF_8
366
- string = self
367
- else
368
- string = encode(::Encoding::UTF_8)
369
- end
370
- if state.ascii_only?
371
- '"' << JSON.utf8_to_json_ascii(string) << '"'
372
- else
373
- '"' << JSON.utf8_to_json(string) << '"'
374
- end
375
- end
376
- else
377
- # This string should be encoded with UTF-8 A call to this method
378
- # returns a JSON string encoded with UTF16 big endian characters as
379
- # \u????.
380
- def to_json(state = nil, *args)
381
- state = State.from_state(state)
382
- if state.ascii_only?
383
- '"' << JSON.utf8_to_json_ascii(self) << '"'
384
- else
385
- '"' << JSON.utf8_to_json(self) << '"'
386
- end
387
- end
388
- end
389
-
390
- # Module that holds the extinding methods if, the String module is
391
- # included.
392
- module Extend
393
- # Raw Strings are JSON Objects (the raw bytes are stored in an
394
- # array for the key "raw"). The Ruby String can be created by this
395
- # module method.
396
- def json_create(o)
397
- o['raw'].pack('C*')
398
- end
399
- end
400
-
401
- # Extends _modul_ with the String::Extend module.
402
- def self.included(modul)
403
- modul.extend Extend
404
- end
405
-
406
- # This method creates a raw object hash, that can be nested into
407
- # other data structures and will be unparsed as a raw string. This
408
- # method should be used, if you want to convert raw strings to JSON
409
- # instead of UTF-8 strings, e. g. binary data.
410
- def to_json_raw_object
411
- {
412
- JSON.create_id => self.class.name,
413
- 'raw' => self.unpack('C*'),
414
- }
415
- end
416
-
417
- # This method creates a JSON text from the result of
418
- # a call to to_json_raw_object of this String.
419
- def to_json_raw(*args)
420
- to_json_raw_object.to_json(*args)
421
- end
422
- end
423
-
424
- module TrueClass
425
- # Returns a JSON string for true: 'true'.
426
- def to_json(*) 'true' end
427
- end
428
-
429
- module FalseClass
430
- # Returns a JSON string for false: 'false'.
431
- def to_json(*) 'false' end
432
- end
433
-
434
- module NilClass
435
- # Returns a JSON string for nil: 'null'.
436
- def to_json(*) 'null' end
437
- end
438
- end
439
- end
440
- end
441
- end