{"id":25817220,"url":"https://github.com/uvlad7/json_scanner","last_synced_at":"2026-02-25T16:03:56.737Z","repository":{"id":268119158,"uuid":"903354859","full_name":"uvlad7/json_scanner","owner":"uvlad7","description":null,"archived":false,"fork":false,"pushed_at":"2025-10-26T00:08:30.000Z","size":213,"stargazers_count":8,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-20T07:48:45.810Z","etag":null,"topics":["gem","json","json-parse","json-parser","json-parsing","jsonparser","ruby","ruby-gem","rubygem","sax-parser","yajl"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/json_scanner","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uvlad7.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-12-14T11:48:21.000Z","updated_at":"2025-10-26T00:08:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"a81cf5d6-1a45-4c20-96f8-194a564ed655","html_url":"https://github.com/uvlad7/json_scanner","commit_stats":null,"previous_names":["uvlad7/json_scanner"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/uvlad7/json_scanner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uvlad7%2Fjson_scanner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uvlad7%2Fjson_scanner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uvlad7%2Fjson_scanner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uvlad7%2Fjson_scanner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uvlad7","download_url":"https://codeload.github.com/uvlad7/json_scanner/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uvlad7%2Fjson_scanner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29829411,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-25T15:41:19.027Z","status":"ssl_error","status_checked_at":"2026-02-25T15:40:47.150Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gem","json","json-parse","json-parser","json-parsing","jsonparser","ruby","ruby-gem","rubygem","sax-parser","yajl"],"created_at":"2025-02-28T06:22:58.600Z","updated_at":"2026-02-25T16:03:56.732Z","avatar_url":"https://github.com/uvlad7.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Tests](https://github.com/uvlad7/json_scanner/actions/workflows/main.yml/badge.svg)](https://github.com/uvlad7/json_scanner/actions/workflows/main.yml)\n\n# JsonScanner\n\nExtract values from JSON without full parsing. This gem uses the `yajl` library to scan a JSON string and allows you to parse pieces of it.\n\n## Installation\n\nInstall the gem and add to the application's Gemfile by executing:\n\n    $ bundle add json_scanner\n\nIf bundler is not being used to manage dependencies, install the gem by executing:\n\n    $ gem install json_scanner\n\nThis gem relies on the [yajl](https://github.com/lloyd/yajl) library and needs its development headers being installed. On Defian and Ubuntu you can install thel with the following command:\n\n    $ sudo apt install libyajl2 libyajl-dev\n\nYou can also use `libyajl2` gem to obtain the library. Install it before installing `json_scanner`:\n\n    $ gem install libyajl2 -v '2.1.0'\n\nand then install the gem by executing:\n\n    $ gem install json_scanner --with-libyajl2-gem\n\nIf bundler is being used, you need to ensure the `libyajl2` gem is installed before it installs `json_scanner`:\n\n- add the following into your Gemfile:\n```ruby\ngroup :libyajl do\n  gem \"libyajl2\", \"~\u003e 2.1\"\nend\n```\n- configure `with-libyajl2-gem` flag:\n```\n$ bundle config --local build.json_scanner --with-libyajl2-gem\n```\n- install the group:\n```\n# if you placed json_scanner into a group, replace 'default' with its name\n$ BUNDLE_WITHOUT='default' BUNDLE_WITH='libyajl2' bundle install\n```\n- now you can install the rest as usual:\n```\n$ bundle install\n```\n## Usage\n\n### Basic usage\n\n```ruby\nrequire \"json\"\nrequire \"json_scanner\"\n\nlarge_json = \"[#{\"4,\" * 100_000}42#{\",2\" * 100_000}]\"\nwhere_is_42 = JsonScanner.scan(large_json, [[100_000]]).first\n# =\u003e [[200001, 200003, :number]]\nwhere_is_42.map do |begin_pos, end_pos, _type|\n  JSON.parse(large_json.byteslice(begin_pos...end_pos), quirks_mode: true)\nend\n# =\u003e [42]\n\n# You can supply multiple paths to retrieve different values; each path can match multiple results,\n# values may overlap if needed\nquestion_path = [\"data\", \"question\"]\nanswers_path = [\"data\", \"answers\", (0..-1)]\njson_str = '{\"data\": {\"question\": \"the Ultimate Question of Life, the Universe, and Everything\", \"answers\": [42, 0, 420]}}'\n(question_pos, ), answers_pos = JsonScanner.scan(json_str, [question_path, answers_path])\nquestion = JSON.parse(json_str.byteslice(question_pos[0]...question_pos[1]), quirks_mode: true)\n# =\u003e \"the Ultimate Question of Life, the Universe, and Everything\"\nanswers = answers_pos.map do |begin_pos, end_pos, _type|\n  JSON.parse(json_str.byteslice(begin_pos...end_pos), quirks_mode: true)\nend\n# =\u003e [42, 0, 420]\n\n# Result contains byte offsets, you need to be careful when working with non-binary strings\nemoji_json = '{\"grin\": \"😁\", \"heart\": \"😍\", \"rofl\": \"🤣\"}'\nbegin_pos, end_pos, = JsonScanner.scan(emoji_json, [[\"heart\"]]).first.first\nemoji_json.byteslice(begin_pos...end_pos)\n# =\u003e \"\\\"😍\\\"\"\n# Note: You most likely don't need the `quirks_mode` option unless you are using\n#  an older version of Ruby with the stdlib - or just also old - version of the json gem.\n# In newer versions, `quirks_mode` is enabled by default.\nJSON.parse(emoji_json.byteslice(begin_pos...end_pos), quirks_mode: true)\n# =\u003e \"😍\"\n# You can also do this\n# emoji_json.force_encoding(Encoding::BINARY)[begin_pos...end_pos].force_encoding(Encoding::UTF_8)\n# =\u003e \"\\\"😍\\\"\"\n\n# Ranges are supported as matchers for indexes with the following restrictions:\n# - the start of a range must be positive\n# - the end of a range must be positive or -1\n# - a range with -1 end must be closed, e.g. (0..-1) works, but (0...-1) is forbidden\nJsonScanner.scan('[0, 42, 0]', [[(1..-1)]])\n# =\u003e [[[4, 6, :number], [8, 9, :number]]]\nJsonScanner.scan('[0, 42, 0]', [[JsonScanner::ANY_INDEX]])\n# =\u003e [[[1, 2, :number], [4, 6, :number], [8, 9, :number]]]\n\n# Special matcher JsonScanner::ANY_KEY is supported for object keys\nJsonScanner.scan('{\"a\": 1, \"b\": 2}', [[JsonScanner::ANY_KEY]], with_path: true)\n# =\u003e [[[[\"a\"], [6, 7, :number]], [[\"b\"], [14, 15, :number]]]]\n# Regex mathers aren't supported yet, but you can simulate it using `with_path` option\nJsonScanner.scan(\n  '{\"question1\": 1, \"answer\": 42, \"question2\": 2}',\n  [[JsonScanner::ANY_KEY]], with_path: true,\n).map do |res|\n  res.map do |path, (begin_pos, end_pos, type)|\n    [begin_pos, end_pos, type] if path[0] =~ /\\Aquestion/\n  end.compact\nend\n# =\u003e [[[14, 15, :number], [44, 45, :number]]]\n```\n\n### Parsing\n\n`JsonScanner` offers a convenient - but less performant and memory efficient - `JsonScanner.parse` method, that parses only selected values.\nSkipped array indices are filled with `:stub` values, so you can access matched values by index as expected\n\n```ruby\nJsonScanner.parse('[1, 2, null, {\"a\": 42, \"b\": 33}, 5]', [[(1..2)], [3, \"a\"]])\n# =\u003e [:stub, 2, nil, {\"a\"=\u003e42}]\n```\n\n`JsonScanner.parse` supports almost the same options `JsonScanner.scan` does, except `with_path` and `with_roots_info`; it also accepts `JsonScanner::Selector`, but doesn't accept `JsonScanner::Options`\n\n```ruby\nJsonScanner.parse('[0, 42, 0]garbage', [[(1..-1)]], allow_trailing_garbage: true)\n# =\u003e [:stub, 42, 0]\nJsonScanner.parse(\n  'null false {\"a\": 1, \"b\": [0,1], \"c\": 42}  4.2 {\"b\": [1,2,3]} {} 1 []',\n  JsonScanner::Selector.new([[\"a\"], [\"b\", 2]]), allow_multiple_values: true,\n)\n# =\u003e [:null, :boolean, {\"a\"=\u003e1}, :number, {\"b\"=\u003e[:stub, :stub, 3]}, :object, :number, :array]\n```\n\n### Options\n\n`JsonScanner` supports multiple options\n\n```ruby\nJsonScanner.scan('[0, 42, 0]', [[(1..-1)]], with_path: true)\n# =\u003e [[[[1], [4, 6, :number]], [[2], [8, 9, :number]]]]\nJsonScanner.scan('[0, 42],', [[(1..-1)]], verbose_error: true)\n# JsonScanner::ParseError (parse error: trailing garbage)\n#                                 [0, 42],\n#                      (right here) ------^\n# Note: the 'right here' pointer is wrong in case of a premature EOF error, it's a bug of the libyajl\nJsonScanner.scan('[0, 42,', [[(1..-1)]], verbose_error: true)\n# JsonScanner::ParseError (parse error: premature EOF)\n#                                        [0, 42,\n#                      (right here) ------^\nJsonScanner.scan('[0, /* answer */ 42, 0]', [[(1..-1)]], allow_comments: true)\n# =\u003e [[[17, 19, :number], [21, 22, :number]]]\nJsonScanner.scan(\"\\\"\\x81\\x83\\\"\", [[]], dont_validate_strings: true)\n# =\u003e [[[0, 4, :string]]]\nJsonScanner.scan(\n  \"{\\\"\\x81\\x83\\\": 42}\", [[JsonScanner::ANY_KEY]],\n  dont_validate_strings: true, with_path: true.\n)\n# =\u003e [[[[\"\\x81\\x83\"], [7, 9, :number]]]]\nJsonScanner.scan('[0, 42, 0]garbage', [[(1..-1)]], allow_trailing_garbage: true)\n# =\u003e [[[4, 6, :number], [8, 9, :number]]]\nJsonScanner.scan('[0, 42, 0]  [0, 34]', [[(1..-1)]], allow_multiple_values: true)\n# =\u003e [[[4, 6, :number], [8, 9, :number], [16, 18, :number]]]\nJsonScanner.scan('[0, 42, 0', [[(1..-1)]], allow_partial_values: true)\n# =\u003e [[[4, 6, :number], [8, 9, :number]]]\nJsonScanner.scan(\n  '{\"a\": 1}', [[JsonScanner::ANY_KEY]],\n  with_path: true, symbolize_path_keys: true,\n)\n# =\u003e [[[[:a], [6, 7, :number]]]]\nJsonScanner.scan('[42]42{\"a\":42} true', [], allow_multiple_values: true, with_roots_info: true).last\n# =\u003e [[:array, 0], [:number, 4], [:object, 6], [:boolean, 15]]\n```\n\n### Comments in the JSON\n\nNote that the standard `JSON` library supports comments, so you may want to enable it in the `JsonScanner` as well\n```ruby\njson_str = '{\"answer\": {\"value\": 42 /* the Ultimate Question of Life, the Universe, and Everything */ }}'\nJsonScanner.scan(\n  json_str, [[\"answer\"]], allow_comments: true.\n).first.map do |begin_pos, end_pos, _type|\n  JSON.parse(json_str.byteslice(begin_pos...end_pos), quirks_mode: true)\nend\n# =\u003e [{\"value\"=\u003e42}]\n```\n\n### Find the end of a JSON string\n\n`allow_trailing_garbage` option may come in handy if you want to extract a JSON string from a JS text\n```ruby\nscript_text = \u003c\u003c~'JS'\n      \u003cscript\u003ewindow.__APOLLO_STATE__={\"ContentItem:0\":{\"__typename\":\"ContentItem\",\"id\":0, \"configurationType\":\"NO_CONFIGURATION\",\"replacementPartsUrl\":null,\"relatedCategories\":[{\"__ref\":\"Category:109450\"},{\"__ref\":\"Category:82044355\"},{\"__ref\":\"Category:109441\"},{\"__ref\":\"Category:109442\"},{\"__ref\":\"Category:109449\"},{\"__ref\":\"Category:109444\"},{\"__ref\":\"Category:82043730\"}],\"recommendedOptions\":[]}};window.__APPVERSION__=7018;window.__CONFIG_ENV__={value: 'PRODUCTION'};\u003c/script\u003e\nJS\njson_with_trailing_garbage = script_text[/__APOLLO_STATE__\\s*=\\s*({.+)/, 1]\njson_end_pos = JsonScanner.scan(\n  json_with_trailing_garbage, [[]], allow_trailing_garbage: true,\n).first.first[1]\napollo_state = JSON.parse(json_with_trailing_garbage[0...json_end_pos])\n```\n\n### Reuse configuration\n\nYou can create a `JsonScanner::Selector` instance and reuse it between `JsonScanner.scan` calls\n\n```ruby\nrequire \"json_scanner\"\n\nselector = JsonScanner::Selector.new([[], [\"key\"], [(0..-1)]])\n# =\u003e #\u003cJsonScanner::Selector [[], ['key'], [(0..-1)]]\u003e\nJsonScanner.scan('{\"key\": \"42\"}', selector)\n# =\u003e [[[0, 13, :object]], [[8, 12, :string]], []]\nJsonScanner.scan('{\"key\": \"42\"}', selector, with_path: true)\n# =\u003e [[[[], [0, 13, :object]]], [[[\"key\"], [8, 12, :string]]], []]\nJsonScanner.scan('[0, 42]', selector)\n# =\u003e [[[0, 7, :array]], [], [[1, 2, :number], [4, 6, :number]]]\nJsonScanner.scan('[0, 42]', selector, with_path: true)\n# =\u003e [[[[], [0, 7, :array]]], [], [[[0], [1, 2, :number]], [[1], [4, 6, :number]]]]\n```\n\nConfiguration options can be passed as a hash, even on Ruby 3\n```ruby\noptions = { allow_trailing_garbage: true, allow_partial_values: true }\nJsonScanner.scan('[0, 42', [[1]], options) == JsonScanner.scan('[0, 42]_', [[1]], options)\n# =\u003e true\n```\n\nAlternatively, you can use `JsonScanner::Options` not to parse a hash every time\n```ruby\nrequire 'benchmark'\n\noptions = { allow_trailing_garbage: true, allow_partial_values: true }\nscanner_options = JsonScanner::Options.new(options)\n# =\u003e #\u003cJsonScanner::Options {allow_trailing_garbage: true, allow_partial_values: true}\u003e\njson_str = '{\"question1\": 1, \"answer\": 42, \"question2\": 2}'\nselector = JsonScanner::Selector.new([['answer']])\nBenchmark.bmbm do |x|\n  x.report(\"options\") { 1_000_000.times { JsonScanner.scan(json_str, selector, options) } }\n  x.report(\"scanner_options\") { 1_000_000.times { JsonScanner.scan(json_str, selector, scanner_options) } }\nend\n# produces the following on Ruby 3.2.2\n# Rehearsal ---------------------------------------------------\n# options           0.957705   0.002293   0.959998 (  0.960228)\n# scanner_options   0.903800   0.003121   0.906921 (  0.906956)\n# ------------------------------------------ total: 1.866919sec\n\n#                       user     system      total        real\n# options           0.929433   0.001102   0.930535 (  0.931687)\n# scanner_options   0.907289   0.005055   0.912344 (  0.912379)\n```\n\n### Streaming mode\n\nStreaming mode isn't supported yet, as it's harder to implement and to use. I plan to add it in the future, its API is a subject to discussion. If you have suggestions, use cases, or preferences for how it should behave, I’d love to hear from you!\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at [github](https://github.com/uvlad7/json_scanner).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Benchmarks\n\n```shell\n========= JSON string size: 463 KB =========\npath :data, :search, :searchResult, :paginationV2, :maxPage; extracted values: [8, 8, 8, 8, 8, 8, 8, 8]\nruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [x86_64-linux]\nWarming up --------------------------------------\n                json     8.000 i/100ms\n                  oj    16.000 i/100ms\n   json_scanner scan    66.000 i/100ms\n  json_scanner parse    44.000 i/100ms\n            simdjson    12.000 i/100ms\n           yajl-ruby    12.000 i/100ms\n                yaji     1.000 i/100ms\n            ffi-yajl     9.000 i/100ms\n     yajl-ffi (stub)     1.000 i/100ms\nCalculating -------------------------------------\n                json     89.542 (±20.1%) i/s   (11.17 ms/i) -    432.000 in   5.083579s\n                  oj    155.916 (±29.5%) i/s    (6.41 ms/i) -    688.000 in   5.033501s\n   json_scanner scan    661.426 (±10.7%) i/s    (1.51 ms/i) -      3.300k in   5.059478s\n  json_scanner parse    649.443 (±12.0%) i/s    (1.54 ms/i) -      3.212k in   5.045073s\n            simdjson    156.793 (±11.5%) i/s    (6.38 ms/i) -    780.000 in   5.053348s\n           yajl-ruby    120.428 (± 5.0%) i/s    (8.30 ms/i) -    612.000 in   5.096770s\n                yaji     18.486 (± 0.0%) i/s   (54.09 ms/i) -     93.000 in   5.034553s\n            ffi-yajl    126.109 (± 9.5%) i/s    (7.93 ms/i) -    630.000 in   5.059638s\n     yajl-ffi (stub)     13.726 (±21.9%) i/s   (72.85 ms/i) -     66.000 in   5.028068s\n\nComparison:\n   json_scanner scan:      661.4 i/s\n  json_scanner parse:      649.4 i/s - same-ish: difference falls within error\n            simdjson:      156.8 i/s - 4.22x  slower\n                  oj:      155.9 i/s - 4.24x  slower\n            ffi-yajl:      126.1 i/s - 5.24x  slower\n           yajl-ruby:      120.4 i/s - 5.49x  slower\n                json:       89.5 i/s - 7.39x  slower\n                yaji:       18.5 i/s - 35.78x  slower\n     yajl-ffi (stub):       13.7 i/s - 48.19x  slower\n\nCalculating -------------------------------------\n                json     1.987M memsize (     0.000  retained)\n                        26.302k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n                  oj     1.379M memsize (     0.000  retained)\n                         9.665k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n   json_scanner scan   368.000  memsize (     0.000  retained)\n                         6.000  objects (     0.000  retained)\n                         1.000  strings (     0.000  retained)\n  json_scanner parse     2.240k memsize (   528.000  retained)\n                        23.000  objects (     9.000  retained)\n                         1.000  strings (     0.000  retained)\n            simdjson     2.203M memsize (     0.000  retained)\n                        30.038k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n           yajl-ruby     1.379M memsize (     0.000  retained)\n                         9.666k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n                yaji     8.593M memsize (     0.000  retained)\n                       138.847k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n            ffi-yajl     1.380M memsize (   168.000  retained)\n                         9.671k objects (     1.000  retained)\n                        50.000  strings (     0.000  retained)\n     yajl-ffi (stub)   233.913M memsize (   208.000  retained)\n                        98.406k objects (     2.000  retained)\n                        50.000  strings (     1.000  retained)\n\nComparison:\n   json_scanner scan:        368 allocated\n  json_scanner parse:       2240 allocated - 6.09x more\n                  oj:    1379274 allocated - 3748.03x more\n           yajl-ruby:    1379442 allocated - 3748.48x more\n            ffi-yajl:    1380058 allocated - 3750.16x more\n                json:    1987269 allocated - 5400.19x more\n            simdjson:    2202607 allocated - 5985.35x more\n                yaji:    8592765 allocated - 23349.90x more\n     yajl-ffi (stub):  233913419 allocated - 635634.29x more\n============================================\n\n\n========= JSON string size: 463 KB =========\npath :data, :search, :searchResult, :paginationV2, :maxPage; extracted values: [8, 8, 8, 8, 8, 8, 8, 8]\nruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]\nWarming up --------------------------------------\n                json    15.000 i/100ms\n                  oj    17.000 i/100ms\n   json_scanner scan    66.000 i/100ms\n  json_scanner parse    74.000 i/100ms\n            simdjson     4.000 i/100ms\n           yajl-ruby    11.000 i/100ms\n                yaji     2.000 i/100ms\n            ffi-yajl     9.000 i/100ms\n     yajl-ffi (stub)     1.000 i/100ms\nCalculating -------------------------------------\n                json    157.797 (± 4.4%) i/s    (6.34 ms/i) -    795.000 in   5.050469s\n                  oj    163.243 (± 7.4%) i/s    (6.13 ms/i) -    816.000 in   5.027023s\n   json_scanner scan    630.410 (± 7.6%) i/s    (1.59 ms/i) -      3.168k in   5.060172s\n  json_scanner parse    684.963 (± 3.1%) i/s    (1.46 ms/i) -      3.478k in   5.082918s\n            simdjson     44.316 (± 0.0%) i/s   (22.57 ms/i) -    224.000 in   5.055158s\n           yajl-ruby    109.968 (± 1.8%) i/s    (9.09 ms/i) -    550.000 in   5.002486s\n                yaji     27.216 (± 3.7%) i/s   (36.74 ms/i) -    138.000 in   5.073578s\n            ffi-yajl    115.785 (± 4.3%) i/s    (8.64 ms/i) -    585.000 in   5.064551s\n     yajl-ffi (stub)     14.820 (±13.5%) i/s   (67.48 ms/i) -     73.000 in   5.007391s\n\nComparison:\n  json_scanner parse:      685.0 i/s\n   json_scanner scan:      630.4 i/s - same-ish: difference falls within error\n                  oj:      163.2 i/s - 4.20x  slower\n                json:      157.8 i/s - 4.34x  slower\n            ffi-yajl:      115.8 i/s - 5.92x  slower\n           yajl-ruby:      110.0 i/s - 6.23x  slower\n            simdjson:       44.3 i/s - 15.46x  slower\n                yaji:       27.2 i/s - 25.17x  slower\n     yajl-ffi (stub):       14.8 i/s - 46.22x  slower\n\nCalculating -------------------------------------\n                json     1.402M memsize (     0.000  retained)\n                        10.184k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n                  oj     1.441M memsize (   168.000  retained)\n                         9.665k objects (     1.000  retained)\n                        50.000  strings (     0.000  retained)\n   json_scanner scan   368.000  memsize (     0.000  retained)\n                         6.000  objects (     0.000  retained)\n                         1.000  strings (     0.000  retained)\n  json_scanner parse     2.072k memsize (   360.000  retained)\n                        22.000  objects (     8.000  retained)\n                         1.000  strings (     0.000  retained)\n            simdjson     2.379M memsize (     0.000  retained)\n                        30.037k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n           yajl-ruby     1.441M memsize (     0.000  retained)\n                         9.666k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n                yaji    10.230M memsize (     0.000  retained)\n                       138.847k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n            ffi-yajl     1.441M memsize (     0.000  retained)\n                         9.671k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n     yajl-ffi (stub)   234.105M memsize (   208.000  retained)\n                        98.509k objects (     2.000  retained)\n                        50.000  strings (     1.000  retained)\n\nComparison:\n   json_scanner scan:        368 allocated\n  json_scanner parse:       2072 allocated - 5.63x more\n                json:    1401815 allocated - 3809.28x more\n                  oj:    1440774 allocated - 3915.15x more\n           yajl-ruby:    1440814 allocated - 3915.26x more\n            ffi-yajl:    1441310 allocated - 3916.60x more\n            simdjson:    2378766 allocated - 6464.04x more\n                yaji:   10230271 allocated - 27799.65x more\n     yajl-ffi (stub):  234104932 allocated - 636154.71x more\n============================================\n\n\n========= JSON string size: 463 KB =========\npath :data, :search, :searchResult, :paginationV2, :maxPage; extracted values: [8, 8, 8, 8, 8, 8, 8, 8]\nruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux]\nWarming up --------------------------------------\n                json    11.000 i/100ms\n                  oj    14.000 i/100ms\n   json_scanner scan    70.000 i/100ms\n  json_scanner parse    69.000 i/100ms\n            simdjson     4.000 i/100ms\n           yajl-ruby     9.000 i/100ms\n                yaji     2.000 i/100ms\n            ffi-yajl     9.000 i/100ms\n     yajl-ffi (stub)     1.000 i/100ms\nCalculating -------------------------------------\n                json    130.231 (± 3.8%) i/s    (7.68 ms/i) -    660.000 in   5.076796s\n                  oj    145.239 (± 6.9%) i/s    (6.89 ms/i) -    728.000 in   5.047231s\n   json_scanner scan    626.381 (± 9.3%) i/s    (1.60 ms/i) -      3.150k in   5.079929s\n  json_scanner parse    667.710 (± 4.5%) i/s    (1.50 ms/i) -      3.381k in   5.076284s\n            simdjson     37.137 (±10.8%) i/s   (26.93 ms/i) -    184.000 in   5.025192s\n           yajl-ruby     98.301 (± 6.1%) i/s   (10.17 ms/i) -    495.000 in   5.054221s\n                yaji     25.146 (± 4.0%) i/s   (39.77 ms/i) -    126.000 in   5.026175s\n            ffi-yajl    105.936 (± 3.8%) i/s    (9.44 ms/i) -    531.000 in   5.022619s\n     yajl-ffi (stub)     13.615 (±14.7%) i/s   (73.45 ms/i) -     67.000 in   5.007215s\n\nComparison:\n  json_scanner parse:      667.7 i/s\n   json_scanner scan:      626.4 i/s - same-ish: difference falls within error\n                  oj:      145.2 i/s - 4.60x  slower\n                json:      130.2 i/s - 5.13x  slower\n            ffi-yajl:      105.9 i/s - 6.30x  slower\n           yajl-ruby:       98.3 i/s - 6.79x  slower\n            simdjson:       37.1 i/s - 17.98x  slower\n                yaji:       25.1 i/s - 26.55x  slower\n     yajl-ffi (stub):       13.6 i/s - 49.04x  slower\n\nCalculating -------------------------------------\n                json     1.377M memsize (     0.000  retained)\n                        10.184k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n                  oj     1.363M memsize (     0.000  retained)\n                         9.665k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n   json_scanner scan   360.000  memsize (     0.000  retained)\n                         6.000  objects (     0.000  retained)\n                         1.000  strings (     0.000  retained)\n  json_scanner parse     2.000k memsize (   360.000  retained)\n                        22.000  objects (     8.000  retained)\n                         1.000  strings (     0.000  retained)\n            simdjson     2.301M memsize (     0.000  retained)\n                        30.037k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n           yajl-ruby     1.364M memsize (     0.000  retained)\n                         9.666k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n                yaji    10.230M memsize (     0.000  retained)\n                       138.847k objects (     0.000  retained)\n                        50.000  strings (     0.000  retained)\n            ffi-yajl     1.364M memsize (    40.000  retained)\n                         9.671k objects (     1.000  retained)\n                        50.000  strings (     1.000  retained)\n     yajl-ffi (stub)   234.105M memsize (   208.000  retained)\n                        98.509k objects (     2.000  retained)\n                        50.000  strings (     1.000  retained)\n\nComparison:\n   json_scanner scan:        360 allocated\n  json_scanner parse:       2000 allocated - 5.56x more\n                  oj:    1363382 allocated - 3787.17x more\n           yajl-ruby:    1363550 allocated - 3787.64x more\n            ffi-yajl:    1364158 allocated - 3789.33x more\n                json:    1376519 allocated - 3823.66x more\n            simdjson:    2301382 allocated - 6392.73x more\n                yaji:   10230263 allocated - 28417.40x more\n     yajl-ffi (stub):  234104932 allocated - 650291.48x more\n============================================\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuvlad7%2Fjson_scanner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuvlad7%2Fjson_scanner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuvlad7%2Fjson_scanner/lists"}