json 2.0.3 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7f771ff2dbe2582a3e23652725e44a2c04f9ef38
4
- data.tar.gz: 1ee70a27e6878091c34a96f65be2dc4e9cb7b509
2
+ SHA256:
3
+ metadata.gz: 80444509bc162d6df8e9cc3e7af2fc28507c06aef49cbfc1dd9e5990af42b14f
4
+ data.tar.gz: 8541be9708b44604eeeecac22f89c47933d32c90606f23c1d37e70c8b2d3e9db
5
5
  SHA512:
6
- metadata.gz: e38803d57bcb19d115083216ff027bbf749879c8fc09b676937072f5e1f95d975965c263252a8aeba6581405e09fd423a5bbc7d5ecaa4d6033d9a12bc9da262d
7
- data.tar.gz: 80a69daa2ffa65cf6b9824dc77ce5e286a5e021c111d70ec0eb3fdf213a38b83feb48f004b7a2165586405a2f898b1358d5c74b9f6ffee33b627111f9af86208
6
+ metadata.gz: 1df7b5ee2bf58103f0b5776c4a581aa3b013ad4b3a85a442d37bb72dc62aaf04dc42ed1080fb307fec1d1e9128c9f21e43827c7f15494cb0f9f310f7189bdc5e
7
+ data.tar.gz: 15ba56ce5d0e04c5326feb9e9faf2627628a715fa4bbeaec5c4aadeab5f27a65135f4f24f142b361f62ca37bbf36380f671d7ae35d46991737e4fc62423a6f9b
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ Gemfile.lock
15
15
  */**/Makefile
16
16
  */**/*.o
17
17
  .byebug_history
18
+ *.log
@@ -4,16 +4,23 @@ language: ruby
4
4
 
5
5
  # Specify which ruby versions you wish to run your tests on, each version will be used
6
6
  rvm:
7
- - 1.9.3
8
7
  - 2.0.0
9
8
  - 2.1
10
9
  - 2.2
11
- - 2.3.3
12
- - 2.4.0
13
- - jruby
10
+ - 2.3
11
+ - 2.4
12
+ - 2.5
13
+ - 2.6
14
+ - 2.7.0-preview3
14
15
  - ruby-head
16
+ - jruby
17
+ - jruby-9.2.7.0
18
+ - truffleruby
15
19
  matrix:
16
20
  allow_failures:
17
21
  - rvm: ruby-head
22
+ - rvm: jruby
23
+ - rvm: jruby-9.2.7.0
24
+ - rvm: truffleruby
18
25
  script: "bundle exec rake"
19
26
  sudo: false
data/CHANGES.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # Changes
2
2
 
3
+ ## 2020-06-30 (2.3.1)
4
+
5
+ * Spelling and grammar fixes for comments. Pull request #191 by Josh
6
+ Kline.
7
+ * Enhance generic JSON and #generate docs. Pull request #347 by Victor
8
+ Shepelev.
9
+ * Add :nodoc: for GeneratorMethods. Pull request #349 by Victor Shepelev.
10
+ * Baseline changes to help (JRuby) development. Pull request #371 by Karol
11
+ Bucek.
12
+ * Add metadata for rubygems.org. Pull request #379 by Alexandre ZANNI.
13
+ * Remove invalid JSON.generate description from JSON module rdoc. Pull
14
+ request #384 by Jeremy Evans.
15
+ * Test with TruffleRuby in CI. Pull request #402 by Benoit Daloze.
16
+ * Rdoc enhancements. Pull request #413 by Burdette Lamar.
17
+ * Fixtures/ are not being tested... Pull request #416 by Marc-André
18
+ Lafortune.
19
+ * Use frozen string for hash key. Pull request #420 by Marc-André
20
+ Lafortune.
21
+ * Added :call-seq: to RDoc for some methods. Pull request #422 by Burdette
22
+ Lamar.
23
+ * Small typo fix. Pull request #423 by Marc-André Lafortune.
24
+
25
+ ## 2019-12-11 (2.3.0)
26
+ * Fix default of `create_additions` to always be `false` for `JSON(user_input)`
27
+ and `JSON.parse(user_input, nil)`.
28
+ Note that `JSON.load` remains with default `true` and is meant for internal
29
+ serialization of trusted data. [CVE-2020-10663]
30
+ * Fix passing args all #to_json in json/add/*.
31
+ * Fix encoding issues
32
+ * Fix issues of keyword vs positional parameter
33
+ * Fix JSON::Parser against bigdecimal updates
34
+ * Bug fixes to JRuby port
35
+
36
+ ## 2019-02-21 (2.2.0)
37
+ * Adds support for 2.6 BigDecimal and ruby standard library Set datetype.
38
+
39
+ ## 2017-04-18 (2.1.0)
40
+ * Allow passing of `decimal_class` option to specify a class as which to parse
41
+ JSON float numbers.
42
+ ## 2017-03-23 (2.0.4)
43
+ * Raise exception for incomplete unicode surrogates/character escape
44
+ sequences. This problem was reported by Daniel Gollahon (dgollahon).
45
+ * Fix arbitrary heap exposure problem. This problem was reported by Ahmad
46
+ Sherif (ahmadsherif).
3
47
 
4
48
  ## 2017-01-12 (2.0.3)
5
49
  * Set `required_ruby_version` to 1.9
data/Gemfile CHANGED
@@ -5,12 +5,10 @@ source 'https://rubygems.org'
5
5
  case ENV['JSON']
6
6
  when 'ext', nil
7
7
  if ENV['RUBY_ENGINE'] == 'jruby'
8
- gemspec :name => 'json', :path => 'java'
8
+ gemspec :name => 'json-java'
9
9
  else
10
10
  gemspec :name => 'json'
11
11
  end
12
12
  when 'pure'
13
13
  gemspec :name => 'json_pure'
14
14
  end
15
-
16
- gem 'simplecov'
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
- # JSON implementation for Ruby ![Travis Widget]
2
- [Travis Widget]: http://travis-ci.org/flori/json.svg?branch=master
1
+ # JSON implementation for Ruby
2
+
3
+ [![Travis Widget](http://travis-ci.org/flori/json.svg?branch=master)](https://travis-ci.org/flori/json)
3
4
 
4
5
  ## Description
5
6
 
@@ -150,6 +151,18 @@ require 'json/add/rails'
150
151
  Both of the additions attempt to require `'json'` (like above) first, if it has
151
152
  not been required yet.
152
153
 
154
+ ## Serializing exceptions
155
+
156
+ The JSON module doesn't extend `Exception` by default. If you convert an `Exception`
157
+ object to JSON, it will by default only include the exception message.
158
+
159
+ To include the full details, you must either load the `json/add/core` mentioned
160
+ above, or specifically load the exception addition:
161
+
162
+ ```ruby
163
+ require 'json/add/exception'
164
+ ```
165
+
153
166
  ## More Examples
154
167
 
155
168
  To create a JSON document from a ruby data structure, you can call
@@ -179,14 +192,14 @@ should return a JSON object (a hash converted to JSON with `#to_json`) like
179
192
  this (don't forget the `*a` for all the arguments):
180
193
 
181
194
  ```ruby
182
- class Range
183
- def to_json(*a)
184
- {
185
- 'json_class' => self.class.name, # = 'Range'
186
- 'data' => [ first, last, exclude_end? ]
187
- }.to_json(*a)
188
- end
189
- end
195
+ class Range
196
+ def to_json(*a)
197
+ {
198
+ 'json_class' => self.class.name, # = 'Range'
199
+ 'data' => [ first, last, exclude_end? ]
200
+ }.to_json(*a)
201
+ end
202
+ end
190
203
  ```
191
204
 
192
205
  The hash key `json_class` is the class, that will be asked to deserialise the
@@ -194,26 +207,30 @@ JSON representation later. In this case it's `Range`, but any namespace of
194
207
  the form `A::B` or `::A::B` will do. All other keys are arbitrary and can be
195
208
  used to store the necessary data to configure the object to be deserialised.
196
209
 
197
- If a the key `json_class` is found in a JSON object, the JSON parser checks
210
+ If the key `json_class` is found in a JSON object, the JSON parser checks
198
211
  if the given class responds to the `json_create` class method. If so, it is
199
212
  called with the JSON object converted to a Ruby hash. So a range can
200
213
  be deserialised by implementing `Range.json_create` like this:
201
214
 
202
215
  ```ruby
203
- class Range
204
- def self.json_create(o)
205
- new(*o['data'])
206
- end
207
- end
216
+ class Range
217
+ def self.json_create(o)
218
+ new(*o['data'])
219
+ end
220
+ end
208
221
  ```
209
222
 
210
223
  Now it possible to serialise/deserialise ranges as well:
211
224
 
212
225
  ```ruby
213
- json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
214
- # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
215
- JSON.parse json
216
- # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
226
+ json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
227
+ # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
228
+ JSON.parse json
229
+ # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
230
+ json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
231
+ # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
232
+ JSON.parse json, :create_additions => true
233
+ # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
217
234
  ```
218
235
 
219
236
  `JSON.generate` always creates the shortest possible string representation of a
@@ -373,6 +390,22 @@ Here are the median comparisons for completeness' sake:
373
390
  secs/call
374
391
  ```
375
392
 
393
+ ## Development
394
+
395
+ ### Release
396
+
397
+ Update the json.gemspec and json-java.gemspec.
398
+
399
+ ```
400
+ rbenv shell 2.6.5
401
+ rake build
402
+ gem push pkg/json-2.3.0.gem
403
+
404
+ rbenv shell jruby-9.2.9.0
405
+ rake build
406
+ gem push pkg/json-2.3.0-java.gem
407
+ ```
408
+
376
409
  ## Author
377
410
 
378
411
  Florian Frank <mailto:flori@ping.de>
@@ -389,4 +422,4 @@ The latest version of this library can be downloaded at
389
422
 
390
423
  Online Documentation should be located at
391
424
 
392
- * http://json.rubyforge.org
425
+ * https://www.rubydoc.info/gems/json
data/Rakefile CHANGED
@@ -23,8 +23,13 @@ class UndocumentedTestTask < Rake::TestTask
23
23
  def desc(*) end
24
24
  end
25
25
 
26
- MAKE = ENV['MAKE'] || %w[gmake make].find { |c| system(c, '-v') }
27
- BUNDLE = ENV['BUNDLE'] || %w[bundle].find { |c| system(c, '-v') }
26
+ which = lambda { |c|
27
+ w = `which #{c}`
28
+ break w.chomp unless w.empty?
29
+ }
30
+
31
+ MAKE = ENV['MAKE'] || %w[gmake make].find(&which)
32
+ BUNDLE = ENV['BUNDLE'] || %w[bundle].find(&which)
28
33
  PKG_NAME = 'json'
29
34
  PKG_TITLE = 'JSON Implementation for Ruby'
30
35
  PKG_VERSION = File.read('VERSION').chomp
@@ -47,8 +52,8 @@ JAVA_CLASSES = []
47
52
  JRUBY_PARSER_JAR = File.expand_path("lib/json/ext/parser.jar")
48
53
  JRUBY_GENERATOR_JAR = File.expand_path("lib/json/ext/generator.jar")
49
54
 
50
- RAGEL_CODEGEN = %w[rlcodegen rlgen-cd ragel].find { |c| system(c, '-v') }
51
- RAGEL_DOTGEN = %w[rlgen-dot rlgen-cd ragel].find { |c| system(c, '-v') }
55
+ RAGEL_CODEGEN = %w[rlcodegen rlgen-cd ragel].find(&which)
56
+ RAGEL_DOTGEN = %w[rlgen-dot rlgen-cd ragel].find(&which)
52
57
 
53
58
  desc "Installing library (pure)"
54
59
  task :install_pure => :version do
@@ -73,86 +78,6 @@ task :install_ext => [ :compile, :install_pure, :install_ext_really ]
73
78
  desc "Installing library (extension)"
74
79
  task :install => :install_ext
75
80
 
76
- if defined?(Gem) and defined?(Gem::PackageTask)
77
- spec_pure = Gem::Specification.new do |s|
78
- s.name = 'json_pure'
79
- s.version = PKG_VERSION
80
- s.summary = PKG_TITLE
81
- s.description = "This is a JSON implementation in pure Ruby."
82
-
83
- s.files = PKG_FILES
84
-
85
- s.require_path = 'lib'
86
- s.add_development_dependency 'rake'
87
- s.add_development_dependency 'test-unit', '~> 2.0'
88
-
89
- s.extra_rdoc_files << 'README.md'
90
- s.rdoc_options <<
91
- '--title' << 'JSON implemention for ruby' << '--main' << 'README.md'
92
- s.test_files.concat Dir['./tests/test_*.rb']
93
-
94
- s.author = "Florian Frank"
95
- s.email = "flori@ping.de"
96
- s.homepage = "http://flori.github.com/#{PKG_NAME}"
97
- s.license = 'Ruby'
98
- s.required_ruby_version = '>= 1.9'
99
- end
100
-
101
- desc 'Creates a json_pure.gemspec file'
102
- task :gemspec_pure => :version do
103
- File.open('json_pure.gemspec', 'w') do |gemspec|
104
- gemspec.write spec_pure.to_ruby
105
- end
106
- end
107
-
108
- Gem::PackageTask.new(spec_pure) do |pkg|
109
- pkg.need_tar = true
110
- pkg.package_files = PKG_FILES
111
- end
112
-
113
- spec_ext = Gem::Specification.new do |s|
114
- s.name = 'json'
115
- s.version = PKG_VERSION
116
- s.summary = PKG_TITLE
117
- s.description = "This is a JSON implementation as a Ruby extension in C."
118
-
119
- s.files = PKG_FILES
120
-
121
- s.extensions = FileList['ext/**/extconf.rb']
122
-
123
- s.require_path = 'lib'
124
- s.add_development_dependency 'rake'
125
- s.add_development_dependency 'test-unit', '~> 2.0'
126
-
127
- s.extra_rdoc_files << 'README.md'
128
- s.rdoc_options <<
129
- '--title' << 'JSON implemention for Ruby' << '--main' << 'README.md'
130
- s.test_files.concat Dir['./tests/test_*.rb']
131
-
132
- s.author = "Florian Frank"
133
- s.email = "flori@ping.de"
134
- s.homepage = "http://flori.github.com/#{PKG_NAME}"
135
- s.license = 'Ruby'
136
- s.required_ruby_version = '>= 1.9'
137
- end
138
-
139
- desc 'Creates a json.gemspec file'
140
- task :gemspec_ext => :version do
141
- File.open('json.gemspec', 'w') do |gemspec|
142
- gemspec.write spec_ext.to_ruby
143
- end
144
- end
145
-
146
- Gem::PackageTask.new(spec_ext) do |pkg|
147
- pkg.need_tar = true
148
- pkg.package_files = PKG_FILES
149
- end
150
-
151
-
152
- desc 'Create all gemspec files'
153
- task :gemspec => [ :gemspec_pure, :gemspec_ext ]
154
- end
155
-
156
81
  desc m = "Writing version information for #{PKG_VERSION}"
157
82
  task :version do
158
83
  puts m
@@ -176,7 +101,8 @@ task :check_env do
176
101
  end
177
102
 
178
103
  desc "Testing library (pure ruby)"
179
- task :test_pure => [ :clean, :check_env, :do_test_pure ]
104
+ task :test_pure => [ :set_env_pure, :check_env, :do_test_pure ]
105
+ task(:set_env_pure) { ENV['JSON'] = 'pure' }
180
106
 
181
107
  UndocumentedTestTask.new do |t|
182
108
  t.name = 'do_test_pure'
@@ -187,10 +113,7 @@ UndocumentedTestTask.new do |t|
187
113
  end
188
114
 
189
115
  desc "Testing library (pure ruby and extension)"
190
- task :test do
191
- sh "env JSON=pure #{BUNDLE} exec rake test_pure" or exit 1
192
- sh "env JSON=ext #{BUNDLE} exec rake test_ext" or exit 1
193
- end
116
+ task :test => [ :test_pure, :test_ext ]
194
117
 
195
118
  namespace :gems do
196
119
  desc 'Install all development gems'
@@ -238,7 +161,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
238
161
  classpath = (Dir['java/lib/*.jar'] << 'java/src' << JRUBY_JAR) * ':'
239
162
  obj = src.sub(/\.java\Z/, '.class')
240
163
  file obj => src do
241
- sh 'javac', '-classpath', classpath, '-source', '1.5', '-target', '1.5', src
164
+ sh 'javac', '-classpath', classpath, '-source', '1.6', '-target', '1.6', src
242
165
  end
243
166
  JAVA_CLASSES << obj
244
167
  end
@@ -257,7 +180,8 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
257
180
  end
258
181
 
259
182
  desc "Testing library (jruby)"
260
- task :test_ext => [ :create_jar, :check_env, :do_test_ext ]
183
+ task :test_ext => [ :set_env_ext, :create_jar, :check_env, :do_test_ext ]
184
+ task(:set_env_ext) { ENV['JSON'] = 'ext' }
261
185
 
262
186
  UndocumentedTestTask.new do |t|
263
187
  t.name = 'do_test_ext'
@@ -331,7 +255,7 @@ else
331
255
  end
332
256
 
333
257
  desc "Testing library (extension)"
334
- task :test_ext => [ :compile, :check_env, :do_test_ext ]
258
+ task :test_ext => [ :check_env, :compile, :do_test_ext ]
335
259
 
336
260
  UndocumentedTestTask.new do |t|
337
261
  t.name = 'do_test_ext'
@@ -363,6 +287,8 @@ else
363
287
  end
364
288
  src = File.read("parser.c").gsub(/[ \t]+$/, '')
365
289
  src.gsub!(/^static const int (JSON_.*=.*);$/, 'enum {\1};')
290
+ src.gsub!(/0 <= \(\*p\) && \(\*p\) <= 31/, "0 <= (signed char)(*p) && (*p) <= 31")
291
+ src[0, 0] = "/* This file is automatically generated from parser.rl by using ragel */"
366
292
  File.open("parser.c", "w") {|f| f.print src}
367
293
  end
368
294
  end
@@ -405,4 +331,4 @@ else
405
331
  end
406
332
 
407
333
  desc "Compile in the the source directory"
408
- task :default => [ :clean, :gemspec, :test ]
334
+ task :default => [ :clean, :test ]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.3
1
+ 2.3.1
@@ -12,9 +12,6 @@
12
12
  #define RFLOAT_VALUE(val) (RFLOAT(val)->value)
13
13
  #endif
14
14
 
15
- #ifndef RARRAY_PTR
16
- #define RARRAY_PTR(ARRAY) RARRAY(ARRAY)->ptr
17
- #endif
18
15
  #ifndef RARRAY_LEN
19
16
  #define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
20
17
  #endif
@@ -15,7 +15,7 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
15
15
  #endif
16
16
  mFloat, mString, mString_Extend,
17
17
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
18
- eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
18
+ eNestingError,
19
19
  i_SAFE_STATE_PROTOTYPE;
20
20
 
21
21
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
@@ -237,6 +237,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
237
237
  int escape_len;
238
238
  unsigned char c;
239
239
  char buf[6] = { '\\', 'u' };
240
+ int ascii_only = rb_enc_str_asciionly_p(string);
240
241
 
241
242
  for (start = 0, end = 0; end < len;) {
242
243
  p = ptr + end;
@@ -281,14 +282,17 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
281
282
  break;
282
283
  default:
283
284
  {
284
- unsigned short clen = trailingBytesForUTF8[c] + 1;
285
- if (end + clen > len) {
286
- rb_raise(rb_path2class("JSON::GeneratorError"),
287
- "partial character in source, but hit end");
288
- }
289
- if (!isLegalUTF8((UTF8 *) p, clen)) {
290
- rb_raise(rb_path2class("JSON::GeneratorError"),
291
- "source sequence is illegal/malformed utf-8");
285
+ unsigned short clen = 1;
286
+ if (!ascii_only) {
287
+ clen += trailingBytesForUTF8[c];
288
+ if (end + clen > len) {
289
+ rb_raise(rb_path2class("JSON::GeneratorError"),
290
+ "partial character in source, but hit end");
291
+ }
292
+ if (!isLegalUTF8((UTF8 *) p, clen)) {
293
+ rb_raise(rb_path2class("JSON::GeneratorError"),
294
+ "source sequence is illegal/malformed utf-8");
295
+ }
292
296
  }
293
297
  end += clen;
294
298
  }
@@ -308,7 +312,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
308
312
  char *result;
309
313
  if (len <= 0) return NULL;
310
314
  result = ALLOC_N(char, len);
311
- memccpy(result, ptr, 0, len);
315
+ memcpy(result, ptr, len);
312
316
  return result;
313
317
  }
314
318
 
@@ -324,6 +328,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
324
328
  *
325
329
  */
326
330
 
331
+ /* Explanation of the following: that's the only way to not pollute
332
+ * standard library's docs with GeneratorMethods::<ClassName> which
333
+ * are uninformative and take a large place in a list of classes
334
+ */
335
+
336
+ /*
337
+ * Document-module: JSON::Ext::Generator::GeneratorMethods
338
+ * :nodoc:
339
+ */
340
+
341
+ /*
342
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
343
+ * :nodoc:
344
+ */
345
+
346
+ /*
347
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
348
+ * :nodoc:
349
+ */
350
+
351
+ /*
352
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
353
+ * :nodoc:
354
+ */
355
+
356
+ /*
357
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
358
+ * :nodoc:
359
+ */
360
+
361
+ /*
362
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
363
+ * :nodoc:
364
+ */
365
+
366
+ /*
367
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
368
+ * :nodoc:
369
+ */
370
+
371
+ /*
372
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
373
+ * :nodoc:
374
+ */
375
+
376
+ /*
377
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
378
+ * :nodoc:
379
+ */
380
+
381
+ /*
382
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
383
+ * :nodoc:
384
+ */
385
+
386
+ /*
387
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String
388
+ * :nodoc:
389
+ */
390
+
391
+ /*
392
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
393
+ * :nodoc:
394
+ */
395
+
396
+ /*
397
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
398
+ * :nodoc:
399
+ */
400
+
327
401
  /*
328
402
  * call-seq: to_json(state = nil)
329
403
  *
@@ -692,7 +766,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
692
766
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
693
767
  return rb_funcall(self, i_send, 1, name);
694
768
  } else {
695
- return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
769
+ return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
696
770
  }
697
771
  }
698
772
 
@@ -715,43 +789,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
715
789
  return Qnil;
716
790
  }
717
791
 
718
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
792
+ struct hash_foreach_arg {
793
+ FBuffer *buffer;
794
+ JSON_Generator_State *state;
795
+ VALUE Vstate;
796
+ int iter;
797
+ };
798
+
799
+ static int
800
+ json_object_i(VALUE key, VALUE val, VALUE _arg)
719
801
  {
802
+ struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
803
+ FBuffer *buffer = arg->buffer;
804
+ JSON_Generator_State *state = arg->state;
805
+ VALUE Vstate = arg->Vstate;
806
+
720
807
  char *object_nl = state->object_nl;
721
808
  long object_nl_len = state->object_nl_len;
722
809
  char *indent = state->indent;
723
810
  long indent_len = state->indent_len;
724
- long max_nesting = state->max_nesting;
725
811
  char *delim = FBUFFER_PTR(state->object_delim);
726
812
  long delim_len = FBUFFER_LEN(state->object_delim);
727
813
  char *delim2 = FBUFFER_PTR(state->object_delim2);
728
814
  long delim2_len = FBUFFER_LEN(state->object_delim2);
815
+ long depth = state->depth;
816
+ int j;
817
+ VALUE klass, key_to_s;
818
+
819
+ if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
820
+ if (object_nl) {
821
+ fbuffer_append(buffer, object_nl, object_nl_len);
822
+ }
823
+ if (indent) {
824
+ for (j = 0; j < depth; j++) {
825
+ fbuffer_append(buffer, indent, indent_len);
826
+ }
827
+ }
828
+
829
+ klass = CLASS_OF(key);
830
+ if (klass == rb_cString) {
831
+ key_to_s = key;
832
+ } else if (klass == rb_cSymbol) {
833
+ key_to_s = rb_id2str(SYM2ID(key));
834
+ } else {
835
+ key_to_s = rb_funcall(key, i_to_s, 0);
836
+ }
837
+ Check_Type(key_to_s, T_STRING);
838
+ generate_json(buffer, Vstate, state, key_to_s);
839
+ fbuffer_append(buffer, delim2, delim2_len);
840
+ generate_json(buffer, Vstate, state, val);
841
+
842
+ arg->iter++;
843
+ return ST_CONTINUE;
844
+ }
845
+
846
+ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
847
+ {
848
+ char *object_nl = state->object_nl;
849
+ long object_nl_len = state->object_nl_len;
850
+ char *indent = state->indent;
851
+ long indent_len = state->indent_len;
852
+ long max_nesting = state->max_nesting;
729
853
  long depth = ++state->depth;
730
- int i, j;
731
- VALUE key, key_to_s, keys;
854
+ int j;
855
+ struct hash_foreach_arg arg;
856
+
732
857
  if (max_nesting != 0 && depth > max_nesting) {
733
858
  fbuffer_free(buffer);
734
859
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
735
860
  }
736
861
  fbuffer_append_char(buffer, '{');
737
- keys = rb_funcall(obj, i_keys, 0);
738
- for(i = 0; i < RARRAY_LEN(keys); i++) {
739
- if (i > 0) fbuffer_append(buffer, delim, delim_len);
740
- if (object_nl) {
741
- fbuffer_append(buffer, object_nl, object_nl_len);
742
- }
743
- if (indent) {
744
- for (j = 0; j < depth; j++) {
745
- fbuffer_append(buffer, indent, indent_len);
746
- }
747
- }
748
- key = rb_ary_entry(keys, i);
749
- key_to_s = rb_funcall(key, i_to_s, 0);
750
- Check_Type(key_to_s, T_STRING);
751
- generate_json(buffer, Vstate, state, key_to_s);
752
- fbuffer_append(buffer, delim2, delim2_len);
753
- generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
754
- }
862
+
863
+ arg.buffer = buffer;
864
+ arg.state = state;
865
+ arg.Vstate = Vstate;
866
+ arg.iter = 0;
867
+ rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
868
+
755
869
  depth = --state->depth;
756
870
  if (object_nl) {
757
871
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -802,11 +916,22 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
802
916
  fbuffer_append_char(buffer, ']');
803
917
  }
804
918
 
919
+ #ifdef HAVE_RUBY_ENCODING_H
920
+ static int enc_utf8_compatible_p(rb_encoding *enc)
921
+ {
922
+ if (enc == rb_usascii_encoding()) return 1;
923
+ if (enc == rb_utf8_encoding()) return 1;
924
+ return 0;
925
+ }
926
+ #endif
927
+
805
928
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
806
929
  {
807
930
  fbuffer_append_char(buffer, '"');
808
931
  #ifdef HAVE_RUBY_ENCODING_H
809
- obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
932
+ if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
933
+ obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil);
934
+ }
810
935
  #endif
811
936
  if (state->ascii_only) {
812
937
  convert_UTF8_to_JSON_ASCII(buffer, obj);
@@ -970,6 +1095,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
970
1095
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
971
1096
  * generated, otherwise an exception is thrown, if these values are
972
1097
  * encountered. This options defaults to false.
1098
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1099
+ * option defaults to false.
973
1100
  * * *buffer_initial_length*: sets the initial length of the generator's
974
1101
  * internal buffer.
975
1102
  */
@@ -1025,10 +1152,8 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1025
1152
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1026
1153
  return rb_funcall(self, i_new, 1, opts);
1027
1154
  } else {
1028
- if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
1029
- CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1030
- }
1031
- return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
1155
+ VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1156
+ return rb_funcall(prototype, i_dup, 0);
1032
1157
  }
1033
1158
  }
1034
1159
 
@@ -1062,7 +1187,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1062
1187
  }
1063
1188
  } else {
1064
1189
  if (state->indent) ruby_xfree(state->indent);
1065
- state->indent = strdup(RSTRING_PTR(indent));
1190
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
1066
1191
  state->indent_len = len;
1067
1192
  }
1068
1193
  return Qnil;
@@ -1100,7 +1225,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1100
1225
  }
1101
1226
  } else {
1102
1227
  if (state->space) ruby_xfree(state->space);
1103
- state->space = strdup(RSTRING_PTR(space));
1228
+ state->space = fstrndup(RSTRING_PTR(space), len);
1104
1229
  state->space_len = len;
1105
1230
  }
1106
1231
  return Qnil;
@@ -1136,7 +1261,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1136
1261
  }
1137
1262
  } else {
1138
1263
  if (state->space_before) ruby_xfree(state->space_before);
1139
- state->space_before = strdup(RSTRING_PTR(space_before));
1264
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1140
1265
  state->space_before_len = len;
1141
1266
  }
1142
1267
  return Qnil;
@@ -1173,7 +1298,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1173
1298
  }
1174
1299
  } else {
1175
1300
  if (state->object_nl) ruby_xfree(state->object_nl);
1176
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1301
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1177
1302
  state->object_nl_len = len;
1178
1303
  }
1179
1304
  return Qnil;
@@ -1208,7 +1333,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1208
1333
  }
1209
1334
  } else {
1210
1335
  if (state->array_nl) ruby_xfree(state->array_nl);
1211
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1336
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1212
1337
  state->array_nl_len = len;
1213
1338
  }
1214
1339
  return Qnil;
@@ -1267,7 +1392,7 @@ static VALUE cState_allow_nan_p(VALUE self)
1267
1392
  /*
1268
1393
  * call-seq: ascii_only?
1269
1394
  *
1270
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1395
+ * Returns true, if only ASCII characters should be generated. Otherwise
1271
1396
  * returns false.
1272
1397
  */
1273
1398
  static VALUE cState_ascii_only_p(VALUE self)
@@ -1335,6 +1460,7 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1335
1460
  */
1336
1461
  void Init_generator(void)
1337
1462
  {
1463
+ #undef rb_intern
1338
1464
  rb_require("json/common");
1339
1465
 
1340
1466
  mJSON = rb_define_module("JSON");
@@ -1343,6 +1469,8 @@ void Init_generator(void)
1343
1469
 
1344
1470
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1345
1471
  eNestingError = rb_path2class("JSON::NestingError");
1472
+ rb_gc_register_mark_object(eGeneratorError);
1473
+ rb_gc_register_mark_object(eNestingError);
1346
1474
 
1347
1475
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1348
1476
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1408,7 +1536,6 @@ void Init_generator(void)
1408
1536
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1409
1537
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1410
1538
 
1411
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1412
1539
  i_to_s = rb_intern("to_s");
1413
1540
  i_to_json = rb_intern("to_json");
1414
1541
  i_new = rb_intern("new");
@@ -1439,5 +1566,4 @@ void Init_generator(void)
1439
1566
  i_encode = rb_intern("encode");
1440
1567
  #endif
1441
1568
  i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1442
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1443
1569
  }