Skip to content

Commit d052678

Browse files
committed
added conversion to utf8 to generators as well
1 parent ed80ac8 commit d052678

3 files changed

Lines changed: 58 additions & 22 deletions

File tree

ext/json/ext/generator/generator.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#ifdef HAVE_RUBY_ENCODING_H
2525
#include "ruby/encoding.h"
2626
#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
27+
static VALUE mEncoding_UTF_8;
28+
static ID i_encoding, i_encode;
2729
#else
2830
#define FORCE_UTF8(obj)
2931
#endif
@@ -357,7 +359,12 @@ static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
357359
{
358360
VALUE result = rb_str_buf_new(RSTRING_LEN(self));
359361
rb_str_buf_cat2(result, "\"");
360-
JSON_convert_UTF8_to_JSON(result, self, strictConversion);
362+
if (rb_funcall(self, i_encoding, 0) == mEncoding_UTF_8) {
363+
JSON_convert_UTF8_to_JSON(result, self, strictConversion);
364+
} else {
365+
VALUE string = rb_funcall(self, i_encode, 1, mEncoding_UTF_8);
366+
JSON_convert_UTF8_to_JSON(result, string, strictConversion);
367+
}
361368
rb_str_buf_cat2(result, "\"");
362369
FORCE_UTF8(result);
363370
return result;
@@ -916,4 +923,9 @@ void Init_generator()
916923
i_unpack = rb_intern("unpack");
917924
i_create_id = rb_intern("create_id");
918925
i_extend = rb_intern("extend");
926+
#ifdef HAVE_RUBY_ENCODING_H
927+
mEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
928+
i_encoding = rb_intern("encoding");
929+
i_encode = rb_intern("encode");
930+
#endif
919931
}

lib/json/pure/generator.rb

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ module JSON
3838

3939
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
4040
# UTF16 big endian characters as \u????, and return it.
41-
if String.method_defined?(:force_encoding)
41+
if defined?(::Encoding)
4242
def utf8_to_json(string) # :nodoc:
4343
string = string.dup
4444
string << '' # XXX workaround: avoid buffer sharing
45-
string.force_encoding(Encoding::ASCII_8BIT)
45+
string.force_encoding(::Encoding::ASCII_8BIT)
4646
string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
4747
string.gsub!(/(
4848
(?:
@@ -56,7 +56,7 @@ def utf8_to_json(string) # :nodoc:
5656
s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
5757
s.gsub!(/.{4}/n, '\\\\u\&')
5858
}
59-
string.force_encoding(Encoding::UTF_8)
59+
string.force_encoding(::Encoding::UTF_8)
6060
string
6161
rescue Iconv::Failure => e
6262
raise GeneratorError, "Caught #{e.class}: #{e}"
@@ -369,11 +369,25 @@ def to_json(state = nil, *)
369369
end
370370

371371
module String
372-
# This string should be encoded with UTF-8 A call to this method
373-
# returns a JSON string encoded with UTF16 big endian characters as
374-
# \u????.
375-
def to_json(*)
376-
'"' << JSON.utf8_to_json(self) << '"'
372+
if defined?(::Encoding)
373+
# This string should be encoded with UTF-8 A call to this method
374+
# returns a JSON string encoded with UTF16 big endian characters as
375+
# \u????.
376+
def to_json(*)
377+
if encoding == ::Encoding::UTF_8
378+
'"' << JSON.utf8_to_json(self) << '"'
379+
else
380+
string = encode(::Encoding::UTF_8)
381+
'"' << JSON.utf8_to_json(string) << '"'
382+
end
383+
end
384+
else
385+
# This string should be encoded with UTF-8 A call to this method
386+
# returns a JSON string encoded with UTF16 big endian characters as
387+
# \u????.
388+
def to_json(*)
389+
'"' << JSON.utf8_to_json(self) << '"'
390+
end
377391
end
378392

379393
# Module that holds the extinding methods if, the String module is

tests/test_json_encoding.rb

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ class TC_JSONEncoding < Test::Unit::TestCase
1414

1515
def setup
1616
@utf_8 = '["© ≠ €!"]'
17-
@decoded = [ "© ≠ €!" ]
17+
@parsed = [ "© ≠ €!" ]
18+
@utf_16_data = Iconv.iconv('utf-16be', 'utf-8', @parsed.first)
19+
@generated = '["\u00a9 \u2260 \u20ac!"]'
1820
if defined?(::Encoding)
1921
@utf_8_ascii_8bit = @utf_8.dup.force_encoding(Encoding::ASCII_8BIT)
2022
@utf_16be, = Iconv.iconv('utf-16be', 'utf-8', @utf_8)
@@ -38,20 +40,28 @@ def setup
3840
end
3941
end
4042

41-
def test_decode
42-
assert @decoded, JSON.parse(@utf_8)
43-
assert @decoded, JSON.parse(@utf_16be)
44-
assert @decoded, JSON.parse(@utf_16le)
45-
assert @decoded, JSON.parse(@utf_32be)
46-
assert @decoded, JSON.parse(@utf_32le)
43+
def test_parse
44+
assert_equal @parsed, JSON.parse(@utf_8)
45+
assert_equal @parsed, JSON.parse(@utf_16be)
46+
assert_equal @parsed, JSON.parse(@utf_16le)
47+
assert_equal @parsed, JSON.parse(@utf_32be)
48+
assert_equal @parsed, JSON.parse(@utf_32le)
4749
end
4850

49-
def test_decode_ascii_8bit
50-
assert @decoded, JSON.parse(@utf_8_ascii_8bit)
51-
assert @decoded, JSON.parse(@utf_16be_ascii_8bit)
52-
assert @decoded, JSON.parse(@utf_16le_ascii_8bit)
53-
assert @decoded, JSON.parse(@utf_32be_ascii_8bit)
54-
assert @decoded, JSON.parse(@utf_32le_ascii_8bit)
51+
def test_parse_ascii_8bit
52+
assert_equal @parsed, JSON.parse(@utf_8_ascii_8bit)
53+
assert_equal @parsed, JSON.parse(@utf_16be_ascii_8bit)
54+
assert_equal @parsed, JSON.parse(@utf_16le_ascii_8bit)
55+
assert_equal @parsed, JSON.parse(@utf_32be_ascii_8bit)
56+
assert_equal @parsed, JSON.parse(@utf_32le_ascii_8bit)
5557
end
5658

59+
def test_generate
60+
assert_equal @generated, JSON.generate(@parsed)
61+
if defined?(::Encoding)
62+
assert_equal @generated, JSON.generate(@utf_16_data)
63+
else
64+
assert_raises(JSON::GeneratorError) { JSON.generate(@utf_16_data) }
65+
end
66+
end
5767
end

0 commit comments

Comments
 (0)