multi_json 1.5.0 → 1.15.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,12 +1,11 @@
1
- require 'json/pure' unless defined?(::JSON)
1
+ require 'json/pure'
2
2
  require 'multi_json/adapters/json_common'
3
3
 
4
4
  module MultiJson
5
5
  module Adapters
6
6
  # Use JSON pure to dump/load.
7
- class JsonPure
7
+ class JsonPure < JsonCommon
8
8
  ParseError = ::JSON::ParserError
9
- extend JsonCommon
10
9
  end
11
10
  end
12
11
  end
@@ -1,3 +1,6 @@
1
+ # This adapter is here for legacy reasons. We can't really test it, so it's hard
2
+ # to tell if it's even working properly. If you're still using it, please
3
+ # consider migrating to any other adapter out there.
1
4
  framework 'Foundation'
2
5
  require 'multi_json/adapters/ok_json'
3
6
 
@@ -6,29 +9,27 @@ module MultiJson
6
9
  class Nsjsonserialization < MultiJson::Adapters::OkJson
7
10
  ParseError = ::MultiJson::OkJson::Error
8
11
 
9
- def self.load(string, options={})
10
- string = string.read if string.respond_to?(:read)
12
+ def load(string, options = {})
11
13
  data = string.dataUsingEncoding(NSUTF8StringEncoding)
12
- object = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves, error: nil)
14
+ object = NSJSONSerialization.JSONObjectWithData(data, :options => NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves, :error => nil)
13
15
  if object
14
16
  object = symbolize_keys(object) if options[:symbolize_keys]
15
17
  object
16
18
  else
17
- super(string, options={})
19
+ super(string, options)
18
20
  end
19
21
  end
20
22
 
21
- def self.dump(object, options={})
23
+ def dump(object, options = {})
22
24
  pretty = options[:pretty] ? NSJSONWritingPrettyPrinted : 0
23
25
  object = object.as_json if object.respond_to?(:as_json)
24
26
  if NSJSONSerialization.isValidJSONObject(object)
25
- data = NSJSONSerialization.dataWithJSONObject(object, options: pretty, error: nil)
26
- NSMutableString.alloc.initWithData(data, encoding: NSUTF8StringEncoding)
27
+ data = NSJSONSerialization.dataWithJSONObject(object, :options => pretty, :error => nil)
28
+ NSMutableString.alloc.initWithData(data, :encoding => NSUTF8StringEncoding)
27
29
  else
28
30
  super(object, options)
29
31
  end
30
32
  end
31
-
32
33
  end
33
34
  end
34
35
  end
@@ -1,25 +1,62 @@
1
- require 'oj' unless defined?(::Oj)
1
+ require 'set'
2
+ require 'oj'
3
+ require 'multi_json/adapter'
2
4
 
3
5
  module MultiJson
4
6
  module Adapters
5
7
  # Use the Oj library to dump/load.
6
- class Oj
7
- ParseError = if defined?(::Oj::ParseError)
8
- ::Oj::ParseError
9
- else
10
- SyntaxError
11
- end
8
+ class Oj < Adapter
9
+ defaults :load, :mode => :strict, :symbolize_keys => false
10
+ defaults :dump, :mode => :compat, :time_format => :ruby, :use_to_json => true
11
+
12
+ # In certain cases OJ gem may throw JSON::ParserError exception instead
13
+ # of its own class. Also, we can't expect ::JSON::ParserError and
14
+ # ::Oj::ParseError to always be defined, since it's often not the case.
15
+ # Because of this, we can't reference those classes directly and have to
16
+ # do string comparison instead. This will not catch subclasses, but it
17
+ # shouldn't be a problem since the library is not known to be using it
18
+ # (at least for now).
19
+ class ParseError < ::SyntaxError
20
+ WRAPPED_CLASSES = %w[Oj::ParseError JSON::ParserError].to_set.freeze
12
21
 
13
- ::Oj.default_options = {:mode => :compat}
22
+ def self.===(exception)
23
+ case exception
24
+ when ::SyntaxError
25
+ true
26
+ else
27
+ WRAPPED_CLASSES.include?(exception.class.to_s)
28
+ end
29
+ end
30
+ end
14
31
 
15
- def self.load(string, options={}) #:nodoc:
16
- options.merge!(:symbol_keys => options[:symbolize_keys])
32
+ def load(string, options = {})
33
+ options[:symbol_keys] = options[:symbolize_keys]
17
34
  ::Oj.load(string, options)
18
35
  end
19
36
 
20
- def self.dump(object, options={}) #:nodoc:
21
- options.merge!(:indent => 2) if options[:pretty]
22
- ::Oj.dump(object, options)
37
+ case ::Oj::VERSION
38
+ when /\A2\./
39
+ def dump(object, options = {})
40
+ options.merge!(:indent => 2) if options[:pretty]
41
+ options[:indent] = options[:indent].to_i if options[:indent]
42
+ ::Oj.dump(object, options)
43
+ end
44
+ when /\A3\./
45
+ PRETTY_STATE_PROTOTYPE = {
46
+ :indent => " ",
47
+ :space => " ",
48
+ :space_before => "",
49
+ :object_nl => "\n",
50
+ :array_nl => "\n",
51
+ :ascii_only => false,
52
+ }
53
+
54
+ def dump(object, options = {})
55
+ options.merge!(PRETTY_STATE_PROTOTYPE.dup) if options.delete(:pretty)
56
+ ::Oj.dump(object, options)
57
+ end
58
+ else
59
+ fail "Unsupported Oj version: #{::Oj::VERSION}"
23
60
  end
24
61
  end
25
62
  end
@@ -1,48 +1,23 @@
1
+ require 'multi_json/adapter'
2
+ require 'multi_json/convertible_hash_keys'
1
3
  require 'multi_json/vendor/okjson'
2
4
 
3
5
  module MultiJson
4
6
  module Adapters
5
- class OkJson
7
+ class OkJson < Adapter
8
+ include ConvertibleHashKeys
6
9
  ParseError = ::MultiJson::OkJson::Error
7
10
 
8
- def self.load(string, options={}) #:nodoc:
9
- string = string.read if string.respond_to?(:read)
11
+ def load(string, options = {})
10
12
  result = ::MultiJson::OkJson.decode("[#{string}]").first
11
13
  options[:symbolize_keys] ? symbolize_keys(result) : result
14
+ rescue ArgumentError # invalid byte sequence in UTF-8
15
+ raise ParseError
12
16
  end
13
17
 
14
- def self.dump(object, options={}) #:nodoc:
18
+ def dump(object, _ = {})
15
19
  ::MultiJson::OkJson.valenc(stringify_keys(object))
16
20
  end
17
-
18
- def self.symbolize_keys(object) #:nodoc:
19
- modify_keys(object) do |key|
20
- key.is_a?(String) ? key.to_sym : key
21
- end
22
- end
23
-
24
- def self.stringify_keys(object) #:nodoc:
25
- modify_keys(object) do |key|
26
- key.respond_to?(:to_s) ? key.to_s : key
27
- end
28
- end
29
-
30
- def self.modify_keys(object, &modifier) #:nodoc:
31
- case object
32
- when Array
33
- object.map do |value|
34
- modify_keys(value, &modifier)
35
- end
36
- when Hash
37
- object.inject({}) do |result, (key, value)|
38
- new_key = modifier.call(key)
39
- new_value = modify_keys(value, &modifier)
40
- result.merge! new_key => new_value
41
- end
42
- else
43
- object
44
- end
45
- end
46
21
  end
47
22
  end
48
23
  end
@@ -1,16 +1,17 @@
1
- require 'yajl' unless defined?(::Yajl)
1
+ require 'yajl'
2
+ require 'multi_json/adapter'
2
3
 
3
4
  module MultiJson
4
5
  module Adapters
5
6
  # Use the Yajl-Ruby library to dump/load.
6
- class Yajl
7
+ class Yajl < Adapter
7
8
  ParseError = ::Yajl::ParseError
8
9
 
9
- def self.load(string, options={}) #:nodoc:
10
+ def load(string, options = {})
10
11
  ::Yajl::Parser.new(:symbolize_keys => options[:symbolize_keys]).parse(string)
11
12
  end
12
13
 
13
- def self.dump(object, options={}) #:nodoc:
14
+ def dump(object, options = {})
14
15
  ::Yajl::Encoder.encode(object, options)
15
16
  end
16
17
  end
@@ -0,0 +1,43 @@
1
+ module MultiJson
2
+ module ConvertibleHashKeys
3
+ private
4
+
5
+ def symbolize_keys(hash)
6
+ prepare_hash(hash) do |key|
7
+ key.respond_to?(:to_sym) ? key.to_sym : key
8
+ end
9
+ end
10
+
11
+ def stringify_keys(hash)
12
+ prepare_hash(hash) do |key|
13
+ key.respond_to?(:to_s) ? key.to_s : key
14
+ end
15
+ end
16
+
17
+ def prepare_hash(hash, &key_modifier)
18
+ return hash unless block_given?
19
+ case hash
20
+ when Array
21
+ hash.map do |value|
22
+ prepare_hash(value, &key_modifier)
23
+ end
24
+ when Hash
25
+ hash.inject({}) do |result, (key, value)|
26
+ new_key = key_modifier.call(key)
27
+ new_value = prepare_hash(value, &key_modifier)
28
+ result.merge! new_key => new_value
29
+ end
30
+ when String, Numeric, true, false, nil
31
+ hash
32
+ else
33
+ if hash.respond_to?(:to_json)
34
+ hash
35
+ elsif hash.respond_to?(:to_s)
36
+ hash.to_s
37
+ else
38
+ hash
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,39 @@
1
+ module MultiJson
2
+ module Options
3
+ def load_options=(options)
4
+ OptionsCache.reset
5
+ @load_options = options
6
+ end
7
+
8
+ def dump_options=(options)
9
+ OptionsCache.reset
10
+ @dump_options = options
11
+ end
12
+
13
+ def load_options(*args)
14
+ defined?(@load_options) && get_options(@load_options, *args) || default_load_options
15
+ end
16
+
17
+ def dump_options(*args)
18
+ defined?(@dump_options) && get_options(@dump_options, *args) || default_dump_options
19
+ end
20
+
21
+ def default_load_options
22
+ @default_load_options ||= {}
23
+ end
24
+
25
+ def default_dump_options
26
+ @default_dump_options ||= {}
27
+ end
28
+
29
+ private
30
+
31
+ def get_options(options, *args)
32
+ if options.respond_to?(:call) && options.arity
33
+ options.arity == 0 ? options[] : options[*args]
34
+ elsif options.respond_to?(:to_hash)
35
+ options.to_hash
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ module MultiJson
2
+ module OptionsCache
3
+ extend self
4
+
5
+ def reset
6
+ @dump_cache = {}
7
+ @load_cache = {}
8
+ end
9
+
10
+ def fetch(type, key, &block)
11
+ cache = instance_variable_get("@#{type}_cache")
12
+ cache.key?(key) ? cache[key] : write(cache, key, &block)
13
+ end
14
+
15
+ private
16
+
17
+ # Normally MultiJson is used with a few option sets for both dump/load
18
+ # methods. When options are generated dynamically though, every call would
19
+ # cause a cache miss and the cache would grow indefinitely. To prevent
20
+ # this, we just reset the cache every time the number of keys outgrows
21
+ # 1000.
22
+ MAX_CACHE_SIZE = 1000
23
+
24
+ def write(cache, key)
25
+ cache.clear if cache.length >= MAX_CACHE_SIZE
26
+ cache[key] = yield
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ module MultiJson
2
+ class ParseError < StandardError
3
+ attr_reader :data, :cause
4
+
5
+ def self.build(original_exception, data)
6
+ new(original_exception.message).tap do |exception|
7
+ exception.instance_eval do
8
+ @cause = original_exception
9
+ set_backtrace original_exception.backtrace
10
+ @data = data
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ DecodeError = LoadError = ParseError # Legacy support
17
+ end
@@ -24,11 +24,12 @@
24
24
 
25
25
  require 'stringio'
26
26
 
27
- # Some parts adapted from
28
- # http://golang.org/src/pkg/json/decode.go and
29
- # http://golang.org/src/pkg/utf8/utf8.go
30
27
  module MultiJson
28
+ # Some parts adapted from
29
+ # https://golang.org/src/encoding/json/decode.go and
30
+ # https://golang.org/src/unicode/utf8/utf8.go
31
31
  module OkJson
32
+ Upstream = '45'
32
33
  extend self
33
34
 
34
35
 
@@ -50,12 +51,53 @@ module MultiJson
50
51
  end
51
52
 
52
53
 
54
+ # Encodes x into a json text. It may contain only
55
+ # Array, Hash, String, Numeric, true, false, nil.
56
+ # (Note, this list excludes Symbol.)
57
+ # X itself must be an Array or a Hash.
58
+ # No other value can be encoded, and an error will
59
+ # be raised if x contains any other value, such as
60
+ # Nan, Infinity, Symbol, and Proc, or if a Hash key
61
+ # is not a String.
62
+ # Strings contained in x must be valid UTF-8.
63
+ def encode(x)
64
+ case x
65
+ when Hash then objenc(x)
66
+ when Array then arrenc(x)
67
+ else
68
+ raise Error, 'root value must be an Array or a Hash'
69
+ end
70
+ end
71
+
72
+
73
+ def valenc(x)
74
+ case x
75
+ when Hash then objenc(x)
76
+ when Array then arrenc(x)
77
+ when String then strenc(x)
78
+ when Numeric then numenc(x)
79
+ when true then "true"
80
+ when false then "false"
81
+ when nil then "null"
82
+ else
83
+ if x.respond_to?(:to_json)
84
+ x.to_json
85
+ else
86
+ raise Error, "cannot encode #{x.class}: #{x.inspect}"
87
+ end
88
+ end
89
+ end
90
+
91
+
92
+ private
93
+
94
+
53
95
  # Parses a "json text" in the sense of RFC 4627.
54
96
  # Returns the parsed value and any trailing tokens.
55
97
  # Note: this is almost the same as valparse,
56
98
  # except that it does not accept atomic values.
57
99
  def textparse(ts)
58
- if ts.length < 0
100
+ if ts.length <= 0
59
101
  raise Error, 'empty'
60
102
  end
61
103
 
@@ -72,7 +114,7 @@ module MultiJson
72
114
  # Parses a "value" in the sense of RFC 4627.
73
115
  # Returns the parsed value and any trailing tokens.
74
116
  def valparse(ts)
75
- if ts.length < 0
117
+ if ts.length <= 0
76
118
  raise Error, 'empty'
77
119
  end
78
120
 
@@ -201,21 +243,19 @@ module MultiJson
201
243
  # it is the lexeme.
202
244
  def tok(s)
203
245
  case s[0]
204
- when ?{ then ['{', s[0,1], s[0,1]]
205
- when ?} then ['}', s[0,1], s[0,1]]
206
- when ?: then [':', s[0,1], s[0,1]]
207
- when ?, then [',', s[0,1], s[0,1]]
208
- when ?[ then ['[', s[0,1], s[0,1]]
209
- when ?] then [']', s[0,1], s[0,1]]
210
- when ?n then nulltok(s)
211
- when ?t then truetok(s)
212
- when ?f then falsetok(s)
213
- when ?" then strtok(s)
214
- when Spc then [:space, s[0,1], s[0,1]]
215
- when ?\t then [:space, s[0,1], s[0,1]]
216
- when ?\n then [:space, s[0,1], s[0,1]]
217
- when ?\r then [:space, s[0,1], s[0,1]]
218
- else numtok(s)
246
+ when ?{ then ['{', s[0,1], s[0,1]]
247
+ when ?} then ['}', s[0,1], s[0,1]]
248
+ when ?: then [':', s[0,1], s[0,1]]
249
+ when ?, then [',', s[0,1], s[0,1]]
250
+ when ?[ then ['[', s[0,1], s[0,1]]
251
+ when ?] then [']', s[0,1], s[0,1]]
252
+ when ?n then nulltok(s)
253
+ when ?t then truetok(s)
254
+ when ?f then falsetok(s)
255
+ when ?" then strtok(s)
256
+ when Spc, ?\t, ?\n, ?\r then [:space, s[0,1], s[0,1]]
257
+ else
258
+ numtok(s)
219
259
  end
220
260
  end
221
261
 
@@ -226,14 +266,14 @@ module MultiJson
226
266
 
227
267
 
228
268
  def numtok(s)
229
- m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
269
+ m = /(-?(?:[1-9][0-9]+|[0-9]))([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
230
270
  if m && m.begin(0) == 0
231
- if m[3] && !m[2]
232
- [:val, m[0], Integer(m[1])*(10**Integer(m[3][1..-1]))]
271
+ if !m[2] && !m[3]
272
+ [:val, m[0], Integer(m[0])]
233
273
  elsif m[2]
234
274
  [:val, m[0], Float(m[0])]
235
275
  else
236
- [:val, m[0], Integer(m[0])]
276
+ [:val, m[0], Integer(m[1])*(10**m[3][1..-1].to_i(10))]
237
277
  end
238
278
  else
239
279
  []
@@ -265,17 +305,14 @@ module MultiJson
265
305
  def unquote(q)
266
306
  q = q[1...-1]
267
307
  a = q.dup # allocate a big enough string
268
- rubydoesenc = false
269
308
  # In ruby >= 1.9, a[w] is a codepoint, not a byte.
270
- if a.class.method_defined?(:force_encoding)
309
+ if rubydoesenc?
271
310
  a.force_encoding('UTF-8')
272
- rubydoesenc = true
273
311
  end
274
312
  r, w = 0, 0
275
313
  while r < q.length
276
314
  c = q[r]
277
- case true
278
- when c == ?\\
315
+ if c == ?\\
279
316
  r += 1
280
317
  if r >= q.length
281
318
  raise Error, "string literal ends with a \"\\\": \"#{q}\""
@@ -308,7 +345,7 @@ module MultiJson
308
345
  end
309
346
  end
310
347
  end
311
- if rubydoesenc
348
+ if rubydoesenc?
312
349
  a[w] = '' << uchar
313
350
  w += 1
314
351
  else
@@ -317,7 +354,7 @@ module MultiJson
317
354
  else
318
355
  raise Error, "invalid escape char #{q[r]} in \"#{q}\""
319
356
  end
320
- when c == ?", c < Spc
357
+ elsif c == ?" || c < Spc
321
358
  raise Error, "invalid character in string literal \"#{q}\""
322
359
  else
323
360
  # Copy anything else byte-for-byte.
@@ -338,15 +375,14 @@ module MultiJson
338
375
  # bytes in string a at position i.
339
376
  # Returns the number of bytes written.
340
377
  def ucharenc(a, i, u)
341
- case true
342
- when u <= Uchar1max
378
+ if u <= Uchar1max
343
379
  a[i] = (u & 0xff).chr
344
380
  1
345
- when u <= Uchar2max
381
+ elsif u <= Uchar2max
346
382
  a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
347
383
  a[i+1] = (Utagx | (u&Umaskx)).chr
348
384
  2
349
- when u <= Uchar3max
385
+ elsif u <= Uchar3max
350
386
  a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
351
387
  a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
352
388
  a[i+2] = (Utagx | (u&Umaskx)).chr
@@ -383,54 +419,15 @@ module MultiJson
383
419
 
384
420
 
385
421
  def nibble(c)
386
- case true
387
- when ?0 <= c && c <= ?9 then c.ord - ?0.ord
388
- when ?a <= c && c <= ?z then c.ord - ?a.ord + 10
389
- when ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
422
+ if ?0 <= c && c <= ?9 then c.ord - ?0.ord
423
+ elsif ?a <= c && c <= ?z then c.ord - ?a.ord + 10
424
+ elsif ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
390
425
  else
391
426
  raise Error, "invalid hex code #{c}"
392
427
  end
393
428
  end
394
429
 
395
430
 
396
- # Encodes x into a json text. It may contain only
397
- # Array, Hash, String, Numeric, true, false, nil.
398
- # (Note, this list excludes Symbol.)
399
- # X itself must be an Array or a Hash.
400
- # No other value can be encoded, and an error will
401
- # be raised if x contains any other value, such as
402
- # Nan, Infinity, Symbol, and Proc, or if a Hash key
403
- # is not a String.
404
- # Strings contained in x must be valid UTF-8.
405
- def encode(x)
406
- case x
407
- when Hash then objenc(x)
408
- when Array then arrenc(x)
409
- else
410
- raise Error, 'root value must be an Array or a Hash'
411
- end
412
- end
413
-
414
-
415
- def valenc(x)
416
- case x
417
- when Hash then objenc(x)
418
- when Array then arrenc(x)
419
- when String then strenc(x)
420
- when Numeric then numenc(x)
421
- when true then "true"
422
- when false then "false"
423
- when nil then "null"
424
- else
425
- if x.respond_to?(:to_json)
426
- x.to_json
427
- else
428
- raise Error, "cannot encode #{x.class}: #{x.inspect}"
429
- end
430
- end
431
- end
432
-
433
-
434
431
  def objenc(x)
435
432
  '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
436
433
  end
@@ -455,9 +452,6 @@ module MultiJson
455
452
  t.putc(?")
456
453
  r = 0
457
454
 
458
- # In ruby >= 1.9, s[r] is a codepoint, not a byte.
459
- rubydoesenc = s.class.method_defined?(:encoding)
460
-
461
455
  while r < s.length
462
456
  case s[r]
463
457
  when ?" then t.print('\\"')
@@ -469,15 +463,20 @@ module MultiJson
469
463
  when ?\t then t.print('\\t')
470
464
  else
471
465
  c = s[r]
472
- case true
473
- when rubydoesenc
466
+ # In ruby >= 1.9, s[r] is a codepoint, not a byte.
467
+ if rubydoesenc?
474
468
  begin
475
- c.ord # will raise an error if c is invalid UTF-8
469
+ # c.ord will raise an error if c is invalid UTF-8
470
+ if c.ord < Spc.ord
471
+ c = "\\u%04x" % [c.ord]
472
+ end
476
473
  t.write(c)
477
474
  rescue
478
475
  t.write(Ustrerr)
479
476
  end
480
- when Spc <= c && c <= ?~
477
+ elsif c < Spc
478
+ t.write("\\u%04x" % c)
479
+ elsif Spc <= c && c <= ?~
481
480
  t.putc(c)
482
481
  else
483
482
  n = ucharcopy(t, s, r) # ensure valid UTF-8 output
@@ -569,6 +568,11 @@ module MultiJson
569
568
  end
570
569
 
571
570
 
571
+ def rubydoesenc?
572
+ ::String.method_defined?(:force_encoding)
573
+ end
574
+
575
+
572
576
  class Utf8Error < ::StandardError
573
577
  end
574
578
 
@@ -577,15 +581,15 @@ module MultiJson
577
581
  end
578
582
 
579
583
 
580
- Utagx = 0x80 # 1000 0000
581
- Utag2 = 0xc0 # 1100 0000
582
- Utag3 = 0xe0 # 1110 0000
583
- Utag4 = 0xf0 # 1111 0000
584
- Utag5 = 0xF8 # 1111 1000
585
- Umaskx = 0x3f # 0011 1111
586
- Umask2 = 0x1f # 0001 1111
587
- Umask3 = 0x0f # 0000 1111
588
- Umask4 = 0x07 # 0000 0111
584
+ Utagx = 0b1000_0000
585
+ Utag2 = 0b1100_0000
586
+ Utag3 = 0b1110_0000
587
+ Utag4 = 0b1111_0000
588
+ Utag5 = 0b1111_1000
589
+ Umaskx = 0b0011_1111
590
+ Umask2 = 0b0001_1111
591
+ Umask3 = 0b0000_1111
592
+ Umask4 = 0b0000_0111
589
593
  Uchar1max = (1<<7) - 1
590
594
  Uchar2max = (1<<11) - 1
591
595
  Uchar3max = (1<<16) - 1
@@ -1,3 +1,17 @@
1
1
  module MultiJson
2
- VERSION = "1.5.0" unless defined?(MultiJson::VERSION)
2
+ class Version
3
+ MAJOR = 1 unless defined? MultiJson::Version::MAJOR
4
+ MINOR = 15 unless defined? MultiJson::Version::MINOR
5
+ PATCH = 0 unless defined? MultiJson::Version::PATCH
6
+ PRE = nil unless defined? MultiJson::Version::PRE
7
+
8
+ class << self
9
+ # @return [String]
10
+ def to_s
11
+ [MAJOR, MINOR, PATCH, PRE].compact.join('.')
12
+ end
13
+ end
14
+ end
15
+
16
+ VERSION = Version.to_s.freeze
3
17
  end