oj 2.9.4 → 2.9.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 472794bb4413026604920270cbf2d91e9486184d
4
- data.tar.gz: da2a776a8dd4e69c8b34bfbc478dbbcd11c60db3
3
+ metadata.gz: e14bd3bc917698abb03e0a65db6ad92ebc89cb38
4
+ data.tar.gz: 1290ce177f66c2dffb8dd852b03faab17bab15ec
5
5
  SHA512:
6
- metadata.gz: b4619f73d69dde844139216836a04570e2abb5103a0235e7199d3a98449c8b6f8c96385f86e627f6592d0095229d329f3f9d0b608b1eb09a9381e7b0d626f398
7
- data.tar.gz: 2dcd720bd6e964c23f33e83227163388bc72b8294c583501bc51ef79d24b7395771f0657b5ba575ea638e2814b1fa3bdc707db8cec6d565638399befac751d03
6
+ metadata.gz: 92b820c57e3c81d2fb716d9726476fb28dd13384436910caec2d930f2464249066d4a9326e519c76dc8aeba7194bfa12e5d00acd69a8aadf81d85ada921b949c
7
+ data.tar.gz: 126a7c2f3ebc4c660894df4d75f723e9180e7fd38c1e25ec56b79d29f10299eab2b40a81ee8899fe496eaee91754d09d96b41c6f81eae422729c3c5b6f579f2c
data/README.md CHANGED
@@ -26,9 +26,21 @@ Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announceme
26
26
 
27
27
  [![Build Status](https://secure.travis-ci.org/ohler55/oj.png?branch=master)](http://travis-ci.org/ohler55/oj)
28
28
 
29
+ ### Current Release 2.9.5
30
+
31
+ - Mimic mode now monkey patches Object like JSON.
32
+
33
+ - A big thanks to krasnoukhov for reorganizing test and helping get Oj more
34
+ rails compatible.
35
+
36
+ - Another thanks goes out to lautis for a pull request that provided some
37
+ optimization and fixed the return exception for an embedded null in a string.
38
+
39
+ - Fixed a bug with zip reader streams where EOF was not handled nicely.
40
+
29
41
  ### Current Release 2.9.4
30
42
 
31
- - In mimic mode parse errors not match the JSON::ParserError.
43
+ - In mimic mode parse errors now match the JSON::ParserError.
32
44
 
33
45
  [Older release notes](http://www.ohler.com/dev/oj_misc/release_notes.html).
34
46
 
@@ -60,6 +72,10 @@ is the `:object` mode.
60
72
  preferred over the `to_json` method. If neither the `to_json` or `to_hash`
61
73
  methods exists, then the Oj internal `Object` variable encoding is used.
62
74
 
75
+ To change default serialization mode:
76
+ ```ruby
77
+ Oj.default_options[:mode] = :compat
78
+ ```
63
79
 
64
80
  ## Compatibility
65
81
 
@@ -113,7 +113,7 @@ static const char hex_chars[17] = "0123456789abcdef";
113
113
 
114
114
  static char hibit_friendly_chars[256] = "\
115
115
  66666666222622666666666666666666\
116
- 11211111111111111111111111111111\
116
+ 11211111111111121111111111111111\
117
117
  11111111111111111111111111112111\
118
118
  11111111111111111111111111111111\
119
119
  11111111111111111111111111111111\
@@ -512,6 +512,7 @@ dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out) {
512
512
  case '2':
513
513
  *out->cur++ = '\\';
514
514
  switch (*str) {
515
+ case '\\': *out->cur++ = '\\'; break;
515
516
  case '\b': *out->cur++ = 'b'; break;
516
517
  case '\t': *out->cur++ = 't'; break;
517
518
  case '\n': *out->cur++ = 'n'; break;
@@ -177,7 +177,7 @@ static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
177
177
  * - circular: [true|false|nil] support circular references while dumping
178
178
  * - auto_define: [true|false|nil] automatically define classes if they do not exist
179
179
  * - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
180
- * - escape_mode: [:json|:xss_safe|:ascii|nil] use symbols instead of strings for hash keys
180
+ * - escape_mode: [:json|:xss_safe|:ascii|nil] determines the characters to escape
181
181
  * - class_cache: [true|false|nil] cache classes for faster parsing (if dynamically modifying classes or reloading classes then don't use this)
182
182
  * - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
183
183
  * - time_format: [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
@@ -1680,6 +1680,48 @@ mimic_create_id(VALUE self, VALUE id) {
1680
1680
  return id;
1681
1681
  }
1682
1682
 
1683
+ static struct _Options mimic_object_to_json_options = {
1684
+ 0, // indent
1685
+ No, // circular
1686
+ No, // auto_define
1687
+ No, // sym_key
1688
+ JSONEsc, // escape_mode
1689
+ CompatMode, // mode
1690
+ No, // class_cache
1691
+ UnixTime, // time_format
1692
+ Yes, // bigdec_as_num
1693
+ AutoDec, // bigdec_load
1694
+ No, // to_json
1695
+ Yes, // nilnil
1696
+ json_class, // create_id
1697
+ 10, // create_id_len
1698
+ 9, // sec_prec
1699
+ Yes, // allow_gc
1700
+ 0, // dump_opts
1701
+ };
1702
+
1703
+ static VALUE
1704
+ mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
1705
+ char buf[4096];
1706
+ struct _Out out;
1707
+ VALUE rstr;
1708
+
1709
+ out.buf = buf;
1710
+ out.end = buf + sizeof(buf) - 10;
1711
+ out.allocated = 0;
1712
+ oj_dump_obj_to_json(self, &mimic_object_to_json_options, &out);
1713
+ if (0 == out.buf) {
1714
+ rb_raise(rb_eNoMemError, "Not enough memory.");
1715
+ }
1716
+ rstr = rb_str_new2(out.buf);
1717
+ rstr = oj_encode(rstr);
1718
+ if (out.allocated) {
1719
+ xfree(out.buf);
1720
+ }
1721
+ return rstr;
1722
+ }
1723
+
1724
+
1683
1725
  /* Document-method: mimic_JSON
1684
1726
  * call-seq: mimic_JSON() => Module
1685
1727
  *
@@ -1752,6 +1794,9 @@ define_mimic_json(int argc, VALUE *argv, VALUE self) {
1752
1794
 
1753
1795
  rb_define_module_function(mimic, "parse", mimic_parse, -1);
1754
1796
  rb_define_module_function(mimic, "parse!", mimic_parse, -1);
1797
+
1798
+ rb_define_method(rb_cObject, "to_json", mimic_object_to_json, -1);
1799
+
1755
1800
  rb_gv_set("$VERBOSE", dummy);
1756
1801
 
1757
1802
  array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&array_nl_sym);
@@ -1761,9 +1806,15 @@ define_mimic_json(int argc, VALUE *argv, VALUE self) {
1761
1806
  space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&space_sym);
1762
1807
  symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
1763
1808
 
1764
- if (!rb_const_defined_at(mimic, rb_intern("ParserError"))) {
1765
- rb_define_const(mimic, "ParserError", oj_parse_error_class);
1809
+ if (rb_const_defined_at(mimic, rb_intern("ParserError"))) {
1810
+ rb_funcall(mimic, rb_intern("remove_const"), 1, ID2SYM(rb_intern("ParserError")));
1766
1811
  }
1812
+ rb_define_const(mimic, "ParserError", oj_parse_error_class);
1813
+
1814
+ if (!rb_const_defined_at(mimic, rb_intern("State"))) {
1815
+ rb_define_class_under(mimic, "State", rb_cObject);
1816
+ }
1817
+
1767
1818
  oj_default_options.mode = CompatMode;
1768
1819
  oj_default_options.escape_mode = ASCIIEsc;
1769
1820
  oj_default_options.nilnil = Yes;
@@ -70,11 +70,11 @@ static void
70
70
  skip_comment(ParseInfo pi) {
71
71
  if ('*' == *pi->cur) {
72
72
  pi->cur++;
73
- for (; '\0' != *pi->cur; pi->cur++) {
73
+ for (; pi->cur < pi->end; pi->cur++) {
74
74
  if ('*' == *pi->cur && '/' == *(pi->cur + 1)) {
75
75
  pi->cur += 2;
76
76
  return;
77
- } else if ('\0' == *pi->cur) {
77
+ } else if (pi->end <= pi->cur) {
78
78
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
79
79
  return;
80
80
  }
@@ -226,7 +226,7 @@ read_escaped_str(ParseInfo pi, const char *start) {
226
226
  buf_append_string(&buf, start, cnt);
227
227
  }
228
228
  for (s = pi->cur; '"' != *s; s++) {
229
- if ('\0' == *s) {
229
+ if (s >= pi->end) {
230
230
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
231
231
  buf_cleanup(&buf);
232
232
  return;
@@ -328,9 +328,12 @@ read_str(ParseInfo pi) {
328
328
  Val parent = stack_peek(&pi->stack);
329
329
 
330
330
  for (; '"' != *pi->cur; pi->cur++) {
331
- if ('\0' == *pi->cur) {
331
+ if (pi->end <= pi->cur) {
332
332
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
333
333
  return;
334
+ } else if ('\0' == *pi->cur) {
335
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
336
+ return;
334
337
  } else if ('\\' == *pi->cur) {
335
338
  read_escaped_str(pi, str);
336
339
  return;
@@ -736,6 +739,12 @@ protect_parse(VALUE pip) {
736
739
  return Qnil;
737
740
  }
738
741
 
742
+ void
743
+ oj_pi_set_input_str(ParseInfo pi, volatile VALUE input) {
744
+ pi->json = rb_string_value_ptr((VALUE*)&input);
745
+ pi->end = pi->json + RSTRING_LEN(input);
746
+ }
747
+
739
748
  VALUE
740
749
  oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
741
750
  char *buf = 0;
@@ -763,8 +772,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
763
772
  pi->end = json + len;
764
773
  free_json = 1;
765
774
  } else if (T_STRING == rb_type(input)) {
766
- pi->json = rb_string_value_cstr((VALUE*)&input);
767
- pi->end = pi->json + RSTRING_LEN(input);
775
+ oj_pi_set_input_str(pi, input);
768
776
  } else if (Qnil == input && Yes == pi->options.nilnil) {
769
777
  return Qnil;
770
778
  } else {
@@ -776,8 +784,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
776
784
 
777
785
  if (oj_stringio_class == clas) {
778
786
  s = rb_funcall2(input, oj_string_id, 0, 0);
779
- pi->json = rb_string_value_cstr((VALUE*)&s);
780
- pi->end = pi->json + RSTRING_LEN(s);
787
+ oj_pi_set_input_str(pi, s);
781
788
  #if !IS_WINDOWS
782
789
  } else if (rb_respond_to(input, oj_fileno_id) &&
783
790
  Qnil != (s = rb_funcall(input, oj_fileno_id, 0)) &&
@@ -89,6 +89,7 @@ typedef struct _ParseInfo {
89
89
 
90
90
  extern void oj_parse2(ParseInfo pi);
91
91
  extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...);
92
+ extern void oj_pi_set_input_str(ParseInfo pi, volatile VALUE input);
92
93
  extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk);
93
94
  extern VALUE oj_num_as_value(NumInfo ni);
94
95
 
@@ -163,7 +163,9 @@ oj_reader_read(Reader reader) {
163
163
 
164
164
  static VALUE
165
165
  rescue_cb(VALUE rbuf, VALUE err) {
166
- if (rb_eTypeError != rb_obj_class(err)) {
166
+ VALUE clas = rb_obj_class(err);
167
+
168
+ if (rb_eTypeError != clas && rb_eEOFError != clas) {
167
169
  Reader reader = (Reader)rbuf;
168
170
 
169
171
  rb_raise(err, "at line %d, column %d\n", reader->line, reader->col);
@@ -186,7 +188,6 @@ partial_io_cb(VALUE rbuf) {
186
188
  }
187
189
  str = StringValuePtr(rstr);
188
190
  cnt = RSTRING_LEN(rstr);
189
- //printf("*** read %lu bytes, str: '%s'\n", cnt, str);
190
191
  strcpy(reader->tail, str);
191
192
  reader->read_end = reader->tail + cnt;
192
193
 
@@ -256,7 +256,7 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) {
256
256
  pi.expect_value = 0;
257
257
  }
258
258
  if (rb_type(input) == T_STRING) {
259
- pi.json = StringValuePtr(input);
259
+ oj_pi_set_input_str(&pi, input);
260
260
  } else {
261
261
  VALUE clas = rb_obj_class(input);
262
262
  volatile VALUE s;
@@ -265,7 +265,7 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) {
265
265
  #endif
266
266
  if (oj_stringio_class == clas) {
267
267
  s = rb_funcall2(input, oj_string_id, 0, 0);
268
- pi.json = StringValuePtr(input);
268
+ oj_pi_set_input_str(&pi, input);
269
269
  #if !IS_WINDOWS
270
270
  // JRuby gets confused with what is the real fileno.
271
271
  } else if (rb_respond_to(input, oj_fileno_id) &&
@@ -275,20 +275,19 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) {
275
275
  size_t len = lseek(fd, 0, SEEK_END);
276
276
 
277
277
  lseek(fd, 0, SEEK_SET);
278
- buf = ALLOC_N(char, len + 1);
278
+ buf = ALLOC_N(char, len);
279
279
  pi.json = buf;
280
+ pi.end = buf + len;
280
281
  if (0 >= (cnt = read(fd, (char*)pi.json, len)) || cnt != (ssize_t)len) {
281
282
  if (0 != buf) {
282
283
  xfree(buf);
283
284
  }
284
285
  rb_raise(rb_eIOError, "failed to read from IO Object.");
285
286
  }
286
- ((char*)pi.json)[len] = '\0';
287
287
  #endif
288
288
  } else if (rb_respond_to(input, oj_read_id)) {
289
289
  s = rb_funcall2(input, oj_read_id, 0, 0);
290
- pi.json = rb_string_value_cstr((VALUE*)&s);
291
-
290
+ oj_pi_set_input_str(&pi, s);
292
291
  } else {
293
292
  rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
294
293
  }
@@ -1,12 +1,12 @@
1
1
 
2
2
  module Oj
3
-
3
+
4
4
  def self.mimic_loaded(mimic_paths=[])
5
5
  $LOAD_PATH.each do |d|
6
6
  next unless File.exist?(d)
7
7
  offset = d.size() + 1
8
8
  Dir.glob(File.join(d, '**', '*.rb')).each do |file|
9
- next unless file[offset..-1].start_with?('json')
9
+ next if file[offset..-1] !~ /^json[\/\\\.]{1}/
10
10
  $LOADED_FEATURES << file unless $LOADED_FEATURES.include?(file)
11
11
  end
12
12
  end
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '2.9.4'
4
+ VERSION = '2.9.5'
5
5
  end
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'helper'
4
+ Oj.mimic_JSON
5
+ require 'rails/all'
6
+
7
+ class MimicRails < Minitest::Test
8
+
9
+ def test_mimic_exception
10
+ begin
11
+ ActiveSupport::JSON.decode("{")
12
+ puts "Failed"
13
+ rescue ActiveSupport::JSON.parse_error
14
+ assert(true)
15
+ rescue Exception
16
+ assert(false, 'Expected a JSON::ParserError')
17
+ end
18
+ end
19
+
20
+ def test_dump_string
21
+ Oj.default_options= {:indent => 2} # JSON this will not change anything
22
+ json = ActiveSupport::JSON.encode([1, true, nil])
23
+ assert_equal(%{[
24
+ 1,
25
+ true,
26
+ null
27
+ ]
28
+ }, json)
29
+ end
30
+
31
+ end # MimicRails
@@ -0,0 +1,27 @@
1
+ # Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
2
+ # required. That can be set in the RUBYOPT environment variable.
3
+ # export RUBYOPT=-w
4
+
5
+ $VERBOSE = true
6
+
7
+ %w(lib ext test).each do |dir|
8
+ $LOAD_PATH.unshift File.expand_path("../../#{dir}", __FILE__)
9
+ end
10
+
11
+ require 'rubygems' if RUBY_VERSION.start_with?('1.8.')
12
+ require 'minitest'
13
+ require 'minitest/autorun'
14
+ require 'stringio'
15
+ require 'date'
16
+ require 'bigdecimal'
17
+ require 'pp'
18
+ require 'oj'
19
+
20
+ $ruby = RUBY_DESCRIPTION.split(' ')[0]
21
+ $ruby = 'ree' if 'ruby' == $ruby && RUBY_DESCRIPTION.include?('Ruby Enterprise Edition')
22
+
23
+ class Range
24
+ def to_hash()
25
+ { 'begin' => self.begin, 'end' => self.end, 'exclude_end' => self.exclude_end? }
26
+ end
27
+ end
@@ -1,52 +1,47 @@
1
- #!/usr/bin/env ruby
2
1
  # encoding: UTF-8
3
2
 
4
- # Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
5
- # required. That can be set in the RUBYOPT environment variable.
6
- # export RUBYOPT=-w
3
+ class SharedMimicTest < Minitest::Test
4
+ class Jam
5
+ attr_accessor :x, :y
7
6
 
8
- $VERBOSE = true
9
-
10
- $: << File.join(File.dirname(__FILE__), "../lib")
11
- $: << File.join(File.dirname(__FILE__), "../ext")
12
-
13
- require 'test/unit'
14
- require 'stringio'
15
- require 'bigdecimal'
16
- require 'oj'
7
+ def initialize(x, y)
8
+ @x = x
9
+ @y = y
10
+ end
17
11
 
18
- $ruby = RUBY_DESCRIPTION.split(' ')[0]
19
- $ruby = 'ree' if 'ruby' == $ruby && RUBY_DESCRIPTION.include?('Ruby Enterprise Edition')
12
+ def eql?(o)
13
+ self.class == o.class && @x == o.x && @y == o.y
14
+ end
15
+ alias == eql?
20
16
 
21
- class Jam
22
- attr_accessor :x, :y
17
+ def as_json()
18
+ {"json_class" => self.class.to_s,"x" => @x,"y" => @y}
19
+ end
23
20
 
24
- def initialize(x, y)
25
- @x = x
26
- @y = y
27
- end
21
+ def self.json_create(h)
22
+ self.new(h['x'], h['y'])
23
+ end
28
24
 
29
- def eql?(o)
30
- self.class == o.class && @x == o.x && @y == o.y
31
- end
32
- alias == eql?
25
+ end # Jam
33
26
 
34
- def as_json()
35
- {"json_class" => self.class.to_s,"x" => @x,"y" => @y}
27
+ def setup
28
+ @default_options = Oj.default_options
36
29
  end
37
30
 
38
- def self.json_create(h)
39
- self.new(h['x'], h['y'])
31
+ def teardown
32
+ Oj.default_options = @default_options
40
33
  end
41
34
 
42
- end # Jam
43
-
44
- class Mimic < ::Test::Unit::TestCase
45
-
46
- def test0_mimic_json
47
- assert(defined?(JSON).nil?)
48
- Oj.mimic_JSON
49
- assert(!defined?(JSON).nil?)
35
+ # exception
36
+ def test_exception
37
+ begin
38
+ JSON.parse("{")
39
+ puts "Failed"
40
+ rescue JSON::ParserError
41
+ assert(true)
42
+ rescue Exception
43
+ assert(false, 'Expected a JSON::ParserError')
44
+ end
50
45
  end
51
46
 
52
47
  # dump
@@ -55,6 +50,17 @@ class Mimic < ::Test::Unit::TestCase
55
50
  assert_equal(%{[1,true,null]}, json)
56
51
  end
57
52
 
53
+ def test_dump_with_options
54
+ Oj.default_options= {:indent => 2} # JSON this will not change anything
55
+ json = JSON.dump([1, true, nil])
56
+ assert_equal(%{[
57
+ 1,
58
+ true,
59
+ null
60
+ ]
61
+ }, json)
62
+ end
63
+
58
64
  def test_dump_io
59
65
  s = StringIO.new()
60
66
  json = JSON.dump([1, true, nil], s)
@@ -179,7 +185,7 @@ class Mimic < ::Test::Unit::TestCase
179
185
  obj = JSON.parse(json, :create_additions => true)
180
186
  assert_equal(jam, obj)
181
187
  obj = JSON.parse(json, :create_additions => false)
182
- assert_equal({'json_class' => 'Jam', 'x' => true, 'y' => 58}, obj)
188
+ assert_equal({'json_class' => 'SharedMimicTest::Jam', 'x' => true, 'y' => 58}, obj)
183
189
  json.gsub!('json_class', 'kson_class')
184
190
  JSON.create_id = 'kson_class'
185
191
  obj = JSON.parse(json, :create_additions => true)
@@ -203,17 +209,30 @@ class Mimic < ::Test::Unit::TestCase
203
209
  end
204
210
  end
205
211
 
206
- # exception check
207
- def test_exception
208
- json = %{["a":1]}
209
- begin
210
- obj = JSON.parse(json)
211
-
212
- rescue JSON::ParserError => je
213
- assert(true)
214
- return
212
+ # make sure to_json is defined for object.
213
+ def test_mimic_to_json
214
+ {'a' => 1}.to_json()
215
+ Object.new().to_json()
216
+ end
217
+ end # SharedMimicTest
218
+
219
+ if defined?(ActiveSupport)
220
+ class SharedMimicRailsTest < SharedMimicTest
221
+ def test_activesupport_exception
222
+ begin
223
+ ActiveSupport::JSON.decode("{")
224
+ puts "Failed"
225
+ rescue ActiveSupport::JSON.parse_error
226
+ assert(true)
227
+ rescue Exception
228
+ assert(false, 'Expected a JSON::ParserError')
229
+ end
215
230
  end
216
- assert(false, "*** expected an JSON::ParserError")
217
- end
218
231
 
219
- end # Mimic
232
+ def test_activesupport_encode
233
+ Oj.default_options= {:indent => 0}
234
+ json = ActiveSupport::JSON.encode([1, true, nil])
235
+ assert_equal(%{[1,true,null]}, json)
236
+ end
237
+ end # SharedMimicRailsTest
238
+ end