Skip to content

Commit

Permalink
[ruby/json] Refactor JSON::Ext::Parser to split configuration and par…
Browse files Browse the repository at this point in the history
…sing state

Ref: ruby/json#718

The existing `Parser` interface is pretty bad, as it forces to
instantiate a new instance for each document.

Instead it's preferable to only take the config and do all the
initialization needed, and then keep the parsing state on the
stack on in ephemeral memory.

This refactor makes the `JSON::Coder` pull request much easier to
implement in a performant way.

ruby/json@c8d5236a92

Co-Authored-By: Étienne Barrié <[email protected]>
  • Loading branch information
2 people authored and hsbt committed Jan 14, 2025
1 parent 61d3f9a commit 220409f
Show file tree
Hide file tree
Showing 5 changed files with 419 additions and 599 deletions.
11 changes: 6 additions & 5 deletions ext/json/lib/json/common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,13 @@ def parse(source, opts = nil)
# - Option +max_nesting+, if not provided, defaults to +false+,
# which disables checking for nesting depth.
# - Option +allow_nan+, if not provided, defaults to +true+.
def parse!(source, opts = {})
opts = {
def parse!(source, opts = nil)
options = {
:max_nesting => false,
:allow_nan => true
}.merge(opts)
Parser.new(source, **(opts||{})).parse
}
options.merge!(opts) if opts
Parser.new(source, options).parse
end

# :call-seq:
Expand All @@ -258,7 +259,7 @@ def load_file(filespec, opts = nil)
# JSON.parse!(File.read(path, opts))
#
# See method #parse!
def load_file!(filespec, opts = {})
def load_file!(filespec, opts = nil)
parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
end

Expand Down
29 changes: 25 additions & 4 deletions ext/json/lib/json/ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,36 @@ module JSON
# This module holds all the modules/classes that implement JSON's
# functionality as C extensions.
module Ext
class Parser
class << self
def parse(...)
new(...).parse
end
end

def initialize(source, opts = nil)
@source = source
@config = Config.new(opts)
end

def source
@source.dup
end

def parse
@config.parse(@source)
end
end

require 'json/ext/parser'
Ext::Parser::Config = Ext::ParserConfig
JSON.parser = Ext::Parser

if RUBY_ENGINE == 'truffleruby'
require 'json/ext/parser'
require 'json/truffle_ruby/generator'
JSON.parser = Parser
JSON.generator = ::JSON::TruffleRuby::Generator
else
require 'json/ext/parser'
require 'json/ext/generator'
JSON.parser = Parser
JSON.generator = Generator
end
end
Expand Down
Loading

0 comments on commit 220409f

Please sign in to comment.