Skip to content

Commit b63b4f1

Browse files
ydahbyroot
authored andcommitted
Honor as_json and reject disabled strict mode in JSON::Coder
1 parent 42cc52a commit b63b4f1

4 files changed

Lines changed: 50 additions & 7 deletions

File tree

‎lib/json/common.rb‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,12 @@ class Coder
827827
#
828828
# puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
829829
#
830-
def initialize(object_class: nil, array_class: nil, on_load: nil, **options, &as_json)
830+
# The conversion callback can also be passed as +as_json:+. If both are given, the block takes precedence.
831+
# Passing +false+ or +nil+ for +strict:+ raises ArgumentError.
832+
#
833+
def initialize(object_class: nil, array_class: nil, on_load: nil, strict: true, **options, &as_json)
834+
raise ArgumentError, "JSON::Coder requires strict mode" unless strict
835+
831836
if object_class || array_class
832837
on_load = ParserOptions.on_load(on_load, object_class, array_class)
833838
end
@@ -839,7 +844,7 @@ def initialize(object_class: nil, array_class: nil, on_load: nil, **options, &as
839844
@state = State.new(
840845
**generator_options,
841846
strict: true,
842-
as_json: as_json,
847+
as_json: as_json || generator_options[:as_json],
843848
).freeze
844849
end
845850

‎lib/json/truffle_ruby/generator.rb‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,16 @@ def initialize(opts = nil)
192192
attr_accessor :array_nl
193193

194194
# This proc converts unsupported types into native JSON types.
195-
attr_accessor :as_json
195+
attr_reader :as_json
196+
197+
def as_json=(value)
198+
raise FrozenError, "can't modify frozen #{self.class}: #{inspect}" if frozen?
199+
value = value.to_proc if !(Proc === value) && value.respond_to?(:to_proc)
200+
unless Proc === value
201+
raise TypeError, "as_json must be a Proc"
202+
end
203+
@as_json = value
204+
end
196205

197206
# This integer returns the maximum level of data structure nesting in
198207
# the generated JSON, max_nesting = 0 if no maximum is checked.
@@ -335,7 +344,11 @@ def configure(options)
335344
@object_nl = object_nl || ''
336345
@array_nl = array_nl || ''
337346
@allow_nan = allow_nan || false
338-
@as_json = as_json || false
347+
if as_json
348+
self.as_json = as_json
349+
else
350+
@as_json = false
351+
end
339352
@ascii_only = ascii_only || false
340353
self.sort_keys = sort_keys
341354
@depth = depth

‎test/json/json_coder_test.rb‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,32 @@ def test_json_coder_with_proc
1010
assert_equal %(["[Object object]"]), coder.dump([Object.new])
1111
end
1212

13+
def test_json_coder_with_as_json_option
14+
callback = ->(object, is_key) { 42 }
15+
[callback, callback.method(:call)].each do |as_json|
16+
coder = JSON::Coder.new(as_json: as_json)
17+
assert_equal '[42]', coder.dump([Object.new])
18+
end
19+
end
20+
21+
def test_json_coder_block_overrides_as_json_option
22+
coder = JSON::Coder.new(as_json: ->(object) { 1 }) { 2 }
23+
assert_equal '[2]', coder.dump([Object.new])
24+
end
25+
26+
def test_json_coder_as_json_invalid_type
27+
assert_raise(TypeError) { JSON::Coder.new(as_json: 'x') }
28+
end
29+
30+
def test_json_coder_rejects_disabling_strict_mode
31+
[false, nil].each do |strict|
32+
error = assert_raise(ArgumentError) { JSON::Coder.new(strict: strict) }
33+
assert_equal 'JSON::Coder requires strict mode', error.message
34+
end
35+
assert_raise(JSON::GeneratorError) { JSON::Coder.new.dump(Object.new) }
36+
assert_raise(JSON::GeneratorError) { JSON::Coder.new(strict: true).dump(Object.new) }
37+
end
38+
1339
def test_json_coder_with_proc_with_unsupported_value
1440
coder = JSON::Coder.new do |object, is_key|
1541
assert_equal false, is_key

‎test/json/json_generator_test.rb‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,26 +1086,25 @@ def test_state_as_json_method
10861086
object = Object.new
10871087
state = JSON.state.new(strict: true)
10881088
state.as_json = -> (o, is_key) { o.object_id }.method(:call)
1089+
assert_kind_of Proc, state.as_json
10891090
assert_equal object.object_id.to_json, state.generate(object)
10901091
end
10911092

10921093
def test_json_generate_as_json_invalid_type
1093-
omit 'TruffleRuby does not convert as_json to Proc' if RUBY_ENGINE == 'truffleruby'
10941094
[Object.new, Time.now].each do |as_json|
10951095
assert_raise(TypeError) { JSON.generate(Object.new, strict: true, as_json: as_json) }
10961096
end
10971097
end
10981098

10991099
def test_state_as_json_invalid_type
1100-
omit 'TruffleRuby does not convert as_json to Proc' if RUBY_ENGINE == 'truffleruby'
11011100
state = JSON.state.new(strict: true)
11021101
[Object.new, Time.now].each do |as_json|
11031102
assert_raise(TypeError) { state.as_json = as_json }
1103+
assert_raise(TypeError) { state.configure(as_json: as_json) }
11041104
end
11051105
end
11061106

11071107
def test_as_json_to_proc_returns_invalid_type
1108-
omit 'TruffleRuby does not convert as_json to Proc' if RUBY_ENGINE == 'truffleruby'
11091108
as_json = Object.new
11101109
def as_json.to_proc
11111110
method(:to_proc)

0 commit comments

Comments
 (0)