├── .codeclimate.yml ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .rspec ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── benchmark ├── encode.rb ├── encode_json_and_marshal.rb ├── encode_json_and_yaml.rb ├── http.rb ├── parse.rb ├── parse_json_and_marshal.rb ├── parse_json_and_yaml.rb ├── parse_stream.rb └── subjects │ ├── item.json │ ├── ohai.json │ ├── ohai.marshal_dump │ ├── ohai.yml │ ├── twitter_search.json │ ├── twitter_stream.json │ └── unicode.json ├── examples ├── encoding │ ├── chunked_encoding.rb │ ├── one_shot.rb │ └── to_an_io.rb ├── http │ ├── twitter_search_api.rb │ └── twitter_stream_api.rb └── parsing │ ├── from_file.rb │ ├── from_stdin.rb │ └── from_string.rb ├── ext └── yajl │ ├── api │ ├── yajl_common.h │ ├── yajl_gen.h │ ├── yajl_parse.h │ └── yajl_version.h │ ├── extconf.rb │ ├── yajl.c │ ├── yajl_alloc.c │ ├── yajl_alloc.h │ ├── yajl_buf.c │ ├── yajl_buf.h │ ├── yajl_bytestack.h │ ├── yajl_encode.c │ ├── yajl_encode.h │ ├── yajl_ext.c │ ├── yajl_ext.h │ ├── yajl_gen.c │ ├── yajl_lex.c │ ├── yajl_lex.h │ ├── yajl_parser.c │ ├── yajl_parser.h │ └── yajl_version.c ├── lib ├── yajl.rb └── yajl │ ├── bzip2.rb │ ├── bzip2 │ ├── stream_reader.rb │ └── stream_writer.rb │ ├── deflate.rb │ ├── deflate │ ├── stream_reader.rb │ └── stream_writer.rb │ ├── gzip.rb │ ├── gzip │ ├── stream_reader.rb │ └── stream_writer.rb │ ├── http_stream.rb │ ├── json_gem.rb │ ├── json_gem │ ├── encoding.rb │ └── parsing.rb │ └── version.rb ├── script └── bootstrap ├── spec ├── encoding │ └── encoding_spec.rb ├── global │ └── global_spec.rb ├── http │ ├── fixtures │ │ ├── http.bzip2.dump │ │ ├── http.chunked.dump │ │ ├── http.deflate.dump │ │ ├── http.error.dump │ │ ├── http.gzip.dump │ │ ├── http.html.dump │ │ └── http.raw.dump │ ├── http_delete_spec.rb │ ├── http_error_spec.rb │ ├── http_get_spec.rb │ ├── http_post_spec.rb │ ├── http_put_spec.rb │ └── http_stream_options_spec.rb ├── json_gem_compatibility │ └── compatibility_spec.rb ├── parsing │ ├── active_support_spec.rb │ ├── chunked_spec.rb │ ├── fixtures │ │ ├── fail.15.json │ │ ├── fail.16.json │ │ ├── fail.17.json │ │ ├── fail.26.json │ │ ├── fail11.json │ │ ├── fail12.json │ │ ├── fail13.json │ │ ├── fail14.json │ │ ├── fail19.json │ │ ├── fail20.json │ │ ├── fail21.json │ │ ├── fail22.json │ │ ├── fail23.json │ │ ├── fail24.json │ │ ├── fail25.json │ │ ├── fail27.json │ │ ├── fail28.json │ │ ├── fail3.json │ │ ├── fail4.json │ │ ├── fail5.json │ │ ├── fail6.json │ │ ├── fail9.json │ │ ├── pass.array.json │ │ ├── pass.codepoints_from_unicode_org.json │ │ ├── pass.contacts.json │ │ ├── pass.db100.xml.json │ │ ├── pass.db1000.xml.json │ │ ├── pass.dc_simple_with_comments.json │ │ ├── pass.deep_arrays.json │ │ ├── pass.difficult_json_c_test_case.json │ │ ├── pass.difficult_json_c_test_case_with_comments.json │ │ ├── pass.doubles.json │ │ ├── pass.empty_array.json │ │ ├── pass.empty_string.json │ │ ├── pass.escaped_bulgarian.json │ │ ├── pass.escaped_foobar.json │ │ ├── pass.item.json │ │ ├── pass.json-org-sample1.json │ │ ├── pass.json-org-sample2.json │ │ ├── pass.json-org-sample3.json │ │ ├── pass.json-org-sample4-nows.json │ │ ├── pass.json-org-sample4.json │ │ ├── pass.json-org-sample5.json │ │ ├── pass.map-spain.xml.json │ │ ├── pass.ns-invoice100.xml.json │ │ ├── pass.ns-soap.xml.json │ │ ├── pass.numbers-fp-4k.json │ │ ├── pass.numbers-fp-64k.json │ │ ├── pass.numbers-int-4k.json │ │ ├── pass.numbers-int-64k.json │ │ ├── pass.twitter-search.json │ │ ├── pass.twitter-search2.json │ │ ├── pass.unicode.json │ │ ├── pass.yelp.json │ │ ├── pass1.json │ │ ├── pass2.json │ │ └── pass3.json │ ├── fixtures_spec.rb │ ├── large_number_spec.rb │ └── one_off_spec.rb ├── projection │ ├── project_file.rb │ └── projection.rb ├── rcov.opts └── spec_helper.rb ├── tasks ├── compile.rake └── rspec.rake └── yajl-ruby.gemspec /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | # This is a sample .codeclimate.yml configured for Engine analysis on Code 2 | # Climate Platform. For an overview of the Code Climate Platform, see here: 3 | # http://docs.codeclimate.com/article/300-the-codeclimate-platform 4 | 5 | # Under the engines key, you can configure which engines will analyze your repo. 6 | # Each key is an engine name. For each value, you need to specify enabled: true 7 | # to enable the engine as well as any other engines-specific configuration. 8 | 9 | # For more details, see here: 10 | # http://docs.codeclimate.com/article/289-configuring-your-repository-via-codeclimate-yml#platform 11 | 12 | # For a list of all available engines, see here: 13 | # http://docs.codeclimate.com/article/296-engines-available-engines 14 | 15 | engines: 16 | # to turn on an engine, add it here and set enabled to `true` 17 | # to turn off an engine, set enabled to `false` or remove it 18 | rubocop: 19 | enabled: true 20 | 21 | # Engines can analyze files and report issues on them, but you can separately 22 | # decide which files will receive ratings based on those issues. This is 23 | # specified by path patterns under the ratings key. 24 | 25 | # For more details see here: 26 | # http://docs.codeclimate.com/article/289-configuring-your-repository-via-codeclimate-yml#platform 27 | 28 | # Note: If the ratings key is not specified, this will result in a 0.0 GPA on your dashboard. 29 | 30 | ratings: 31 | paths: 32 | - ext/** 33 | - lib/** 34 | 35 | # You can globally exclude files from being analyzed by any engine using the 36 | # exclude_paths key. 37 | 38 | #exclude_paths: 39 | #- spec/**/* 40 | #- vendor/**/* 41 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | strategy: 8 | matrix: 9 | ruby_version: [2.6, 2.7, 3.0] 10 | fail-fast: false 11 | runs-on: ubuntu-latest 12 | name: Test on Ruby ${{ matrix.ruby_version }} 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Setup Ruby ${{ matrix.ruby_version }} 16 | uses: ruby/setup-ruby@v1 17 | with: 18 | ruby-version: ${{ matrix.ruby_version }} 19 | - name: Install dependencies 20 | run: bundle install 21 | - name: Build gem 22 | run: gem build yajl-ruby.gemspec 23 | - name: Install gem 24 | run: gem install yajl-ruby 25 | - name: Run tests 26 | run: bundle exec rake spec 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | benchmark/subjects/contacts.* 3 | *.rbc 4 | *.o 5 | *.dylib 6 | *.bundle 7 | TODO.txt 8 | tmp/* 9 | pkg/* 10 | vendor/gems 11 | Gemfile.lock 12 | .rbx 13 | bin/ 14 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --colour 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Brian Lopez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Load custom tasks 2 | Dir['tasks/*.rake'].sort.each { |f| load f } 3 | -------------------------------------------------------------------------------- /benchmark/encode.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'benchmark' 6 | require 'yajl' 7 | require 'stringio' 8 | begin 9 | require 'json' 10 | rescue LoadError 11 | end 12 | begin 13 | require 'psych' 14 | rescue LoadError 15 | end 16 | begin 17 | require 'active_support' 18 | rescue LoadError 19 | end 20 | 21 | filename = ARGV[0] || 'benchmark/subjects/ohai.json' 22 | hash = File.open(filename, 'rb') { |f| Yajl::Parser.new.parse(f.read) } 23 | 24 | times = ARGV[1] ? ARGV[1].to_i : 1000 25 | puts "Starting benchmark encoding #{filename} #{times} times\n\n" 26 | Benchmark.bmbm { |x| 27 | io_encoder = Yajl::Encoder.new 28 | string_encoder = Yajl::Encoder.new 29 | 30 | x.report("Yajl::Encoder#encode (to an IO)") { 31 | times.times { 32 | io_encoder.encode(hash, StringIO.new) 33 | } 34 | } 35 | x.report("Yajl::Encoder#encode (to a String)") { 36 | times.times { 37 | output = string_encoder.encode(hash) 38 | } 39 | } 40 | if defined?(JSON) 41 | x.report("JSON.generate") { 42 | times.times { 43 | JSON.generate(hash) 44 | } 45 | } 46 | end 47 | if defined?(Psych) 48 | x.report("Psych.to_json") { 49 | times.times { 50 | Psych.to_json(hash) 51 | } 52 | } 53 | if defined?(Psych::JSON::Stream) 54 | x.report("Psych::JSON::Stream") { 55 | times.times { 56 | io = StringIO.new 57 | stream = Psych::JSON::Stream.new io 58 | stream.start 59 | stream.push hash 60 | stream.finish 61 | } 62 | } 63 | end 64 | end 65 | if defined?(ActiveSupport::JSON) 66 | x.report("ActiveSupport::JSON.encode") { 67 | times.times { 68 | ActiveSupport::JSON.encode(hash) 69 | } 70 | } 71 | end 72 | } 73 | -------------------------------------------------------------------------------- /benchmark/encode_json_and_marshal.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'benchmark' 6 | require 'yajl' 7 | require 'stringio' 8 | begin 9 | require 'json' 10 | rescue LoadError 11 | end 12 | 13 | times = ARGV[0] ? ARGV[0].to_i : 1000 14 | filename = 'benchmark/subjects/ohai.json' 15 | json = File.new(filename, 'r') 16 | hash = Yajl::Parser.new.parse(json) 17 | json.close 18 | 19 | puts "Starting benchmark encoding #{filename} #{times} times\n\n" 20 | Benchmark.bmbm { |x| 21 | encoder = Yajl::Encoder.new 22 | x.report { 23 | puts "Yajl::Encoder#encode" 24 | times.times { 25 | encoder.encode(hash, StringIO.new) 26 | } 27 | } 28 | if defined?(JSON) 29 | x.report { 30 | puts "JSON's #to_json" 31 | times.times { 32 | JSON.generate(hash) 33 | } 34 | } 35 | end 36 | x.report { 37 | puts "Marshal.dump" 38 | times.times { 39 | Marshal.dump(hash) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /benchmark/encode_json_and_yaml.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'benchmark' 6 | require 'yajl' 7 | begin 8 | require 'json' 9 | rescue LoadError 10 | end 11 | require 'yaml' 12 | 13 | # JSON Section 14 | filename = 'benchmark/subjects/ohai.json' 15 | json = File.new(filename, 'r') 16 | hash = Yajl::Parser.new.parse(json) 17 | json.close 18 | 19 | times = ARGV[0] ? ARGV[0].to_i : 1000 20 | puts "Starting benchmark encoding #{filename} into JSON #{times} times\n\n" 21 | Benchmark.bmbm { |x| 22 | encoder = Yajl::Encoder.new 23 | x.report { 24 | puts "Yajl::Encoder#encode" 25 | times.times { 26 | encoder.encode(hash, StringIO.new) 27 | } 28 | } 29 | if defined?(JSON) 30 | x.report { 31 | puts "JSON's #to_json" 32 | times.times { 33 | JSON.generate(hash) 34 | } 35 | } 36 | end 37 | } 38 | 39 | # YAML Section 40 | filename = 'benchmark/subjects/ohai.yml' 41 | yml = File.new(filename, 'r') 42 | data = YAML.load_stream(yml) 43 | yml.close 44 | 45 | puts "Starting benchmark encoding #{filename} into YAML #{times} times\n\n" 46 | Benchmark.bmbm { |x| 47 | x.report { 48 | puts "YAML.dump" 49 | times.times { 50 | YAML.dump(data, StringIO.new) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /benchmark/http.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'benchmark' 6 | require 'yajl/http_stream' 7 | require 'yajl/gzip' 8 | require 'yajl/deflate' 9 | require 'yajl/bzip2' unless defined?(Bzip2) 10 | require 'json' 11 | require 'uri' 12 | require 'net/http' 13 | 14 | uri = URI.parse('http://search.twitter.com/search.json?q=github') 15 | # uri = URI.parse('http://localhost/yajl-ruby.git/benchmark/subjects/contacts.json') 16 | 17 | times = ARGV[0] ? ARGV[0].to_i : 1 18 | puts "Starting benchmark parsing #{uri.to_s} #{times} times\n\n" 19 | Benchmark.bmbm { |x| 20 | x.report { 21 | puts "Yajl::HttpStream.get" 22 | times.times { 23 | Yajl::HttpStream.get(uri) 24 | } 25 | } 26 | x.report { 27 | puts "JSON.parser" 28 | times.times { 29 | JSON.parse(Net::HTTP.get_response(uri).body, :max_nesting => false) 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /benchmark/parse.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'benchmark' 6 | require 'yaml' 7 | require 'yajl' 8 | begin 9 | require 'json' 10 | rescue LoadError 11 | end 12 | begin 13 | require 'psych' 14 | rescue LoadError 15 | end 16 | begin 17 | require 'active_support' 18 | rescue LoadError 19 | end 20 | 21 | filename = ARGV[0] || 'benchmark/subjects/item.json' 22 | json = File.new(filename, 'r') 23 | 24 | times = ARGV[1] ? ARGV[1].to_i : 10_000 25 | puts "Starting benchmark parsing #{File.size(filename)} bytes of JSON data #{times} times\n\n" 26 | Benchmark.bmbm { |x| 27 | io_parser = Yajl::Parser.new 28 | io_parser.on_parse_complete = lambda {|obj|} if times > 1 29 | x.report { 30 | puts "Yajl::Parser#parse (from an IO)" 31 | times.times { 32 | json.rewind 33 | io_parser.parse(json) 34 | } 35 | } 36 | string_parser = Yajl::Parser.new 37 | string_parser.on_parse_complete = lambda {|obj|} if times > 1 38 | x.report { 39 | puts "Yajl::Parser#parse (from a String)" 40 | times.times { 41 | json.rewind 42 | string_parser.parse(json.read) 43 | } 44 | } 45 | if defined?(JSON) 46 | x.report { 47 | puts "JSON.parse" 48 | times.times { 49 | json.rewind 50 | JSON.parse(json.read, :max_nesting => false) 51 | } 52 | } 53 | end 54 | if defined?(ActiveSupport::JSON) 55 | x.report { 56 | puts "ActiveSupport::JSON.decode" 57 | times.times { 58 | json.rewind 59 | ActiveSupport::JSON.decode(json.read) 60 | } 61 | } 62 | end 63 | x.report { 64 | puts "YAML.load (from an IO)" 65 | times.times { 66 | json.rewind 67 | YAML.load(json) 68 | } 69 | } 70 | x.report { 71 | puts "YAML.load (from a String)" 72 | times.times { 73 | json.rewind 74 | YAML.load(json.read) 75 | } 76 | } 77 | if defined?(Psych) 78 | x.report { 79 | puts "Psych.load (from an IO)" 80 | times.times { 81 | json.rewind 82 | Psych.load(json) 83 | } 84 | } 85 | x.report { 86 | puts "Psych.load (from a String)" 87 | times.times { 88 | json.rewind 89 | Psych.load(json.read) 90 | } 91 | } 92 | end 93 | } 94 | json.close -------------------------------------------------------------------------------- /benchmark/parse_json_and_marshal.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'benchmark' 6 | require 'yajl' 7 | begin 8 | require 'json' 9 | rescue LoadError 10 | end 11 | 12 | # JSON section 13 | filename = 'benchmark/subjects/ohai.json' 14 | marshal_filename = 'benchmark/subjects/ohai.marshal_dump' 15 | json = File.new(filename, 'r') 16 | marshal_file = File.new(marshal_filename, 'r') 17 | 18 | hash = {} 19 | 20 | times = ARGV[0] ? ARGV[0].to_i : 1000 21 | puts "Starting benchmark parsing #{File.size(filename)} bytes of JSON data #{times} times\n\n" 22 | Benchmark.bmbm { |x| 23 | x.report { 24 | puts "Yajl::Parser#parse" 25 | yajl = Yajl::Parser.new 26 | yajl.on_parse_complete = lambda {|obj|} if times > 1 27 | times.times { 28 | json.rewind 29 | hash = yajl.parse(json) 30 | } 31 | } 32 | if defined?(JSON) 33 | x.report { 34 | puts "JSON.parse" 35 | times.times { 36 | json.rewind 37 | JSON.parse(json.read, :max_nesting => false) 38 | } 39 | } 40 | end 41 | x.report { 42 | puts "Marshal.load" 43 | times.times { 44 | marshal_file.rewind 45 | Marshal.load(marshal_file) 46 | } 47 | } 48 | } 49 | json.close 50 | marshal_file.close -------------------------------------------------------------------------------- /benchmark/parse_json_and_yaml.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'benchmark' 6 | require 'yajl' 7 | begin 8 | require 'json' 9 | rescue LoadError 10 | end 11 | require 'yaml' 12 | 13 | # JSON section 14 | filename = 'benchmark/subjects/ohai.json' 15 | json = File.new(filename, 'r') 16 | 17 | times = ARGV[0] ? ARGV[0].to_i : 1000 18 | puts "Starting benchmark parsing #{File.size(filename)} bytes of JSON data #{times} times\n\n" 19 | Benchmark.bmbm { |x| 20 | parser = Yajl::Parser.new 21 | parser.on_parse_complete = lambda {|obj|} if times > 1 22 | x.report { 23 | puts "Yajl::Parser#parse" 24 | times.times { 25 | json.rewind 26 | parser.parse(json) 27 | } 28 | } 29 | if defined?(JSON) 30 | x.report { 31 | puts "JSON.parse" 32 | times.times { 33 | json.rewind 34 | JSON.parse(json.read, :max_nesting => false) 35 | } 36 | } 37 | end 38 | } 39 | json.close 40 | 41 | # YAML section 42 | filename = 'benchmark/subjects/ohai.yml' 43 | yaml = File.new(filename, 'r') 44 | 45 | puts "Starting benchmark parsing #{File.size(filename)} bytes of YAML data #{times} times\n\n" 46 | Benchmark.bmbm { |x| 47 | x.report { 48 | puts "YAML.load_stream" 49 | times.times { 50 | yaml.rewind 51 | YAML.load(yaml) 52 | } 53 | } 54 | } 55 | yaml.close -------------------------------------------------------------------------------- /benchmark/parse_stream.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'benchmark' 6 | require 'yajl' 7 | begin 8 | require 'json' 9 | rescue LoadError 10 | end 11 | begin 12 | require 'active_support' 13 | rescue LoadError 14 | end 15 | 16 | filename = 'benchmark/subjects/twitter_stream.json' 17 | json = File.new(filename, 'r') 18 | 19 | times = ARGV[0] ? ARGV[0].to_i : 100 20 | puts "Starting benchmark parsing JSON stream (#{File.size(filename)} bytes of JSON data with 430 JSON separate strings) #{times} times\n\n" 21 | Benchmark.bmbm { |x| 22 | parser = Yajl::Parser.new 23 | parser.on_parse_complete = lambda {|obj|} 24 | x.report { 25 | puts "Yajl::Parser#parse" 26 | times.times { 27 | json.rewind 28 | parser.parse(json) 29 | } 30 | } 31 | if defined?(JSON) 32 | x.report { 33 | puts "JSON.parse" 34 | times.times { 35 | json.rewind 36 | while chunk = json.gets 37 | JSON.parse(chunk, :max_nesting => false) 38 | end 39 | } 40 | } 41 | end 42 | if defined?(ActiveSupport::JSON) 43 | x.report { 44 | puts "ActiveSupport::JSON.decode" 45 | times.times { 46 | json.rewind 47 | while chunk = json.gets 48 | ActiveSupport::JSON.decode(chunk) 49 | end 50 | } 51 | } 52 | end 53 | } 54 | json.close -------------------------------------------------------------------------------- /benchmark/subjects/item.json: -------------------------------------------------------------------------------- 1 | {"item": {"name": "generated", "cached_tag_list": "", "updated_at": "2009-03-24T05:25:09Z", "updated_by_id": null, "price": 1.99, "delta": false, "cost": 0.597, "account_id": 16, "unit": null, "import_tag": null, "taxable": true, "id": 1, "created_by_id": null, "description": null, "company_id": 0, "sku": "06317-0306", "created_at": "2009-03-24T05:25:09Z", "active": true}} -------------------------------------------------------------------------------- /benchmark/subjects/ohai.marshal_dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianmario/yajl-ruby/63760720e58d8cb818d59ae6c4f3d96760cd7854/benchmark/subjects/ohai.marshal_dump -------------------------------------------------------------------------------- /benchmark/subjects/twitter_search.json: -------------------------------------------------------------------------------- 1 | {"results":[{"text":"RT @tmornini: Engine Yard Express = perfect way to test merb or rails deployment - http:\/\/express.engineyard.com\/","to_user_id":null,"from_user":"seanhealy","id":1429979943,"from_user_id":4485910,"iso_language_code":"en","source":"<a href="http:\/\/iconfactory.com\/software\/twitterrific">twitterrific<\/a>","profile_image_url":"https:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/62254150\/irish_noir_normal.jpg","created_at":"Wed, 01 Apr 2009 07:06:16 +0000"},{"text":"RT: Engine Yard Express = perfect way to test merb or rails deployment - http:\/\/express.engineyard.com\/ (via @digsby)","to_user_id":null,"from_user":"tmornini","id":1429966620,"from_user_id":168963,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/49018042\/Tom_Icon_64x64_normal.png","created_at":"Wed, 01 Apr 2009 07:02:00 +0000"},{"text":"Engine Yard Express = perfect way to test merb or rails deployment - http:\/\/express.engineyard.com\/","to_user_id":null,"from_user":"richardholland","id":1428644441,"from_user_id":1608628,"iso_language_code":"en","source":"<a href="http:\/\/www.digsby.com\/">digsby<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/63723025\/mesarah_normal.jpg","created_at":"Wed, 01 Apr 2009 02:07:30 +0000"},{"text":"RT @wycats: How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic.com\/2nl7x","to_user_id":null,"from_user":"AmandaMorin","id":1427373261,"from_user_id":1756964,"iso_language_code":"en","source":"<a href="http:\/\/www.tweetdeck.com\/">TweetDeck<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/67971839\/avatar_normal.jpg","created_at":"Tue, 31 Mar 2009 22:19:29 +0000"},{"text":"engineyard added jarnold to mongrel: \n\n \n \n \n mongrel is at engineyard\/mongrel http:\/\/tinyurl.com\/dm7ldz","to_user_id":null,"from_user":"_snax","id":1427357028,"from_user_id":118386,"iso_language_code":"en","source":"<a href="http:\/\/twitterfeed.com">twitterfeed<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/19934062\/logo_large_normal.gif","created_at":"Tue, 31 Mar 2009 22:16:38 +0000"},{"text":"RT: LOL! RT @wycats:How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic... http:\/\/tinyurl.com\/cgs2hj","to_user_id":null,"from_user":"howtotweets","id":1427228937,"from_user_id":3437258,"iso_language_code":"en","source":"<a href="http:\/\/twitterfeed.com">twitterfeed<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/81039760\/images_normal.jpg","created_at":"Tue, 31 Mar 2009 21:54:32 +0000"},{"text":"LOL! RT @wycats:How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic.com\/2nl7x","to_user_id":null,"from_user":"tsykoduk","id":1427225099,"from_user_id":71236,"iso_language_code":"en","source":"<a href="http:\/\/www.nambu.com">Nambu<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/63278451\/Photo_33_normal.jpg","created_at":"Tue, 31 Mar 2009 21:53:52 +0000"},{"text":"RT @wycats: How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic.com\/2nl7x","to_user_id":null,"from_user":"bratta","id":1427177698,"from_user_id":8376,"iso_language_code":"en","source":"<a href="http:\/\/thecosmicmachine.com\/eventbox\/">EventBox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/80333638\/photo_normal.jpg","created_at":"Tue, 31 Mar 2009 21:45:46 +0000"},{"text":"additional infos on the engineyard outage: http:\/\/tinyurl.com\/cbhbkn","to_user_id":null,"from_user":"aentos","id":1427149457,"from_user_id":6459508,"iso_language_code":"en","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/66789130\/aentos_a_normal.png","created_at":"Tue, 31 Mar 2009 21:40:47 +0000"},{"text":"http:\/\/twitpic.com\/2nl9z - Surviving monster attacks. A PSA from your friends @engineyard","to_user_id":null,"from_user":"carllerche","id":1427108503,"from_user_id":880629,"iso_language_code":"en","source":"<a href="http:\/\/twitpic.com\/">TwitPic<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/56520194\/fry_coffee2_normal.jpg","created_at":"Tue, 31 Mar 2009 21:33:38 +0000"},{"text":"How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic.com\/2nl7x","to_user_id":null,"from_user":"wycats","id":1427099726,"from_user_id":18414,"iso_language_code":"en","source":"<a href="http:\/\/twitterfon.net\/">TwitterFon<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/51747258\/Yehuda_-_Looking_at_Sky_normal.jpg","created_at":"Tue, 31 Mar 2009 21:32:07 +0000"},{"text":"RT @engineyard: Our CEO posted an update on yesterday's outage: http:\/\/bit.ly\/yA4p5 Good job keeping people in the loop!","to_user_id":null,"from_user":"fatnutz","id":1426857591,"from_user_id":706358,"iso_language_code":"en","source":"<a href="http:\/\/www.tweetdeck.com\/">TweetDeck<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/55573179\/snipe_normal.jpg","created_at":"Tue, 31 Mar 2009 20:50:21 +0000"},{"text":"loving our @entryway @engineyard solo instance, we built an integrity server in mins flat with @atmos lovely chef scripts: http:\/\/is.gd\/pVXw","to_user_id":null,"from_user":"gustin","id":1426653742,"from_user_id":3736601,"iso_language_code":"en","source":"<a href="http:\/\/83degrees.com\/to\/powertwitter">Power Twitter<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/116498033\/face_normal.png","created_at":"Tue, 31 Mar 2009 20:16:36 +0000"},{"text":"RT: Our CEO posted an update on yesterday's outage: http:\/\/bit.ly\/yA4p5 (via @engineyard)","to_user_id":null,"from_user":"tmornini","id":1426483075,"from_user_id":168963,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/49018042\/Tom_Icon_64x64_normal.png","created_at":"Tue, 31 Mar 2009 19:47:00 +0000"},{"text":"#engineyard #github very impressive - both the reason and the response - I must have missed the blog sorry","to_user_id":null,"from_user":"rickwindham","id":1426328592,"from_user_id":1819414,"iso_language_code":"en","source":"<a href="http:\/\/www.tweetdeck.com\/">TweetDeck<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/73617189\/me_new_normal.jpg","created_at":"Tue, 31 Mar 2009 19:16:30 +0000"}],"since_id":1386843259,"max_id":1429979943,"refresh_url":"?since_id=1429979943&q=engineyard","results_per_page":15,"next_page":"?page=2&max_id=1429979943&since_id=1386843259&q=engineyard","warning":"adjusted since_id, it was older than allowed","completed_in":0.037275,"page":1,"query":"engineyard"} -------------------------------------------------------------------------------- /benchmark/subjects/unicode.json: -------------------------------------------------------------------------------- 1 | {"results":[{"text":"#ruby \u732e\u672c\u30ad\u30bf\u30fc\u30fc\u30fc\u30fc\u30fc\u30fc\uff08\u309c\u2200\u309c\uff09\u30fc\u30fc\u30fc\u30fc\u30fc\u30fc\uff01\uff01 http:\/\/www.amazon.co.jp\/gp\/product\/4863540221","to_user_id":null,"from_user":"rubikitch","id":1843394737,"from_user_id":847295,"iso_language_code":"ja","source":"<a href="http:\/\/www.misuzilla.org\/dist\/net\/twitterircgateway\/">TwitterIrcGateway<\/a>","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Tue, 19 May 2009 03:12:47 +0000"},{"text":"Ruby on Rails\u3068CakePHP\u3001\u3069\u3063\u3061\u3067\u88fd\u9020\u3057\u3088\u3046\u304b\u3057\u3089","to_user_id":null,"from_user":"takkada","id":1842694220,"from_user_id":412519,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/16301882\/62305_4124481745_normal.jpg","created_at":"Tue, 19 May 2009 02:00:08 +0000"},{"text":"Ruby on Rails \u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u306f\u30fc\u3058\u307e\u30fc\u308b\u3088\u30fc","to_user_id":null,"from_user":"Tomohiro","id":1842375120,"from_user_id":38704,"iso_language_code":"ja","source":"<a href="http:\/\/www.misuzilla.org\/dist\/net\/twitterircgateway\/">TwitterIrcGateway<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/20970892\/578576_3772887925_normal.jpg","created_at":"Tue, 19 May 2009 01:27:18 +0000"},{"text":"ruby winole.rb\u3067\u547c\u3073\u51fa\u3057\u305f\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u30e1\u30e2\u30ea\u304c\u9069\u5207\u306b\u958b\u653e\u3055\u308c\u3066\u306a\u304b\u3063\u305f\u3002","to_user_id":null,"from_user":"tomofusa","id":1841955169,"from_user_id":35354,"iso_language_code":"ja","source":"<a href="http:\/\/cheebow.info\/chemt\/archives\/2007\/04\/twitterwindowst.html">Twit<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/18213412\/fusa2.0_about53_normal.png","created_at":"Tue, 19 May 2009 00:43:20 +0000"},{"text":"Ruby HTTP\u4e26\u5217\u3092\u51e6\u7406\u3092\u9ad8\u901f\u5316\u3001"Typhoeus"\u767b\u5834 | \u30a8\u30f3\u30bf\u30fc\u30d7\u30e9\u30a4\u30ba | \u30de\u30a4\u30b3\u30df\u30b8\u30e3\u30fc\u30ca\u30eb http:\/\/ff.im\/-31cez","to_user_id":null,"from_user":"MyGReaderFeed","id":1841206557,"from_user_id":11923042,"iso_language_code":"ja","source":"<a href="http:\/\/friendfeed.com\/">FriendFeed<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/141487706\/3379573163_e79dab7511_normal.bmp","created_at":"Mon, 18 May 2009 23:22:26 +0000"},{"text":"\u3044\u305a\u308c\u306b\u3057\u3066\u3082\u3069\u3053\u304b\u306b Ruby 1.9.1 \u74b0\u5883\u306f\u4f5c\u3089\u306a\u3044\u3068\u30c0\u30e1\u304b\u306a\u3041\u3002Debian lenny \u4efb\u305b\u3060\u3068 1.9.0 \u3057\u304b\u8a66\u305b\u306a\u3044\u3063\u307d\u3044\u3057\u3002","to_user_id":null,"from_user":"wtnabe","id":1840166013,"from_user_id":32040,"iso_language_code":"ja","source":"<a href="http:\/\/www.misuzilla.org\/dist\/net\/twitterircgateway\/">TwitterIrcGateway<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/59828670\/200805-wtnabe-film_normal.png","created_at":"Mon, 18 May 2009 21:26:17 +0000"},{"text":"Ruby 1.9 \u3067\u306f URI#decode \u3060\u3051\u3058\u3083\u610f\u5473\u304c\u306a\u3044\u306e\u304b\u306a\uff1f \u3053\u306e\u8fba\u304b\u3089\u5206\u304b\u3089\u306a\u304f\u306a\u3063\u3066\u304f\u308b\u306a\u3002","to_user_id":null,"from_user":"wtnabe","id":1839967007,"from_user_id":32040,"iso_language_code":"ja","source":"<a href="http:\/\/www.misuzilla.org\/dist\/net\/twitterircgateway\/">TwitterIrcGateway<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/59828670\/200805-wtnabe-film_normal.png","created_at":"Mon, 18 May 2009 21:06:06 +0000"},{"text":"Star Ruby \u3067\u30d5\u30ec\u30fc\u30e0\u30b9\u30ad\u30c3\u30d7\u304c\u5b9f\u88c5\u3057\u306b\u304f\u3044\u7406\u7531\u306e\u3072\u3068\u3064\u306b\u3001\u30b9\u30af\u30ea\u30fc\u30f3\u3078\u306e\u63cf\u753b\u304c\u9045\u5ef6\u3067\u304d\u306a\u3044\u3068\u3044\u3046\u306e\u304c\u3042\u308b\u3002 Texture#[] \u306a\u3069\u3067\u30d4\u30af\u30bb\u30eb\u306e\u5024\u3092\u8aad\u307f\u53d6\u3089\u308c\u308b\u53ef\u80fd\u6027\u304c\u3042\u308b\u305f\u3081\u3002\u8aad\u307f\u53d6\u3089\u308c\u308b\u30ae\u30ea\u30ae\u30ea\u307e\u3067\u9045\u5ef6\u3059\u308b\u306e\u3082\u30a2\u30ea\u3060\u304c\u3001\u5b9f\u88c5\u306f\u9762\u5012\u3067\u3042\u308b\u3002","to_user_id":null,"from_user":"hajimehoshi","id":1837784833,"from_user_id":7543,"iso_language_code":"ja","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/14446892\/michael_normal.jpg","created_at":"Mon, 18 May 2009 17:21:16 +0000"},{"text":"ruby-gem\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u3066\u3001rails\u306b\u30c1\u30e3\u30ec\u30f3\u30b8","to_user_id":null,"from_user":"tom_a","id":1837459653,"from_user_id":366098,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/16661182\/DSC02701_normal.jpg","created_at":"Mon, 18 May 2009 16:46:36 +0000"},{"text":"@saronpasu \u4e2d\u8eab\u306b\u30a2\u30af\u30bb\u30b9\u3057\u306b\u304f\u3044\u3057\u3001\u4f55\u3088\u308a\u4e0d\u5b89\u5b9a\u3059\u304e\u3067\u3059\u306d\u2026\u4f8b\u5916\u3063\u3066\u30ec\u30d9\u30eb\u3058\u3083\u306a\u304f\u3066 ruby \u5dfb\u304d\u8fbc\u3093\u3067\u843d\u3061\u308b\u306e\u3067\u2026","to_user_id":28082,"to_user":"saronpasu","from_user":"negaton","id":1836710607,"from_user_id":5893,"iso_language_code":"ja","source":"<a href="http:\/\/cheebow.info\/chemt\/archives\/2007\/04\/twitterwindowst.html">Twit<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/35934732\/DSC00338_icon_normal.jpg","created_at":"Mon, 18 May 2009 15:28:25 +0000"},{"text":"\u6628\u65e5 CaboCha-Ruby \u306e token \u306e surface \u3092\u53e9\u3044\u305f\u3089\u843d\u3061\u305f\u306e\u306b\u4eca\u65e5\u306f\u5168\u304f\u540c\u3058\u30b3\u30fc\u30c9\u52d5\u304b\u3057\u3066\u3066\u843d\u3061\u306a\u3044\u3068\u304b\u306a\u3093\u306a\u306e\u2026","to_user_id":null,"from_user":"negaton","id":1836267822,"from_user_id":5893,"iso_language_code":"ja","source":"<a href="http:\/\/cheebow.info\/chemt\/archives\/2007\/04\/twitterwindowst.html">Twit<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/35934732\/DSC00338_icon_normal.jpg","created_at":"Mon, 18 May 2009 14:41:26 +0000"},{"text":"ruby.snippets \u3092\u773a\u3081\u3066\u307f\u3066\u3001\u3053\u308c\u306f\u81ea\u5206\u304c\u4f7f\u3044\u3053\u306a\u305b\u308b\u3082\u306e\u3067\u306f\u306a\u3044\u3068\u308f\u304b\u3063\u305f","to_user_id":null,"from_user":"ursm","id":1835699306,"from_user_id":41919,"iso_language_code":"ja","source":"<a href="http:\/\/www.nambu.com">Nambu<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/28792412\/1153147983506_normal.jpg","created_at":"Mon, 18 May 2009 13:33:59 +0000"},{"text":"\u3068\u3053\u308d\u3067\u3001PHP \u304b\u3089\u306f Ruby \u3063\u3066\u547c\u3079\u308b\u306e\uff1f","to_user_id":null,"from_user":"nov","id":1835354604,"from_user_id":76705,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfon.net\/">TwitterFon<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/60572614\/nov_normal.gif","created_at":"Mon, 18 May 2009 12:47:52 +0000"},{"text":"\u3067\u304d\u3042\u304c\u3063\u305f\u3053\u308d shindig ruby ver. \u51fa\u3066\u305f\u308a\u3057\u305f\u3089\u6ce3\u304f\u3002","to_user_id":null,"from_user":"nov","id":1835155373,"from_user_id":76705,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfon.net\/">TwitterFon<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/60572614\/nov_normal.gif","created_at":"Mon, 18 May 2009 12:17:17 +0000"},{"text":"@papiron ruby-dev\u3067ruby1.9\u306bsqlite\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u6a19\u6e96\u6dfb\u4ed8\u3057\u3088\u3046\u3068\u3044\u3046\u8b70\u8ad6\u304c\u3055\u308c\u3066\u307e\u3059\u3002http:\/\/bit.ly\/Limi9","to_user_id":10226526,"to_user":"papiron","from_user":"taigou","id":1834625775,"from_user_id":3915244,"iso_language_code":"ja","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/95583044\/me_normal.png","created_at":"Mon, 18 May 2009 10:38:40 +0000"}],"since_id":1769782474,"max_id":1843394737,"refresh_url":"?since_id=1843394737&q=ruby","results_per_page":15,"next_page":"?page=2&max_id=1843394737&lang=ja&q=ruby","warning":"adjusted since_id, it was older than allowedsince_id removed for pagination.","completed_in":0.052502,"page":1,"query":"ruby"} -------------------------------------------------------------------------------- /examples/encoding/chunked_encoding.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib') 3 | 4 | require 'yajl' 5 | 6 | obj = { 7 | :a_test => "of encoding in one pass" * 512, 8 | :a_test2 => "of encoding in one pass" * 512, 9 | :a_test3 => "of encoding in one pass" * 512, 10 | :a_test4 => "of encoding in one pass" * 512, 11 | :which_will => "simply return a string when finished" * 512, 12 | :which_will2 => "simply return a string when finished" * 512, 13 | :which_will3 => "simply return a string when finished" * 512, 14 | :which_will4 => "simply return a string when finished" * 512, 15 | :as_easy_as => 123 16 | } 17 | 18 | chunks = 0 19 | total_size = 0 20 | 21 | Yajl::Encoder.encode(obj) do |chunk| 22 | chunks += 1 23 | total_size += chunk.size 24 | STDOUT << chunk 25 | end 26 | 27 | puts "\n\nEncoder generated #{total_size} bytes of data, in #{chunks} chunks" 28 | -------------------------------------------------------------------------------- /examples/encoding/one_shot.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib') 3 | 4 | require 'yajl' 5 | 6 | obj = { 7 | :a_test => "of encoding in one pass", 8 | :which_will => "simply return a string when finished", 9 | :as_easy_as => 123 10 | } 11 | 12 | str = Yajl::Encoder.encode(obj) 13 | puts str 14 | -------------------------------------------------------------------------------- /examples/encoding/to_an_io.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib') 3 | 4 | require 'yajl' 5 | 6 | obj = { 7 | :a_test => "of encoding directly to an IO stream", 8 | :which_will => "simply return a string when finished", 9 | :as_easy_as => 123 10 | } 11 | 12 | Yajl::Encoder.encode(obj, STDOUT) 13 | -------------------------------------------------------------------------------- /examples/http/twitter_search_api.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib') 3 | 4 | require 'yajl/http_stream' 5 | require 'uri' 6 | 7 | unless keywords = ARGV[0] 8 | puts "\nUsage: ruby examples/http/twitter_search_api.rb keyword\n\n" 9 | exit(0) 10 | end 11 | 12 | puts Yajl::HttpStream.get("http://search.twitter.com/search.json?q=#{keywords}").inspect 13 | -------------------------------------------------------------------------------- /examples/http/twitter_stream_api.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib') 3 | 4 | require 'yajl/gzip' 5 | require 'yajl/deflate' 6 | require 'yajl/http_stream' 7 | require 'uri' 8 | 9 | unless (username = ARGV[0]) && (password = ARGV[1]) 10 | puts "\nUsage: ruby examples/http/twitter_stream_api.rb username password\n\n" 11 | exit(0) 12 | end 13 | captured = 0 14 | uri = URI.parse("http://#{username}:#{password}@stream.twitter.com/1/statuses/sample.json") 15 | 16 | trap('INT') { 17 | puts "\n\nCaptured #{captured} objects from the stream" 18 | puts "CTRL+C caught, later!" 19 | exit(0) 20 | } 21 | 22 | Yajl::HttpStream.get(uri, :symbolize_keys => true) do |hash| 23 | STDOUT.putc '.' 24 | STDOUT.flush 25 | captured += 1 26 | end 27 | -------------------------------------------------------------------------------- /examples/parsing/from_file.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib') 3 | 4 | require 'yajl' 5 | 6 | unless file = ARGV[0] 7 | puts "\nUsage: ruby examples/from_file.rb benchmark/subjects/item.json\n\n" 8 | exit(0) 9 | end 10 | 11 | json = File.new(file, 'r') 12 | 13 | hash = Yajl::Parser.parse(json) 14 | puts hash.inspect 15 | -------------------------------------------------------------------------------- /examples/parsing/from_stdin.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib') 3 | 4 | require 'yajl' 5 | 6 | # Usage: cat benchmark/subjects/item.json | ruby examples/from_stdin.rb 7 | 8 | hash = Yajl::Parser.parse(STDIN) 9 | puts hash.inspect 10 | -------------------------------------------------------------------------------- /examples/parsing/from_string.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../..') 2 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib') 3 | 4 | require 'yajl' 5 | require 'stringio' 6 | 7 | unless string = ARGV[0] 8 | puts "\nUsage: ruby examples/from_string.rb '{\"foo\": 1145}'\n\n" 9 | exit(0) 10 | end 11 | 12 | hash = Yajl::Parser.parse(string) 13 | puts hash.inspect 14 | -------------------------------------------------------------------------------- /ext/yajl/api/yajl_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __YAJL_COMMON_H__ 34 | #define __YAJL_COMMON_H__ 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | #define YAJL_MAX_DEPTH 256 41 | 42 | /* msft dll export gunk. To build a DLL on windows, you 43 | * must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared 44 | * DLL, you must define YAJL_SHARED and WIN32 */ 45 | #if defined(WIN32) && defined(YAJL_SHARED) 46 | # ifdef YAJL_BUILD 47 | # define YAJL_API __declspec(dllexport) 48 | # else 49 | # define YAJL_API __declspec(dllimport) 50 | # endif 51 | #else 52 | # if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303 53 | # define YAJL_API __attribute__ ((visibility("hidden"))) 54 | # else 55 | # define YAJL_API 56 | # endif 57 | #endif 58 | 59 | #if defined(__GNUC__) 60 | #define YAJL_WARN_UNUSED __attribute__ ((warn_unused_result)) 61 | #else 62 | #define YAJL_WARN_UNUSED 63 | #endif 64 | 65 | /** pointer to a malloc function, supporting client overriding memory 66 | * allocation routines */ 67 | typedef void * (*yajl_malloc_func)(void *ctx, unsigned int sz); 68 | 69 | /** pointer to a free function, supporting client overriding memory 70 | * allocation routines */ 71 | typedef void (*yajl_free_func)(void *ctx, void * ptr); 72 | 73 | /** pointer to a realloc function which can resize an allocation. */ 74 | typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, unsigned int sz); 75 | 76 | /** A structure which can be passed to yajl_*_alloc routines to allow the 77 | * client to specify memory allocation functions to be used. */ 78 | typedef struct 79 | { 80 | /** pointer to a function that can allocate uninitialized memory */ 81 | yajl_malloc_func malloc; 82 | /** pointer to a function that can resize memory allocations */ 83 | yajl_realloc_func realloc; 84 | /** pointer to a function that can free memory allocated using 85 | * reallocFunction or mallocFunction */ 86 | yajl_free_func free; 87 | /** a context pointer that will be passed to above allocation routines */ 88 | void * ctx; 89 | } yajl_alloc_funcs; 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /ext/yajl/api/yajl_gen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /** 34 | * \file yajl_gen.h 35 | * Interface to YAJL's JSON generation facilities. 36 | */ 37 | 38 | #include "api/yajl_common.h" 39 | 40 | #ifndef __YAJL_GEN_H__ 41 | #define __YAJL_GEN_H__ 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | /** generator status codes */ 47 | typedef enum { 48 | /** no error */ 49 | yajl_gen_status_ok = 0, 50 | /** at a point where a map key is generated, a function other than 51 | * yajl_gen_string was called */ 52 | yajl_gen_keys_must_be_strings, 53 | /** YAJL's maximum generation depth was exceeded. see 54 | * YAJL_MAX_DEPTH */ 55 | yajl_max_depth_exceeded, 56 | /** A generator function (yajl_gen_XXX) was called while in an error 57 | * state */ 58 | yajl_gen_in_error_state, 59 | /** A complete JSON document has been generated */ 60 | yajl_gen_generation_complete, 61 | /** yajl_gen_double was passed an invalid floating point value 62 | * (infinity or NaN). */ 63 | yajl_gen_invalid_number, 64 | /** A print callback was passed in, so there is no internal 65 | * buffer to get from */ 66 | yajl_gen_no_buf, 67 | /** Tried to decrement at depth 0 */ 68 | yajl_depth_underflow, 69 | /** Allocation error */ 70 | yajl_gen_alloc_error 71 | } yajl_gen_status; 72 | 73 | /** an opaque handle to a generator */ 74 | typedef struct yajl_gen_t * yajl_gen; 75 | 76 | /** a callback used for "printing" the results. */ 77 | typedef void (*yajl_print_t)(void * ctx, 78 | const char * str, 79 | unsigned int len); 80 | 81 | /** configuration structure for the generator */ 82 | typedef struct { 83 | /** generate indented (beautiful) output */ 84 | unsigned int beautify; 85 | /** an opportunity to define an indent string. such as \\t or 86 | * some number of spaces. default is four spaces ' '. This 87 | * member is only relevant when beautify is true */ 88 | const char * indentString; 89 | /** escape the '/' character */ 90 | unsigned int htmlSafe; 91 | } yajl_gen_config; 92 | 93 | /** allocate a generator handle 94 | * \param config a pointer to a structure containing parameters which 95 | * configure the behavior of the json generator 96 | * \param allocFuncs an optional pointer to a structure which allows 97 | * the client to overide the memory allocation 98 | * used by yajl. May be NULL, in which case 99 | * malloc/free/realloc will be used. 100 | * 101 | * \returns an allocated handle on success, NULL on failure (bad params) 102 | */ 103 | YAJL_API yajl_gen yajl_gen_alloc(const yajl_gen_config * config, 104 | const yajl_alloc_funcs * allocFuncs); 105 | 106 | /** allocate a generator handle that will print to the specified 107 | * callback rather than storing the results in an internal buffer. 108 | * \param callback a pointer to a printer function. May be NULL 109 | * in which case, the results will be store in an 110 | * internal buffer. 111 | * \param config a pointer to a structure containing parameters 112 | * which configure the behavior of the json 113 | * generator. 114 | * \param allocFuncs an optional pointer to a structure which allows 115 | * the client to overide the memory allocation 116 | * used by yajl. May be NULL, in which case 117 | * malloc/free/realloc will be used. 118 | * \param ctx a context pointer that will be passed to the 119 | * printer callback. 120 | * 121 | * \returns an allocated handle on success, NULL on failure (bad params) 122 | */ 123 | YAJL_API yajl_gen yajl_gen_alloc2(const yajl_print_t callback, 124 | const yajl_gen_config * config, 125 | const yajl_alloc_funcs * allocFuncs, 126 | void * ctx); 127 | 128 | /** free a generator handle */ 129 | YAJL_API void yajl_gen_free(yajl_gen handle); 130 | 131 | YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long int number); 132 | /** generate a floating point number. number may not be infinity or 133 | * NaN, as these have no representation in JSON. In these cases the 134 | * generator will return 'yajl_gen_invalid_number' */ 135 | YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number); 136 | YAJL_API yajl_gen_status yajl_gen_long(yajl_gen hand, long value); 137 | YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand, 138 | const char * num, 139 | unsigned int len); 140 | YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand, 141 | const unsigned char * str, 142 | unsigned int len); 143 | YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand); 144 | YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean); 145 | YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand); 146 | YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand); 147 | YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand); 148 | YAJL_API yajl_gen_status yajl_gen_array_close(yajl_gen hand); 149 | 150 | /** access the null terminated generator buffer. If incrementally 151 | * outputing JSON, one should call yajl_gen_clear to clear the 152 | * buffer. This allows stream generation. */ 153 | YAJL_API YAJL_WARN_UNUSED yajl_gen_status yajl_gen_get_buf(yajl_gen hand, 154 | const unsigned char ** buf, 155 | unsigned int * len); 156 | 157 | /** clear yajl's output buffer, but maintain all internal generation 158 | * state. This function will not "reset" the generator state, and is 159 | * intended to enable incremental JSON outputing. */ 160 | YAJL_API void yajl_gen_clear(yajl_gen hand); 161 | 162 | #ifdef __cplusplus 163 | } 164 | #endif 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /ext/yajl/api/yajl_version.h: -------------------------------------------------------------------------------- 1 | #ifndef YAJL_VERSION_H_ 2 | #define YAJL_VERSION_H_ 3 | 4 | #include "api/yajl_common.h" 5 | 6 | #define YAJL_MAJOR 1 7 | #define YAJL_MINOR 0 8 | #define YAJL_MICRO 12 9 | 10 | #define YAJL_VERSION ((YAJL_MAJOR * 10000) + (YAJL_MINOR * 100) + YAJL_MICRO) 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | extern int YAJL_API yajl_version(void); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif /* YAJL_VERSION_H_ */ 23 | 24 | -------------------------------------------------------------------------------- /ext/yajl/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | require 'rbconfig' 3 | 4 | $CFLAGS << ' -Wall -funroll-loops -Wno-declaration-after-statement' 5 | $CFLAGS << ' -Werror-implicit-function-declaration -Wextra -O0 -ggdb3' if ENV['DEBUG'] 6 | 7 | if ENV['SANITIZE'] 8 | $CFLAGS << ' -fsanitize=address' 9 | $LDFLAGS << ' -fsanitize=address' 10 | end 11 | 12 | create_makefile('yajl/yajl') 13 | -------------------------------------------------------------------------------- /ext/yajl/yajl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include "api/yajl_parse.h" 34 | #include "yajl_lex.h" 35 | #include "yajl_parser.h" 36 | #include "yajl_alloc.h" 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | const char * 43 | yajl_status_to_string(yajl_status stat) 44 | { 45 | const char * statStr = "unknown"; 46 | switch (stat) { 47 | case yajl_status_ok: 48 | statStr = "ok, no error"; 49 | break; 50 | case yajl_status_client_canceled: 51 | statStr = "client canceled parse"; 52 | break; 53 | case yajl_status_insufficient_data: 54 | statStr = "eof was met before the parse could complete"; 55 | break; 56 | case yajl_status_error: 57 | statStr = "parse error"; 58 | break; 59 | case yajl_status_alloc_failed: 60 | statStr = "allocation failed"; 61 | break; 62 | } 63 | return statStr; 64 | } 65 | 66 | yajl_handle 67 | yajl_alloc(const yajl_callbacks * callbacks, 68 | const yajl_parser_config * config, 69 | const yajl_alloc_funcs * afs, 70 | void * ctx) 71 | { 72 | unsigned int allowComments = 0; 73 | unsigned int validateUTF8 = 0; 74 | yajl_handle hand = NULL; 75 | yajl_alloc_funcs afsBuffer; 76 | 77 | /* first order of business is to set up memory allocation routines */ 78 | if (afs != NULL) { 79 | if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) 80 | { 81 | return NULL; 82 | } 83 | } else { 84 | yajl_set_default_alloc_funcs(&afsBuffer); 85 | afs = &afsBuffer; 86 | } 87 | 88 | hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t)); 89 | if (hand == NULL) 90 | return NULL; 91 | 92 | /* copy in pointers to allocation routines */ 93 | memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); 94 | 95 | if (config != NULL) { 96 | allowComments = config->allowComments; 97 | validateUTF8 = config->checkUTF8; 98 | } 99 | 100 | hand->callbacks = callbacks; 101 | hand->ctx = ctx; 102 | hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8); 103 | if (!hand->lexer) { 104 | YA_FREE(afs, hand); 105 | return NULL; 106 | } 107 | hand->bytesConsumed = 0; 108 | hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); 109 | yajl_bs_init(hand->stateStack, &(hand->alloc)); 110 | 111 | if (yajl_bs_push(hand->stateStack, yajl_state_start)) { 112 | return NULL; 113 | } 114 | 115 | return hand; 116 | } 117 | 118 | void 119 | yajl_reset_parser(yajl_handle hand) { 120 | assert(hand); 121 | hand->lexer = yajl_lex_realloc(hand->lexer); 122 | } 123 | 124 | void 125 | yajl_free(yajl_handle handle) 126 | { 127 | assert(handle); 128 | yajl_bs_free(handle->stateStack); 129 | yajl_buf_free(handle->decodeBuf); 130 | yajl_lex_free(handle->lexer); 131 | YA_FREE(&(handle->alloc), handle); 132 | } 133 | 134 | yajl_status 135 | yajl_parse(yajl_handle hand, const unsigned char * jsonText, 136 | unsigned int jsonTextLen) 137 | { 138 | assert(hand); 139 | yajl_status status; 140 | status = yajl_do_parse(hand, jsonText, jsonTextLen); 141 | return status; 142 | } 143 | 144 | yajl_status 145 | yajl_parse_complete(yajl_handle hand) 146 | { 147 | assert(hand); 148 | /* The particular case we want to handle is a trailing number. 149 | * Further input consisting of digits could cause our interpretation 150 | * of the number to change (buffered "1" but "2" comes in). 151 | * A very simple approach to this is to inject whitespace to terminate 152 | * any number in the lex buffer. 153 | */ 154 | return yajl_parse(hand, (const unsigned char *)" ", 1); 155 | } 156 | 157 | unsigned char * 158 | yajl_get_error(yajl_handle hand, int verbose, 159 | const unsigned char * jsonText, unsigned int jsonTextLen) 160 | { 161 | assert(hand); 162 | return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose); 163 | } 164 | 165 | unsigned int 166 | yajl_get_bytes_consumed(yajl_handle hand) 167 | { 168 | if (!hand) return 0; 169 | else return hand->bytesConsumed; 170 | } 171 | 172 | 173 | void 174 | yajl_free_error(yajl_handle hand, unsigned char * str) 175 | { 176 | /* use memory allocation functions if set */ 177 | YA_FREE(&(hand->alloc), str); 178 | } 179 | 180 | /* XXX: add utility routines to parse from file */ 181 | -------------------------------------------------------------------------------- /ext/yajl/yajl_alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /** 34 | * \file yajl_alloc.h 35 | * default memory allocation routines for yajl which use malloc/realloc and 36 | * free 37 | */ 38 | 39 | #include "yajl_alloc.h" 40 | #include 41 | 42 | static void * yajl_internal_malloc(void *ctx, unsigned int sz) 43 | { 44 | return malloc(sz); 45 | } 46 | 47 | static void * yajl_internal_realloc(void *ctx, void * previous, 48 | unsigned int sz) 49 | { 50 | return realloc(previous, sz); 51 | } 52 | 53 | static void yajl_internal_free(void *ctx, void * ptr) 54 | { 55 | free(ptr); 56 | } 57 | 58 | void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) 59 | { 60 | yaf->malloc = yajl_internal_malloc; 61 | yaf->free = yajl_internal_free; 62 | yaf->realloc = yajl_internal_realloc; 63 | yaf->ctx = NULL; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /ext/yajl/yajl_alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /** 34 | * \file yajl_alloc.h 35 | * default memory allocation routines for yajl which use malloc/realloc and 36 | * free 37 | */ 38 | 39 | #ifndef __YAJL_ALLOC_H__ 40 | #define __YAJL_ALLOC_H__ 41 | 42 | #include "api/yajl_common.h" 43 | 44 | #define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) 45 | #define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) 46 | #define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)) 47 | 48 | YAJL_API 49 | void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /ext/yajl/yajl_buf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include "yajl_buf.h" 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #define YAJL_BUF_INIT_SIZE 2048 41 | 42 | struct yajl_buf_t { 43 | yajl_buf_state state; 44 | unsigned int len; 45 | unsigned int used; 46 | unsigned char * data; 47 | yajl_alloc_funcs * alloc; 48 | }; 49 | 50 | static void *noop_realloc(void *ctx, void *ptr, unsigned int sz) { 51 | fprintf(stderr, "Attempt to allocate on invalid yajl_buf_t\n"); 52 | abort(); 53 | } 54 | static void *noop_malloc(void *ctx, unsigned int sz) { return noop_realloc(ctx, NULL, sz); } 55 | static void noop_free(void *ctx, void *ptr) { } 56 | 57 | static yajl_alloc_funcs noop_allocs = { 58 | .malloc = &noop_malloc, 59 | .realloc = &noop_realloc, 60 | .free = &noop_free, 61 | }; 62 | 63 | // A buffer to be returned if the initial allocation fails 64 | static struct yajl_buf_t buf_alloc_error = { 65 | .state = yajl_buf_alloc_failed, 66 | .alloc = &noop_allocs 67 | }; 68 | 69 | #include 70 | 71 | yajl_buf_state yajl_buf_err(yajl_buf buf) 72 | { 73 | assert(buf); 74 | return buf->state; 75 | } 76 | 77 | static 78 | yajl_buf_state yajl_buf_set_error(yajl_buf buf, yajl_buf_state err) 79 | { 80 | buf->state = err; 81 | 82 | // free and clear all data from the buffer 83 | YA_FREE(buf->alloc, buf->data); 84 | buf->len = 0; 85 | buf->data = 0; 86 | buf->used = 0; 87 | 88 | return err; 89 | } 90 | 91 | static 92 | yajl_buf_state yajl_buf_ensure_available(yajl_buf buf, unsigned int want) 93 | { 94 | unsigned int need; 95 | 96 | assert(buf != NULL); 97 | 98 | if (buf->state != yajl_buf_ok) { 99 | return buf->state; 100 | } 101 | 102 | /* first call */ 103 | if (buf->data == NULL) { 104 | buf->len = YAJL_BUF_INIT_SIZE; 105 | buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len); 106 | if (buf->data == NULL) { 107 | return yajl_buf_set_error(buf, yajl_buf_overflow); 108 | } 109 | 110 | buf->data[0] = 0; 111 | } 112 | 113 | if (want == 0) { 114 | return yajl_buf_ok; 115 | } 116 | 117 | need = buf->len; 118 | 119 | while (want >= (need - buf->used) && need > 0) need <<= 1; 120 | 121 | // Check for overflow 122 | if (need < buf->used || need == 0) { 123 | return yajl_buf_set_error(buf, yajl_buf_overflow); 124 | } 125 | 126 | if (need != buf->len) { 127 | buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need); 128 | 129 | if (buf->data == NULL) { 130 | return yajl_buf_set_error(buf, yajl_buf_overflow); 131 | } 132 | 133 | buf->len = need; 134 | } 135 | 136 | return yajl_buf_ok; 137 | } 138 | 139 | yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc) 140 | { 141 | yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t)); 142 | if (b == NULL) { 143 | return &buf_alloc_error; 144 | } 145 | 146 | memset((void *) b, 0, sizeof(struct yajl_buf_t)); 147 | b->alloc = alloc; 148 | return b; 149 | } 150 | 151 | void yajl_buf_free(yajl_buf buf) 152 | { 153 | assert(buf != NULL); 154 | if (buf->data) YA_FREE(buf->alloc, buf->data); 155 | YA_FREE(buf->alloc, buf); 156 | } 157 | 158 | void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len) 159 | { 160 | if (yajl_buf_ensure_available(buf, len)) { 161 | return; 162 | } 163 | if (len > 0) { 164 | assert(data != NULL); 165 | memcpy(buf->data + buf->used, data, len); 166 | buf->used += len; 167 | buf->data[buf->used] = 0; 168 | } 169 | } 170 | 171 | void yajl_buf_clear(yajl_buf buf) 172 | { 173 | assert(buf); 174 | assert(!yajl_buf_err(buf)); 175 | buf->used = 0; 176 | if (buf->data) buf->data[buf->used] = 0; 177 | } 178 | 179 | const unsigned char * yajl_buf_data(yajl_buf buf) 180 | { 181 | assert(buf); 182 | assert(!yajl_buf_err(buf)); 183 | return buf->data; 184 | } 185 | 186 | unsigned int yajl_buf_len(yajl_buf buf) 187 | { 188 | assert(buf); 189 | assert(!yajl_buf_err(buf)); 190 | return buf->used; 191 | } 192 | 193 | void 194 | yajl_buf_truncate(yajl_buf buf, unsigned int len) 195 | { 196 | assert(buf); 197 | assert(!yajl_buf_err(buf)); 198 | assert(len <= buf->used); 199 | buf->used = len; 200 | } 201 | -------------------------------------------------------------------------------- /ext/yajl/yajl_buf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __YAJL_BUF_H__ 34 | #define __YAJL_BUF_H__ 35 | 36 | #include "api/yajl_common.h" 37 | #include "yajl_alloc.h" 38 | 39 | /* 40 | * Implementation/performance notes. If this were moved to a header 41 | * only implementation using #define's where possible we might be 42 | * able to sqeeze a little performance out of the guy by killing function 43 | * call overhead. YMMV. 44 | */ 45 | 46 | typedef enum { 47 | yajl_buf_ok = 0, 48 | yajl_buf_alloc_failed, 49 | yajl_buf_overflow 50 | } yajl_buf_state; 51 | 52 | /** 53 | * yajl_buf is a buffer with exponential growth. the buffer ensures that 54 | * you are always null padded. 55 | */ 56 | typedef struct yajl_buf_t * yajl_buf; 57 | 58 | /* allocate a new buffer */ 59 | YAJL_API 60 | yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc); 61 | 62 | /* free the buffer */ 63 | YAJL_API 64 | void yajl_buf_free(yajl_buf buf); 65 | 66 | /* append a number of bytes to the buffer */ 67 | YAJL_API 68 | void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len); 69 | 70 | /* empty the buffer */ 71 | YAJL_API 72 | void yajl_buf_clear(yajl_buf buf); 73 | 74 | /* get a pointer to the beginning of the buffer */ 75 | YAJL_API 76 | const unsigned char * yajl_buf_data(yajl_buf buf); 77 | 78 | /* get the length of the buffer */ 79 | YAJL_API 80 | unsigned int yajl_buf_len(yajl_buf buf); 81 | 82 | /* truncate the buffer */ 83 | YAJL_API 84 | void yajl_buf_truncate(yajl_buf buf, unsigned int len); 85 | 86 | /* get the state of buffer */ 87 | yajl_buf_state yajl_buf_err(yajl_buf buf); 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /ext/yajl/yajl_bytestack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * A header only implementation of a simple stack of bytes, used in YAJL 35 | * to maintain parse state. 36 | */ 37 | 38 | #ifndef __YAJL_BYTESTACK_H__ 39 | #define __YAJL_BYTESTACK_H__ 40 | 41 | #include 42 | #include 43 | #include "api/yajl_common.h" 44 | 45 | #define YAJL_BS_INC 128 46 | #define YAJL_BS_MAX_SIZE UINT_MAX 47 | 48 | typedef struct yajl_bytestack_t 49 | { 50 | unsigned char * stack; 51 | unsigned int size; 52 | unsigned int used; 53 | yajl_alloc_funcs * yaf; 54 | } yajl_bytestack; 55 | 56 | /* initialize a bytestack */ 57 | #define yajl_bs_init(obs, _yaf) { \ 58 | (obs).stack = NULL; \ 59 | (obs).size = 0; \ 60 | (obs).used = 0; \ 61 | (obs).yaf = (_yaf); \ 62 | } \ 63 | 64 | 65 | /* initialize a bytestack */ 66 | #define yajl_bs_free(obs) \ 67 | if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack); 68 | 69 | #define yajl_bs_current(obs) \ 70 | (assert((obs).used > 0), (obs).stack[(obs).used - 1]) 71 | 72 | /* 0: success, 1: error */ 73 | static inline YAJL_WARN_UNUSED 74 | int yajl_bs_push_inline(yajl_bytestack *obs, unsigned char byte) { 75 | if ((obs->size - obs->used) == 0) { 76 | if (obs->size > YAJL_BS_MAX_SIZE - YAJL_BS_INC) 77 | return 1; 78 | obs->size += YAJL_BS_INC; 79 | obs->stack = obs->yaf->realloc(obs->yaf->ctx, (void *)obs->stack, obs->size); 80 | if (!obs->stack) 81 | return 1; 82 | } 83 | obs->stack[obs->used++] = byte; 84 | return 0; 85 | } 86 | 87 | #define yajl_bs_push(obs, byte) yajl_bs_push_inline(&(obs), (byte)) 88 | 89 | /* removes the top item of the stack, returns nothing */ 90 | #define yajl_bs_pop(obs) { ((obs).used)--; } 91 | 92 | static inline 93 | void 94 | yajl_bs_set_inline(yajl_bytestack *obs, unsigned char byte) { 95 | assert(obs->used > 0); 96 | assert(obs->size >= obs->used); 97 | obs->stack[obs->used - 1] = byte; 98 | } 99 | 100 | #define yajl_bs_set(obs, byte) yajl_bs_set_inline(&obs, byte) 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /ext/yajl/yajl_encode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include "yajl_encode.h" 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | static void CharToHex(unsigned char c, char * hexBuf) 41 | { 42 | const char * hexchar = "0123456789ABCDEF"; 43 | hexBuf[0] = hexchar[c >> 4]; 44 | hexBuf[1] = hexchar[c & 0x0F]; 45 | } 46 | 47 | void 48 | yajl_string_encode(yajl_buf buf, const unsigned char * str, 49 | unsigned int len, unsigned int htmlSafe) 50 | { 51 | yajl_string_encode2((const yajl_print_t) &yajl_buf_append, buf, str, len, htmlSafe); 52 | } 53 | 54 | void 55 | yajl_string_encode2(const yajl_print_t print, 56 | void * ctx, 57 | const unsigned char * str, 58 | unsigned int len, 59 | unsigned int htmlSafe) 60 | { 61 | unsigned int beg = 0; 62 | unsigned int end = 0; 63 | unsigned int increment = 0; 64 | char hexBuf[7]; 65 | char entityBuffer[7]; 66 | hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0'; 67 | hexBuf[6] = 0; 68 | 69 | entityBuffer[0] = '\\'; entityBuffer[1] = 'u'; entityBuffer[2] = '2'; entityBuffer[3] = '0'; 70 | entityBuffer[6] = 0; 71 | 72 | while (end < len) { 73 | increment = 1; 74 | const char * escaped = NULL; 75 | switch (str[end]) { 76 | case '\r': escaped = "\\r"; break; 77 | case '\n': escaped = "\\n"; break; 78 | case '\\': escaped = "\\\\"; break; 79 | /* case '/': escaped = "\\/"; break; */ 80 | case '"': escaped = "\\\""; break; 81 | case '\f': escaped = "\\f"; break; 82 | case '\b': escaped = "\\b"; break; 83 | case '\t': escaped = "\\t"; break; 84 | case '/': 85 | if (htmlSafe == 1 || htmlSafe == 2) { 86 | escaped = "\\/"; 87 | } 88 | break; 89 | /* Escaping 0xe280a8 0xe280a9 */ 90 | case 0xe2: 91 | if (htmlSafe == 2) { 92 | if (len - end >= 2 && str[end + 1] == 0x80) { 93 | if (str[end + 2] == 0xa8) { 94 | increment = 3; 95 | entityBuffer[4] = '2'; 96 | entityBuffer[5] = '8'; 97 | escaped = entityBuffer; 98 | break; 99 | } 100 | 101 | if (str[end + 2] == 0xa9) { 102 | increment = 3; 103 | entityBuffer[4] = '2'; 104 | entityBuffer[5] = '9'; 105 | escaped = entityBuffer; 106 | break; 107 | } 108 | } 109 | } 110 | case '<': 111 | case '>': 112 | case '&': 113 | if (htmlSafe == 2) { 114 | CharToHex(str[end], hexBuf + 4); 115 | escaped = hexBuf; 116 | } 117 | break; 118 | default: 119 | if ((unsigned char) str[end] < 32) { 120 | CharToHex(str[end], hexBuf + 4); 121 | escaped = hexBuf; 122 | } 123 | break; 124 | } 125 | if (escaped != NULL) { 126 | print(ctx, (const char *) (str + beg), end - beg); 127 | print(ctx, escaped, (unsigned int)strlen(escaped)); 128 | end += increment; 129 | beg = end; 130 | } else { 131 | ++end; 132 | } 133 | } 134 | print(ctx, (const char *) (str + beg), end - beg); 135 | } 136 | 137 | static void hexToDigit(unsigned int * val, const unsigned char * hex) 138 | { 139 | unsigned int i; 140 | for (i=0;i<4;i++) { 141 | unsigned char c = hex[i]; 142 | if (c >= 'A') c = (c & ~0x20) - 7; 143 | c -= '0'; 144 | assert(!(c & 0xF0)); 145 | *val = (*val << 4) | c; 146 | } 147 | } 148 | 149 | static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) 150 | { 151 | if (codepoint < 0x80) { 152 | utf8Buf[0] = (char) codepoint; 153 | utf8Buf[1] = 0; 154 | } else if (codepoint < 0x0800) { 155 | utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0); 156 | utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80); 157 | utf8Buf[2] = 0; 158 | } else if (codepoint < 0x10000) { 159 | utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0); 160 | utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80); 161 | utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80); 162 | utf8Buf[3] = 0; 163 | } else if (codepoint < 0x200000) { 164 | utf8Buf[0] =(char)((codepoint >> 18) | 0xF0); 165 | utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80); 166 | utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80); 167 | utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80); 168 | utf8Buf[4] = 0; 169 | } else { 170 | utf8Buf[0] = '?'; 171 | utf8Buf[1] = 0; 172 | } 173 | } 174 | 175 | void yajl_string_decode(yajl_buf buf, const unsigned char * str, 176 | unsigned int len) 177 | { 178 | unsigned int beg = 0; 179 | unsigned int end = 0; 180 | 181 | while (end < len) { 182 | if (str[end] == '\\') { 183 | char utf8Buf[5]; 184 | const char * unescaped = "?"; 185 | yajl_buf_append(buf, str + beg, end - beg); 186 | switch (str[++end]) { 187 | case 'r': unescaped = "\r"; break; 188 | case 'n': unescaped = "\n"; break; 189 | case '\\': unescaped = "\\"; break; 190 | case '/': unescaped = "/"; break; 191 | case '"': unescaped = "\""; break; 192 | case 'f': unescaped = "\f"; break; 193 | case 'b': unescaped = "\b"; break; 194 | case 't': unescaped = "\t"; break; 195 | case 'u': { 196 | unsigned int codepoint = 0; 197 | hexToDigit(&codepoint, str + ++end); 198 | end+=3; 199 | /* check if this is a surrogate */ 200 | if ((codepoint & 0xFC00) == 0xD800) { 201 | if (end + 2 < len && str[end + 1] == '\\' && str[end + 2] == 'u') { 202 | end++; 203 | unsigned int surrogate = 0; 204 | hexToDigit(&surrogate, str + end + 2); 205 | codepoint = 206 | (((codepoint & 0x3F) << 10) | 207 | ((((codepoint >> 6) & 0xF) + 1) << 16) | 208 | (surrogate & 0x3FF)); 209 | end += 5; 210 | } else { 211 | unescaped = "?"; 212 | break; 213 | } 214 | } 215 | 216 | Utf32toUtf8(codepoint, utf8Buf); 217 | unescaped = utf8Buf; 218 | 219 | if (codepoint == 0) { 220 | yajl_buf_append(buf, unescaped, 1); 221 | beg = ++end; 222 | continue; 223 | } 224 | 225 | break; 226 | } 227 | default: 228 | assert("this should never happen" == NULL); 229 | } 230 | yajl_buf_append(buf, unescaped, (unsigned int)strlen(unescaped)); 231 | beg = ++end; 232 | } else { 233 | end++; 234 | } 235 | } 236 | yajl_buf_append(buf, str + beg, end - beg); 237 | } 238 | -------------------------------------------------------------------------------- /ext/yajl/yajl_encode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __YAJL_ENCODE_H__ 34 | #define __YAJL_ENCODE_H__ 35 | 36 | #include "yajl_buf.h" 37 | #include "api/yajl_gen.h" 38 | 39 | YAJL_API 40 | void yajl_string_encode2(const yajl_print_t printer, 41 | void * ctx, 42 | const unsigned char * str, 43 | unsigned int length, 44 | unsigned int htmlSafe); 45 | 46 | YAJL_API 47 | void yajl_string_encode(yajl_buf buf, const unsigned char * str, 48 | unsigned int length, 49 | unsigned int htmlSafe); 50 | 51 | YAJL_API 52 | void yajl_string_decode(yajl_buf buf, const unsigned char * str, 53 | unsigned int length); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /ext/yajl/yajl_ext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2011 Brian Lopez - http://github.com/brianmario 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include "api/yajl_parse.h" 25 | #include "api/yajl_gen.h" 26 | 27 | /* tell rbx not to use it's caching compat layer 28 | by doing this we're making a promize to RBX that 29 | we'll never modify the pointers we get back from RSTRING_PTR */ 30 | #define RSTRING_NOT_MODIFIED 31 | 32 | #include 33 | 34 | #ifdef HAVE_RUBY_ENCODING_H 35 | #include 36 | static rb_encoding *utf8Encoding; 37 | #endif 38 | 39 | #define READ_BUFSIZE 8192 40 | #define WRITE_BUFSIZE 8192 41 | 42 | /* Older versions of Ruby (< 1.8.6) need these */ 43 | #ifndef RSTRING_PTR 44 | #define RSTRING_PTR(s) (RSTRING(s)->ptr) 45 | #endif 46 | #ifndef RSTRING_LEN 47 | #define RSTRING_LEN(s) (RSTRING(s)->len) 48 | #endif 49 | #ifndef RARRAY_PTR 50 | #define RARRAY_PTR(s) (RARRAY(s)->ptr) 51 | #endif 52 | #ifndef RARRAY_LEN 53 | #define RARRAY_LEN(s) (RARRAY(s)->len) 54 | #endif 55 | 56 | static VALUE cStandardError, cParseError, cEncodeError, mYajl, cParser, cProjector, cEncoder; 57 | static ID intern_io_read, intern_call, intern_keys, intern_to_s, 58 | intern_to_json, intern_has_key, intern_to_sym, intern_as_json; 59 | static ID sym_allow_comments, sym_check_utf8, sym_pretty, sym_indent, sym_terminator, sym_symbolize_keys, sym_symbolize_names, sym_html_safe, sym_entities; 60 | 61 | #define GetParser(obj, sval) Data_Get_Struct(obj, yajl_parser_wrapper, sval); 62 | #define GetEncoder(obj, sval) Data_Get_Struct(obj, yajl_encoder_wrapper, sval); 63 | 64 | static void yajl_check_and_fire_callback(void * ctx); 65 | static void yajl_set_static_value(void * ctx, VALUE val); 66 | static void yajl_encode_part(void * wrapper, VALUE obj, VALUE io); 67 | static void yajl_parse_chunk(const unsigned char * chunk, unsigned int len, yajl_handle parser); 68 | 69 | static int yajl_found_null(void * ctx); 70 | static int yajl_found_boolean(void * ctx, int boolean); 71 | static int yajl_found_number(void * ctx, const char * numberVal, unsigned int numberLen); 72 | static int yajl_found_string(void * ctx, const unsigned char * stringVal, unsigned int stringLen); 73 | static int yajl_found_hash_key(void * ctx, const unsigned char * stringVal, unsigned int stringLen); 74 | static int yajl_found_start_hash(void * ctx); 75 | static int yajl_found_end_hash(void * ctx); 76 | static int yajl_found_start_array(void * ctx); 77 | static int yajl_found_end_array(void * ctx); 78 | 79 | static yajl_callbacks callbacks = { 80 | yajl_found_null, 81 | yajl_found_boolean, 82 | NULL, 83 | NULL, 84 | yajl_found_number, 85 | yajl_found_string, 86 | yajl_found_start_hash, 87 | yajl_found_hash_key, 88 | yajl_found_end_hash, 89 | yajl_found_start_array, 90 | yajl_found_end_array 91 | }; 92 | 93 | typedef struct { 94 | VALUE builderStack; 95 | VALUE parse_complete_callback; 96 | int nestedArrayLevel; 97 | int nestedHashLevel; 98 | int objectsFound; 99 | int symbolizeKeys; 100 | yajl_handle parser; 101 | } yajl_parser_wrapper; 102 | 103 | typedef struct { 104 | VALUE on_progress_callback; 105 | VALUE terminator; 106 | yajl_gen encoder; 107 | unsigned char *indentString; 108 | } yajl_encoder_wrapper; 109 | 110 | static VALUE rb_yajl_parser_new(int argc, VALUE * argv, VALUE self); 111 | static VALUE rb_yajl_parser_init(int argc, VALUE * argv, VALUE self); 112 | static VALUE rb_yajl_parser_parse(int argc, VALUE * argv, VALUE self); 113 | static VALUE rb_yajl_parser_parse_chunk(VALUE self, VALUE chunk); 114 | static VALUE rb_yajl_parser_set_complete_cb(VALUE self, VALUE callback); 115 | static void yajl_parser_wrapper_free(void * wrapper); 116 | static void yajl_parser_wrapper_mark(void * wrapper); 117 | 118 | static VALUE rb_yajl_encoder_new(int argc, VALUE * argv, VALUE klass); 119 | static VALUE rb_yajl_encoder_init(int argc, VALUE * argv, VALUE self); 120 | static VALUE rb_yajl_encoder_encode(int argc, VALUE * argv, VALUE self); 121 | static VALUE rb_yajl_encoder_set_progress_cb(VALUE self, VALUE callback); 122 | static void yajl_encoder_wrapper_free(void * wrapper); 123 | static void yajl_encoder_wrapper_mark(void * wrapper); 124 | 125 | static VALUE rb_yajl_json_ext_hash_to_json(int argc, VALUE * argv, VALUE self); 126 | static VALUE rb_yajl_json_ext_array_to_json(int argc, VALUE * argv, VALUE self); 127 | static VALUE rb_yajl_json_ext_fixnum_to_json(int argc, VALUE * argv, VALUE self); 128 | static VALUE rb_yajl_json_ext_float_to_json(int argc, VALUE * argv, VALUE self); 129 | static VALUE rb_yajl_json_ext_string_to_json(int argc, VALUE * argv, VALUE self); 130 | static VALUE rb_yajl_json_ext_true_to_json(int argc, VALUE * argv, VALUE self); 131 | static VALUE rb_yajl_json_ext_false_to_json(int argc, VALUE * argv, VALUE self); 132 | static VALUE rb_yajl_json_ext_nil_to_json(int argc, VALUE * argv, VALUE self); 133 | static VALUE rb_yajl_encoder_enable_json_gem_ext(VALUE klass); 134 | 135 | void Init_yajl(); 136 | -------------------------------------------------------------------------------- /ext/yajl/yajl_lex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __YAJL_LEX_H__ 34 | #define __YAJL_LEX_H__ 35 | 36 | #include "api/yajl_common.h" 37 | 38 | typedef enum { 39 | yajl_tok_bool, // 0 40 | yajl_tok_colon, // 1 41 | yajl_tok_comma, // 2 42 | yajl_tok_eof, // 3 43 | yajl_tok_error, // 4 44 | yajl_tok_left_brace, // 5 45 | yajl_tok_left_bracket, // 6 46 | yajl_tok_null, // 7 47 | yajl_tok_right_brace, // 8 48 | yajl_tok_right_bracket, // 9 49 | 50 | /* we differentiate between integers and doubles to allow the 51 | * parser to interpret the number without re-scanning */ 52 | yajl_tok_integer, // 10 53 | yajl_tok_double, // 11 54 | 55 | /* we differentiate between strings which require further processing, 56 | * and strings that do not */ 57 | yajl_tok_string, // 12 58 | yajl_tok_string_with_escapes, // 13 59 | 60 | /* comment tokens are not currently returned to the parser, ever */ 61 | yajl_tok_comment // 14 62 | } yajl_tok; 63 | 64 | typedef struct yajl_lexer_t * yajl_lexer; 65 | 66 | const char *yajl_tok_name(yajl_tok tok); 67 | 68 | YAJL_API 69 | yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc, 70 | unsigned int allowComments, 71 | unsigned int validateUTF8); 72 | 73 | YAJL_API 74 | yajl_lexer yajl_lex_realloc(yajl_lexer orig); 75 | 76 | YAJL_API 77 | void yajl_lex_free(yajl_lexer lexer); 78 | 79 | /** 80 | * run/continue a lex. "offset" is an input/output parameter. 81 | * It should be initialized to zero for a 82 | * new chunk of target text, and upon subsetquent calls with the same 83 | * target text should passed with the value of the previous invocation. 84 | * 85 | * the client may be interested in the value of offset when an error is 86 | * returned from the lexer. This allows the client to render useful 87 | n * error messages. 88 | * 89 | * When you pass the next chunk of data, context should be reinitialized 90 | * to zero. 91 | * 92 | * Finally, the output buffer is usually just a pointer into the jsonText, 93 | * however in cases where the entity being lexed spans multiple chunks, 94 | * the lexer will buffer the entity and the data returned will be 95 | * a pointer into that buffer. 96 | * 97 | * This behavior is abstracted from client code except for the performance 98 | * implications which require that the client choose a reasonable chunk 99 | * size to get adequate performance. 100 | */ 101 | YAJL_API 102 | yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, 103 | unsigned int jsonTextLen, unsigned int * offset, 104 | const unsigned char ** outBuf, unsigned int * outLen); 105 | 106 | /** have a peek at the next token, but don't move the lexer forward */ 107 | YAJL_API 108 | yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, 109 | unsigned int jsonTextLen, unsigned int offset); 110 | 111 | 112 | typedef enum { 113 | yajl_lex_e_ok = 0, 114 | yajl_lex_string_invalid_utf8, 115 | yajl_lex_string_invalid_escaped_char, 116 | yajl_lex_string_invalid_json_char, 117 | yajl_lex_string_invalid_hex_char, 118 | yajl_lex_invalid_char, 119 | yajl_lex_invalid_string, 120 | yajl_lex_missing_integer_after_decimal, 121 | yajl_lex_missing_integer_after_exponent, 122 | yajl_lex_missing_integer_after_minus, 123 | yajl_lex_unallowed_comment, 124 | yajl_lex_alloc_failed 125 | } yajl_lex_error; 126 | 127 | YAJL_API 128 | const char * yajl_lex_error_to_string(yajl_lex_error error); 129 | 130 | /** allows access to more specific information about the lexical 131 | * error when yajl_lex_lex returns yajl_tok_error. */ 132 | YAJL_API 133 | yajl_lex_error yajl_lex_get_error(yajl_lexer lexer); 134 | 135 | /** get the current offset into the most recently lexed json string. */ 136 | YAJL_API 137 | unsigned int yajl_lex_current_offset(yajl_lexer lexer); 138 | 139 | /** get the number of lines lexed by this lexer instance */ 140 | YAJL_API 141 | unsigned int yajl_lex_current_line(yajl_lexer lexer); 142 | 143 | /** get the number of chars lexed by this lexer instance since the last 144 | * \n or \r */ 145 | YAJL_API 146 | unsigned int yajl_lex_current_char(yajl_lexer lexer); 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /ext/yajl/yajl_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, Lloyd Hilaiel. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * 3. Neither the name of Lloyd Hilaiel nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __YAJL_PARSER_H__ 34 | #define __YAJL_PARSER_H__ 35 | 36 | #include "api/yajl_parse.h" 37 | #include "yajl_bytestack.h" 38 | #include "yajl_buf.h" 39 | 40 | 41 | typedef enum { 42 | yajl_state_start = 0, 43 | yajl_state_parse_complete, 44 | yajl_state_parse_error, 45 | yajl_state_lexical_error, 46 | yajl_state_map_start, 47 | yajl_state_map_sep, 48 | yajl_state_map_need_val, 49 | yajl_state_map_got_val, 50 | yajl_state_map_need_key, 51 | yajl_state_array_start, 52 | yajl_state_array_got_val, 53 | yajl_state_array_need_val 54 | } yajl_state; 55 | 56 | struct yajl_handle_t { 57 | const yajl_callbacks * callbacks; 58 | void * ctx; 59 | yajl_lexer lexer; 60 | const char * parseError; 61 | /* the number of bytes consumed from the last client buffer, 62 | * in the case of an error this will be an error offset, in the 63 | * case of an error this can be used as the error offset */ 64 | unsigned int bytesConsumed; 65 | /* temporary storage for decoded strings */ 66 | yajl_buf decodeBuf; 67 | /* a stack of states. access with yajl_state_XXX routines */ 68 | yajl_bytestack stateStack; 69 | /* memory allocation routines */ 70 | yajl_alloc_funcs alloc; 71 | }; 72 | 73 | YAJL_API 74 | yajl_status 75 | yajl_do_parse(yajl_handle handle, const unsigned char * jsonText, 76 | unsigned int jsonTextLen); 77 | 78 | YAJL_API 79 | unsigned char * 80 | yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, 81 | unsigned int jsonTextLen, int verbose); 82 | 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /ext/yajl/yajl_version.c: -------------------------------------------------------------------------------- 1 | #include "api/yajl_version.h" 2 | 3 | int yajl_version(void) 4 | { 5 | return YAJL_VERSION; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /lib/yajl.rb: -------------------------------------------------------------------------------- 1 | require 'yajl/yajl' 2 | 3 | # = Extras 4 | # We're not going to load these automatically, because you might not need them ;) 5 | # 6 | # require 'yajl/http_stream.rb' unless defined?(Yajl::HttpStream) 7 | # require 'yajl/gzip.rb' unless defined?(Yajl::Gzip) 8 | # require 'yajl/deflate.rb' unless defined?(Yajl::Deflate) 9 | # require 'yajl/bzip2.rb' unless defined?(Yajl::Bzip2) 10 | 11 | # = Yajl 12 | # 13 | # Ruby bindings to the excellent Yajl (Yet Another JSON Parser) ANSI C library. 14 | module Yajl 15 | 16 | # For compatibility, has the same signature of Yajl::Parser.parse 17 | def self.load(str_or_io, options={}, read_bufsize=nil, &block) 18 | Parser.parse(str_or_io, options, read_bufsize, &block) 19 | end 20 | 21 | # For compatibility, has the same signature of Yajl::Encoder.encode 22 | def self.dump(obj, *args, &block) 23 | Encoder.encode(obj, args, &block) 24 | end 25 | 26 | class Projector 27 | def initialize(stream, read_bufsize=4096) 28 | @stream = stream 29 | @buffer_size = read_bufsize 30 | end 31 | end 32 | 33 | class Parser 34 | # A helper method for parse-and-forget use-cases 35 | # 36 | # +io+ is the stream to parse JSON from 37 | # 38 | # The +options+ hash allows you to set two parsing options - :allow_comments and :check_utf8 39 | # 40 | # :allow_comments accepts a boolean will enable/disable checks for in-line comments in the JSON stream 41 | # 42 | # :check_utf8 accepts a boolean will enable/disable UTF8 validation for the JSON stream 43 | def self.parse(str_or_io, options={}, read_bufsize=nil, &block) 44 | new(options).parse(str_or_io, read_bufsize, &block) 45 | end 46 | end 47 | 48 | class Encoder 49 | # A helper method for encode-and-forget use-cases 50 | # 51 | # Examples: 52 | # Yajl::Encoder.encode(obj[, io, :pretty => true, :indent => "\t", &block]) 53 | # 54 | # output = Yajl::Encoder.encode(obj[, :pretty => true, :indent => "\t", &block]) 55 | # 56 | # +obj+ is a ruby object to encode to JSON format 57 | # 58 | # +io+ is the optional IO stream to encode the ruby object to. 59 | # If +io+ isn't passed, the resulting JSON string is returned. If +io+ is passed, nil is returned. 60 | # 61 | # The +options+ hash allows you to set two encoding options - :pretty and :indent 62 | # 63 | # :pretty accepts a boolean and will enable/disable "pretty printing" the resulting output 64 | # 65 | # :indent accepts a string and will be used as the indent character(s) during the pretty print process 66 | # 67 | # If a block is passed, it will be used as (and work the same as) the +on_progress+ callback 68 | def self.encode(obj, *args, &block) 69 | # TODO: this code smells, any ideas? 70 | args.flatten! 71 | options = {} 72 | io = nil 73 | args.each do |arg| 74 | if arg.is_a?(Hash) 75 | options = arg 76 | elsif arg.respond_to?(:write) 77 | io = arg 78 | end 79 | end if args.any? 80 | new(options).encode(obj, io, &block) 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /lib/yajl/bzip2.rb: -------------------------------------------------------------------------------- 1 | puts "DEPRECATION WARNING: Yajl's Bzip2 support is going to be removed in 2.0" 2 | 3 | require 'yajl' unless defined?(Yajl::Parser) 4 | 5 | begin 6 | require 'bzip2' unless defined?(Bzip2) 7 | require 'yajl/bzip2/stream_reader.rb' 8 | require 'yajl/bzip2/stream_writer.rb' 9 | rescue LoadError 10 | raise "Unable to load the bzip2 library. Is the bzip2-ruby gem installed?" 11 | end 12 | -------------------------------------------------------------------------------- /lib/yajl/bzip2/stream_reader.rb: -------------------------------------------------------------------------------- 1 | module Yajl 2 | module Bzip2 3 | # This is a wrapper around Bzip::Reader to allow it's #read method to adhere 4 | # to the IO spec, allowing for two parameters (length, and buffer) 5 | class StreamReader < ::Bzip2::Reader 6 | # A helper method to allow use similar to IO#read 7 | def read(len=nil, buffer=nil) 8 | if val = super(len) 9 | unless buffer.nil? 10 | buffer.replace(val) 11 | return buffer 12 | end 13 | super(len) 14 | else 15 | nil 16 | end 17 | end 18 | 19 | # Helper method for one-off parsing from a bzip2-compressed stream 20 | # 21 | # See Yajl::Parser#parse for parameter documentation 22 | def self.parse(input, options={}, buffer_size=nil, &block) 23 | if input.is_a?(String) 24 | input = StringIO.new(input) 25 | end 26 | 27 | Yajl::Parser.new(options).parse(new(input), buffer_size, &block) 28 | end 29 | end 30 | end 31 | end -------------------------------------------------------------------------------- /lib/yajl/bzip2/stream_writer.rb: -------------------------------------------------------------------------------- 1 | module Yajl 2 | module Bzip2 3 | # A wrapper around the Bzip2::Writer class for easier JSON stream encoding 4 | class StreamWriter < ::Bzip2::Writer 5 | 6 | # A helper method for encoding to a bzip2-compressed stream 7 | # 8 | # Look up Yajl::Encoder#encode for parameter documentation 9 | def self.encode(obj, io) 10 | Yajl::Encoder.new.encode(obj, new(io)) 11 | end 12 | end 13 | end 14 | end -------------------------------------------------------------------------------- /lib/yajl/deflate.rb: -------------------------------------------------------------------------------- 1 | puts "DEPRECATION WARNING: Yajl's Deflate support is going to be removed in 2.0" 2 | 3 | require 'yajl' unless defined?(Yajl::Parser) 4 | require 'zlib' unless defined?(Zlib) 5 | require 'yajl/deflate/stream_reader.rb' 6 | require 'yajl/deflate/stream_writer.rb' -------------------------------------------------------------------------------- /lib/yajl/deflate/stream_reader.rb: -------------------------------------------------------------------------------- 1 | module Yajl 2 | module Deflate 3 | # This is a wrapper around Zlib::Inflate, creating a #read method that adheres 4 | # to the IO spec, allowing for two parameters (length, and buffer) 5 | class StreamReader < ::Zlib::Inflate 6 | 7 | # Wrapper to the initialize method so we can set the initial IO to parse from. 8 | def initialize(io, options) 9 | @io = io 10 | super(options) 11 | end 12 | 13 | # A helper method to allow use similar to IO#read 14 | def read(len=nil, buffer=nil) 15 | if val = @io.read(len) 16 | unless buffer.nil? 17 | buffer.replace(inflate(val)) 18 | return buffer 19 | end 20 | inflate(@io.read(len)) 21 | else 22 | nil 23 | end 24 | end 25 | 26 | # Helper method for one-off parsing from a deflate-compressed stream 27 | # 28 | # See Yajl::Parser#parse for parameter documentation 29 | def self.parse(input, options={}, buffer_size=nil, &block) 30 | if input.is_a?(String) 31 | input = StringIO.new(input) 32 | end 33 | 34 | if options.is_a?(Hash) 35 | deflate_options = options.delete(:deflate_options) 36 | Yajl::Parser.new(options).parse(new(input, deflate_options), buffer_size, &block) 37 | elsif options.is_a?(Fixnum) 38 | Yajl::Parser.new.parse(new(input, options), buffer_size, &block) 39 | end 40 | end 41 | end 42 | end 43 | end -------------------------------------------------------------------------------- /lib/yajl/deflate/stream_writer.rb: -------------------------------------------------------------------------------- 1 | module Yajl 2 | module Deflate 3 | # A wrapper around the Zlib::Deflate class for easier JSON stream parsing 4 | class StreamWriter < ::Zlib::Deflate 5 | 6 | # A helper method to allow use similar to IO#write 7 | def write(str) 8 | deflate(str) 9 | str.size unless str.nil? 10 | end 11 | 12 | # A helper method for one-off encoding to a deflate-compressed stream 13 | # 14 | # Look up Yajl::Encoder#encode for parameter documentation 15 | def self.encode(obj, io) 16 | Yajl::Encoder.new.encode(obj, new(io)) 17 | end 18 | end 19 | end 20 | end -------------------------------------------------------------------------------- /lib/yajl/gzip.rb: -------------------------------------------------------------------------------- 1 | puts "DEPRECATION WARNING: Yajl's Gzip support is going to be removed in 2.0" 2 | 3 | require 'yajl' unless defined?(Yajl::Parser) 4 | require 'zlib' unless defined?(Zlib) 5 | require 'yajl/gzip/stream_reader.rb' 6 | require 'yajl/gzip/stream_writer.rb' -------------------------------------------------------------------------------- /lib/yajl/gzip/stream_reader.rb: -------------------------------------------------------------------------------- 1 | module Yajl 2 | module Gzip 3 | # This is a wrapper around Zlib::GzipReader to allow it's #read method to adhere 4 | # to the IO spec, allowing for two parameters (length, and buffer) 5 | class StreamReader < ::Zlib::GzipReader 6 | # A helper method to allow use similar to IO#read 7 | def read(len=nil, buffer=nil) 8 | if val = super(len) 9 | unless buffer.nil? 10 | buffer.replace(val) 11 | return buffer 12 | end 13 | super(len) 14 | else 15 | nil 16 | end 17 | end 18 | 19 | # Helper method for one-off parsing from a gzip-compressed stream 20 | # 21 | # See Yajl::Parser#parse for parameter documentation 22 | def self.parse(input, options={}, buffer_size=nil, &block) 23 | if input.is_a?(String) 24 | input = StringIO.new(input) 25 | end 26 | Yajl::Parser.new(options).parse(new(input), buffer_size, &block) 27 | end 28 | end 29 | end 30 | end -------------------------------------------------------------------------------- /lib/yajl/gzip/stream_writer.rb: -------------------------------------------------------------------------------- 1 | module Yajl 2 | module Gzip 3 | # Wraper around the Zlib::GzipWriter class 4 | class StreamWriter < ::Zlib::GzipWriter 5 | # A helper method for one-off encoding to a gzip-compressed stream 6 | # 7 | # Look up Yajl::Encoder#encode for parameter documentation 8 | def self.encode(obj, io) 9 | Yajl::Encoder.new.encode(obj, new(io)) 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /lib/yajl/http_stream.rb: -------------------------------------------------------------------------------- 1 | puts "DEPRECATION WARNING: Yajl::HttpStream is going to be removed in 2.0" 2 | 3 | require 'socket' 4 | require 'yajl' 5 | require 'yajl/version' unless defined? Yajl::VERSION 6 | require 'uri' 7 | require 'cgi' 8 | 9 | module Yajl 10 | # This module is for making HTTP requests to which the response bodies (and possibly requests in the near future) 11 | # are streamed directly into Yajl. 12 | class HttpStream 13 | 14 | # This Exception is thrown when an HTTP response isn't in ALLOWED_MIME_TYPES 15 | # and therefore cannot be parsed. 16 | class InvalidContentType < Exception; end 17 | class HttpError < StandardError 18 | 19 | attr_reader :message, :headers 20 | 21 | def initialize(message, headers) 22 | @message = message 23 | @headers = headers 24 | end 25 | end 26 | 27 | # The mime-type we expect the response to be. If it's anything else, we can't parse it 28 | # and an InvalidContentType is raised. 29 | ALLOWED_MIME_TYPES = ["application/json", "text/plain"] 30 | 31 | # Makes a basic HTTP GET request to the URI provided 32 | def self.get(uri, opts = {}, &block) 33 | request("GET", uri, opts, &block) 34 | end 35 | 36 | # Makes a basic HTTP GET request to the URI provided allowing the user to terminate the connection 37 | def get(uri, opts = {}, &block) 38 | initialize_socket(uri, opts) 39 | HttpStream::get(uri, opts, &block) 40 | rescue IOError => e 41 | raise e unless @intentional_termination 42 | end 43 | 44 | # Makes a basic HTTP POST request to the URI provided 45 | def self.post(uri, body, opts = {}, &block) 46 | request("POST", uri, opts.merge({:body => body}), &block) 47 | end 48 | 49 | # Makes a basic HTTP POST request to the URI provided allowing the user to terminate the connection 50 | def post(uri, body, opts = {}, &block) 51 | initialize_socket(uri, opts) 52 | HttpStream::post(uri, body, opts, &block) 53 | rescue IOError => e 54 | raise e unless @intentional_termination 55 | end 56 | 57 | # Makes a basic HTTP PUT request to the URI provided 58 | def self.put(uri, body, opts = {}, &block) 59 | request("PUT", uri, opts.merge({:body => body}), &block) 60 | end 61 | 62 | # Makes a basic HTTP PUT request to the URI provided allowing the user to terminate the connection 63 | def put(uri, body, opts = {}, &block) 64 | initialize_socket(uri, opts) 65 | HttpStream::put(uri, body, opts, &block) 66 | rescue IOError => e 67 | raise e unless @intentional_termination 68 | end 69 | 70 | # Makes a basic HTTP DELETE request to the URI provided 71 | def self.delete(uri, opts = {}, &block) 72 | request("DELETE", uri, opts, &block) 73 | end 74 | 75 | # Makes a basic HTTP DELETE request to the URI provided allowing the user to terminate the connection 76 | def delete(uri, opts = {}, &block) 77 | initialize_socket(uri, opts) 78 | HttpStream::delete(uri, opts, &block) 79 | rescue IOError => e 80 | raise e unless @intentional_termination 81 | end 82 | 83 | # Terminate a running HTTPStream instance 84 | def terminate 85 | @intentional_termination = true 86 | @socket.close 87 | end 88 | 89 | protected 90 | def self.request(method, uri, opts = {}, &block) 91 | if uri.is_a?(String) 92 | uri = URI.parse(uri) 93 | end 94 | 95 | default_headers = { 96 | "User-Agent" => opts["User-Agent"] || "Yajl::HttpStream #{Yajl::VERSION}", 97 | "Accept" => "*/*", 98 | "Accept-Charset" => "utf-8" 99 | } 100 | 101 | if method == "POST" || method == "PUT" 102 | default_headers["Content-Type"] = opts["Content-Type"] || "application/x-www-form-urlencoded" 103 | body = opts.delete(:body) 104 | if body.is_a?(Hash) 105 | body = body.keys.collect {|param| "#{CGI.escape(param.to_s)}=#{CGI.escape(body[param].to_s)}"}.join('&') 106 | end 107 | default_headers["Content-Length"] = body.length 108 | end 109 | 110 | unless uri.userinfo.nil? 111 | default_headers["Authorization"] = "Basic #{[uri.userinfo].pack('m').strip!}\r\n" 112 | end 113 | 114 | encodings = [] 115 | encodings << "bzip2" if defined?(Yajl::Bzip2) 116 | encodings << "gzip" if defined?(Yajl::Gzip) 117 | encodings << "deflate" if defined?(Yajl::Deflate) 118 | if encodings.any? 119 | default_headers["Accept-Encoding"] = "#{encodings.join(',')}\r\n" 120 | end 121 | 122 | headers = default_headers.merge(opts[:headers] || {}) 123 | 124 | socket = opts.delete(:socket) || TCPSocket.new(uri.host, uri.port) 125 | request = "#{method} #{uri.path}#{uri.query ? "?"+uri.query : nil} HTTP/1.1\r\n" 126 | request << "Host: #{uri.host}\r\n" 127 | headers.each do |k, v| 128 | request << "#{k}: #{v}\r\n" 129 | end 130 | request << "\r\n" 131 | if method == "POST" || method == "PUT" 132 | request << body 133 | end 134 | socket.write(request) 135 | response_head = {} 136 | response_head[:headers] = {} 137 | 138 | socket.each_line do |line| 139 | if line == "\r\n" # end of the headers 140 | break 141 | else 142 | header = line.split(": ") 143 | if header.size == 1 144 | header = header[0].split(" ") 145 | response_head[:version] = header[0] 146 | response_head[:code] = header[1].to_i 147 | response_head[:msg] = header[2] 148 | # this is the response code line 149 | else 150 | response_head[:headers][header[0]] = header[1].strip 151 | end 152 | end 153 | end 154 | 155 | if (response_head[:code] != 200) 156 | raise HttpError.new("Code 200 expected got #{response_head[:code]}", response_head[:headers]) 157 | end 158 | 159 | parser = Yajl::Parser.new(opts) 160 | parser.on_parse_complete = block if block_given? 161 | if response_head[:headers]["Transfer-Encoding"] == 'chunked' 162 | if block_given? 163 | chunkLeft = 0 164 | while !socket.eof? && (line = socket.gets) 165 | break if line.match(/^0.*?\r\n/) 166 | next if line == "\r\n" 167 | size = line.hex 168 | json = socket.read(size) 169 | next if json.nil? 170 | chunkLeft = size-json.size 171 | if chunkLeft == 0 172 | parser << json 173 | else 174 | # received only part of the chunk, grab the rest 175 | parser << socket.read(chunkLeft) 176 | end 177 | end 178 | else 179 | raise Exception, "Chunked responses detected, but no block given to handle the chunks." 180 | end 181 | else 182 | content_type = response_head[:headers]["Content-Type"].split(';') 183 | content_type = content_type.first 184 | if ALLOWED_MIME_TYPES.include?(content_type) 185 | case response_head[:headers]["Content-Encoding"] 186 | when "gzip" 187 | return Yajl::Gzip::StreamReader.parse(socket, opts, &block) 188 | when "deflate" 189 | return Yajl::Deflate::StreamReader.parse(socket, opts.merge({:deflate_options => -Zlib::MAX_WBITS}), &block) 190 | when "bzip2" 191 | return Yajl::Bzip2::StreamReader.parse(socket, opts, &block) 192 | else 193 | return parser.parse(socket) 194 | end 195 | else 196 | raise InvalidContentType, "The response MIME type #{content_type}" 197 | end 198 | end 199 | ensure 200 | socket.close if !socket.nil? and !socket.closed? 201 | end 202 | 203 | private 204 | # Initialize socket and add it to the opts 205 | def initialize_socket(uri, opts = {}) 206 | return if opts[:socket] 207 | 208 | @socket = TCPSocket.new(uri.host, uri.port) 209 | opts.merge!({:socket => @socket}) 210 | @intentional_termination = false 211 | end 212 | end 213 | end 214 | -------------------------------------------------------------------------------- /lib/yajl/json_gem.rb: -------------------------------------------------------------------------------- 1 | require 'yajl' unless defined?(Yajl::Parser) 2 | require 'yajl/json_gem/parsing' 3 | require 'yajl/json_gem/encoding' 4 | 5 | module ::Kernel 6 | def JSON(object, opts = {}) 7 | if object.respond_to? :to_s 8 | JSON.parse(object.to_s, JSON.default_options.merge(opts)) 9 | else 10 | JSON.generate(object, opts) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/yajl/json_gem/encoding.rb: -------------------------------------------------------------------------------- 1 | require 'yajl' unless defined?(Yajl::Parser) 2 | 3 | # NOTE: this is probably temporary until I can split out the JSON compat C code into it's own 4 | # extension that can be included when this file is. 5 | Yajl::Encoder.enable_json_gem_compatability 6 | 7 | # Our fallback to_json definition 8 | unless defined?(ActiveSupport) 9 | class Object 10 | def to_json(*args, &block) 11 | "\"#{to_s}\"" 12 | end 13 | end 14 | end 15 | 16 | module JSON 17 | class JSONError < StandardError; end unless defined?(JSON::JSONError) 18 | class GeneratorError < JSONError; end unless defined?(JSON::GeneratorError) 19 | 20 | def self.generate(obj, opts=nil) 21 | opts ||= {} 22 | options_map = {} 23 | if opts.has_key?(:indent) 24 | options_map[:pretty] = true 25 | options_map[:indent] = opts[:indent] 26 | end 27 | Yajl::Encoder.encode(obj, options_map) 28 | rescue Yajl::EncodeError => e 29 | raise JSON::GeneratorError, e.message 30 | end 31 | 32 | def self.pretty_generate(obj, opts={}) 33 | begin 34 | options_map = {} 35 | options_map[:pretty] = true 36 | options_map[:indent] = opts[:indent] if opts.has_key?(:indent) 37 | Yajl::Encoder.encode(obj, options_map) 38 | rescue Yajl::EncodeError => e 39 | raise JSON::GeneratorError, e.message 40 | end 41 | end 42 | 43 | def self.dump(obj, io=nil, *args) 44 | begin 45 | Yajl::Encoder.encode(obj, io) 46 | rescue Yajl::EncodeError => e 47 | raise JSON::GeneratorError, e.message 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/yajl/json_gem/parsing.rb: -------------------------------------------------------------------------------- 1 | require 'yajl' unless defined?(Yajl::Parser) 2 | 3 | module JSON 4 | class JSONError < StandardError; end unless defined?(JSON::JSONError) 5 | class ParserError < JSONError; end unless defined?(JSON::ParserError) 6 | 7 | def self.default_options 8 | @default_options ||= {:symbolize_keys => false} 9 | end 10 | 11 | def self.parse(str, opts=JSON.default_options) 12 | begin 13 | Yajl::Parser.parse(str, opts) 14 | rescue Yajl::ParseError => e 15 | raise JSON::ParserError, e.message 16 | end 17 | end 18 | 19 | def self.load(input, *args) 20 | begin 21 | Yajl::Parser.parse(input, default_options) 22 | rescue Yajl::ParseError => e 23 | raise JSON::ParserError, e.message 24 | end 25 | end 26 | end -------------------------------------------------------------------------------- /lib/yajl/version.rb: -------------------------------------------------------------------------------- 1 | module Yajl 2 | VERSION = '1.4.3' 3 | end 4 | -------------------------------------------------------------------------------- /script/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | cd "$(dirname "$0")/.." 5 | exec bundle install --binstubs --path vendor/gems "$@" 6 | -------------------------------------------------------------------------------- /spec/global/global_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | 3 | describe "Yajl" do 4 | context "dump" do 5 | it "should exist as a class-method" do 6 | expect(Yajl).to respond_to(:dump) 7 | end 8 | 9 | it "should be able to encode to a string" do 10 | expect(Yajl.dump({:a => 1234})).to eql('{"a":1234}') 11 | end 12 | 13 | it "should be able to encode to an IO" do 14 | io = StringIO.new 15 | Yajl.dump({:a => 1234}, io) 16 | io.rewind 17 | expect(io.read).to eql('{"a":1234}') 18 | end 19 | 20 | it "should be able to encode with a block supplied" do 21 | Yajl.dump({:a => 1234}) do |chunk| 22 | expect(chunk).to eql('{"a":1234}') 23 | end 24 | end 25 | end 26 | 27 | context "load" do 28 | it "should exist as a class-method" do 29 | expect(Yajl).to respond_to(:load) 30 | end 31 | 32 | it "should be able to parse from a string" do 33 | expect(Yajl.load('{"a":1234}')).to eql({"a" => 1234}) 34 | end 35 | 36 | it "should be able to parse from an IO" do 37 | io = StringIO.new('{"a":1234}') 38 | expect(Yajl.load(io)).to eql({"a" => 1234}) 39 | end 40 | 41 | it "should be able to parse from a string with a block supplied" do 42 | Yajl.load('{"a":1234}') do |h| 43 | expect(h).to eql({"a" => 1234}) 44 | end 45 | end 46 | 47 | it "should be able to parse from an IO with a block supplied" do 48 | io = StringIO.new('{"a":1234}') 49 | Yajl.load(io) do |h| 50 | expect(h).to eql({"a" => 1234}) 51 | end 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/http/fixtures/http.bzip2.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianmario/yajl-ruby/63760720e58d8cb818d59ae6c4f3d96760cd7854/spec/http/fixtures/http.bzip2.dump -------------------------------------------------------------------------------- /spec/http/fixtures/http.chunked.dump: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Content-Type: application/json 3 | Transfer-Encoding: chunked 4 | 5 | 12f 6 | {"item": {"name": "generated", "cached_tag_list": "", "updated_at": "2009-03-24T05:25:09Z", "updated_by_id": null, "price": 1.99, "delta": false, "cost": 0.597, "account_id": 16, "unit": null, "import_tag": null, "taxable": true, "id": 1, "created_by_id": null, "description": null, "company_id": 0, "sk 7 | 8 | 48 9 | u": "06317-0306", "created_at": "2009-03-24T05:25:09Z", "active": true}} 10 | 11 | 0 -------------------------------------------------------------------------------- /spec/http/fixtures/http.deflate.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianmario/yajl-ruby/63760720e58d8cb818d59ae6c4f3d96760cd7854/spec/http/fixtures/http.deflate.dump -------------------------------------------------------------------------------- /spec/http/fixtures/http.error.dump: -------------------------------------------------------------------------------- 1 | HTTP/1.1 404 NOT FOUND 2 | Vary: Accept-Encoding 3 | Content-Type: text/html 4 | Accept-Ranges: bytes 5 | ETag: "-1274243775" 6 | Last-Modified: Thu, 30 Apr 2009 04:36:11 GMT 7 | Content-Length: 32444 8 | Date: Wed, 24 Jun 2009 06:02:18 GMT 9 | Server: lighttpd/1.4.22 10 | Transfer-Encoding: chunked 11 | 12 | THIS PAGE COULD NOT BE FOUND! 13 | -------------------------------------------------------------------------------- /spec/http/fixtures/http.gzip.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianmario/yajl-ruby/63760720e58d8cb818d59ae6c4f3d96760cd7854/spec/http/fixtures/http.gzip.dump -------------------------------------------------------------------------------- /spec/http/http_delete_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | begin 3 | require 'yajl/bzip2' 4 | rescue 5 | warn "Couldn't load yajl/bzip2, maybe you don't have bzip2-ruby installed? Continuing without running bzip2 specs." 6 | end 7 | require 'yajl/gzip' 8 | require 'yajl/deflate' 9 | require 'yajl/http_stream' 10 | 11 | def parse_off_headers(io) 12 | io.each_line do |line| 13 | if line == "\r\n" # end of the headers 14 | break 15 | end 16 | end 17 | end 18 | 19 | describe "Yajl HTTP DELETE request" do 20 | before(:all) do 21 | raw = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.raw.dump'), 'r') 22 | parse_off_headers(raw) 23 | @template_hash = Yajl::Parser.parse(raw) 24 | 25 | raw.rewind 26 | parse_off_headers(raw) 27 | @template_hash_symbolized = Yajl::Parser.parse(raw, :symbolize_keys => true) 28 | 29 | @deflate = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.deflate.dump'), 'r') 30 | @gzip = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.gzip.dump'), 'r') 31 | end 32 | 33 | after(:each) do 34 | @file_path = nil 35 | end 36 | 37 | def prepare_mock_request_dump(format=:raw) 38 | @request = File.new(File.expand_path(File.dirname(__FILE__) + "/fixtures/http.#{format}.dump"), 'r') 39 | @uri = 'file://'+File.expand_path(File.dirname(__FILE__) + "/fixtures/http/http.#{format}.dump") 40 | expect(TCPSocket).to receive(:new).and_return(@request) 41 | expect(@request).to receive(:write) 42 | end 43 | 44 | it "should parse a raw response" do 45 | prepare_mock_request_dump :raw 46 | expect(@template_hash).to eq(Yajl::HttpStream.delete(@uri)) 47 | end 48 | 49 | it "should parse a raw response using instance method" do 50 | prepare_mock_request_dump :raw 51 | expect(@uri).to receive(:host) 52 | expect(@uri).to receive(:port) 53 | stream = Yajl::HttpStream.new 54 | expect(@template_hash).to eq(stream.delete(@uri)) 55 | end 56 | 57 | it "should parse a raw response and symbolize keys" do 58 | prepare_mock_request_dump :raw 59 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.delete(@uri, :symbolize_keys => true)) 60 | end 61 | 62 | if defined?(Yajl::Bzip2::StreamReader) 63 | it "should parse a bzip2 compressed response" do 64 | prepare_mock_request_dump :bzip2 65 | expect(@template_hash).to eq(Yajl::HttpStream.delete(@uri)) 66 | end 67 | 68 | it "should parse a bzip2 compressed response and symbolize keys" do 69 | prepare_mock_request_dump :bzip2 70 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.delete(@uri, :symbolize_keys => true)) 71 | end 72 | end 73 | 74 | it "should parse a deflate compressed response" do 75 | prepare_mock_request_dump :deflate 76 | expect(@template_hash).to eq(Yajl::HttpStream.delete(@uri)) 77 | end 78 | 79 | it "should parse a deflate compressed response and symbolize keys" do 80 | prepare_mock_request_dump :deflate 81 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.delete(@uri, :symbolize_keys => true)) 82 | end 83 | 84 | it "should parse a gzip compressed response" do 85 | prepare_mock_request_dump :gzip 86 | expect(@template_hash).to eq(Yajl::HttpStream.delete(@uri)) 87 | end 88 | 89 | it "should parse a gzip compressed response and symbolize keys" do 90 | prepare_mock_request_dump :gzip 91 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.delete(@uri, :symbolize_keys => true)) 92 | end 93 | 94 | it "should raise when an HTTP code that isn't 200 is returned" do 95 | prepare_mock_request_dump :error 96 | expect { Yajl::HttpStream.delete(@uri) }.to raise_exception(Yajl::HttpStream::HttpError) 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /spec/http/http_error_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | begin 3 | require 'yajl/bzip2' 4 | rescue 5 | warn "Couldn't load yajl/bzip2, maybe you don't have bzip2-ruby installed? Continuing without running bzip2 specs." 6 | end 7 | require 'yajl/gzip' 8 | require 'yajl/deflate' 9 | require 'yajl/http_stream' 10 | 11 | describe "Yajl HTTP error" do 12 | before do 13 | @uri = 'file://' + File.expand_path(File.dirname(__FILE__) + "/fixtures/http/http.error.dump") 14 | @request = File.new(File.expand_path(File.dirname(__FILE__) + "/fixtures/http.error.dump"), 'r') 15 | allow(TCPSocket).to receive(:new).and_return(@request) 16 | allow(@request).to receive(:write) 17 | begin 18 | Yajl::HttpStream.get(@uri) 19 | rescue Yajl::HttpStream::HttpError => e 20 | @error = e 21 | end 22 | end 23 | 24 | it "should contain the error code in the message" do 25 | expect(@error.message).to match(/404/) 26 | end 27 | 28 | it "should provide the HTTP response headers" do 29 | expect(@error.headers.keys).to include('ETag', 'Content-Length', 'Server') 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/http/http_get_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | begin 3 | require 'yajl/bzip2' 4 | rescue 5 | warn "Couldn't load yajl/bzip2, maybe you don't have bzip2-ruby installed? Continuing without running bzip2 specs." 6 | end 7 | require 'yajl/gzip' 8 | require 'yajl/deflate' 9 | require 'yajl/http_stream' 10 | 11 | def parse_off_headers(io) 12 | io.each_line do |line| 13 | if line == "\r\n" # end of the headers 14 | break 15 | end 16 | end 17 | end 18 | 19 | describe "Yajl HTTP GET request" do 20 | before(:all) do 21 | raw = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.raw.dump'), 'r') 22 | parse_off_headers(raw) 23 | @template_hash = Yajl::Parser.parse(raw) 24 | 25 | raw.rewind 26 | parse_off_headers(raw) 27 | @template_hash_symbolized = Yajl::Parser.parse(raw, :symbolize_keys => true) 28 | 29 | @deflate = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.deflate.dump'), 'r') 30 | @gzip = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.gzip.dump'), 'r') 31 | @chunked_body = {"item"=>{"price"=>1.99, "updated_by_id"=>nil, "cached_tag_list"=>"", "name"=>"generated", "created_at"=>"2009-03-24T05:25:09Z", "cost"=>0.597, "delta"=>false, "created_by_id"=>nil, "updated_at"=>"2009-03-24T05:25:09Z", "import_tag"=>nil, "account_id"=>16, "id"=>1, "taxable"=>true, "unit"=>nil, "sku"=>"06317-0306", "company_id"=>0, "description"=>nil, "active"=>true}} 32 | end 33 | 34 | after(:each) do 35 | @file_path = nil 36 | end 37 | 38 | def prepare_mock_request_dump(format=:raw) 39 | @request = File.new(File.expand_path(File.dirname(__FILE__) + "/fixtures/http.#{format}.dump"), 'r') 40 | @uri = 'file://'+File.expand_path(File.dirname(__FILE__) + "/fixtures/http/http.#{format}.dump") 41 | expect(TCPSocket).to receive(:new).and_return(@request) 42 | expect(@request).to receive(:write) 43 | end 44 | 45 | it "should parse a raw response" do 46 | prepare_mock_request_dump :raw 47 | expect(@template_hash).to eq(Yajl::HttpStream.get(@uri)) 48 | end 49 | 50 | it "should parse a raw response and symbolize keys" do 51 | prepare_mock_request_dump :raw 52 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.get(@uri, :symbolize_keys => true)) 53 | end 54 | 55 | it "should parse a raw response using instance method" do 56 | prepare_mock_request_dump :raw 57 | expect(@uri).to receive(:host) 58 | expect(@uri).to receive(:port) 59 | stream = Yajl::HttpStream.new 60 | expect(@template_hash).to eq(stream.get(@uri)) 61 | end 62 | 63 | it "should parse a chunked response using instance method" do 64 | prepare_mock_request_dump :chunked 65 | expect(@uri).to receive(:host) 66 | expect(@uri).to receive(:port) 67 | stream = Yajl::HttpStream.new 68 | stream.get(@uri) do |obj| 69 | expect(obj).to eql(@chunked_body) 70 | end 71 | end 72 | 73 | if defined?(Yajl::Bzip2::StreamReader) 74 | it "should parse a bzip2 compressed response" do 75 | prepare_mock_request_dump :bzip2 76 | expect(@template_hash).to eq(Yajl::HttpStream.get(@uri)) 77 | end 78 | 79 | it "should parse a bzip2 compressed response and symbolize keys" do 80 | prepare_mock_request_dump :bzip2 81 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.get(@uri, :symbolize_keys => true)) 82 | end 83 | end 84 | 85 | it "should parse a deflate compressed response" do 86 | prepare_mock_request_dump :deflate 87 | expect(@template_hash).to eq(Yajl::HttpStream.get(@uri)) 88 | end 89 | 90 | it "should parse a deflate compressed response and symbolize keys" do 91 | prepare_mock_request_dump :deflate 92 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.get(@uri, :symbolize_keys => true)) 93 | end 94 | 95 | it "should parse a gzip compressed response" do 96 | prepare_mock_request_dump :gzip 97 | expect(@template_hash).to eq(Yajl::HttpStream.get(@uri)) 98 | end 99 | 100 | it "should parse a gzip compressed response and symbolize keys" do 101 | prepare_mock_request_dump :gzip 102 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.get(@uri, :symbolize_keys => true)) 103 | end 104 | 105 | it "should raise when an HTTP code that isn't 200 is returned" do 106 | prepare_mock_request_dump :error 107 | expect { Yajl::HttpStream.get(@uri) }.to raise_exception(Yajl::HttpStream::HttpError) 108 | end 109 | end 110 | -------------------------------------------------------------------------------- /spec/http/http_post_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | begin 3 | require 'yajl/bzip2' 4 | rescue 5 | warn "Couldn't load yajl/bzip2, maybe you don't have bzip2-ruby installed? Continuing without running bzip2 specs." 6 | end 7 | require 'yajl/gzip' 8 | require 'yajl/deflate' 9 | require 'yajl/http_stream' 10 | 11 | def parse_off_headers(io) 12 | io.each_line do |line| 13 | if line == "\r\n" # end of the headers 14 | break 15 | end 16 | end 17 | end 18 | 19 | describe "Yajl HTTP POST request" do 20 | before(:all) do 21 | raw = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.raw.dump'), 'r') 22 | parse_off_headers(raw) 23 | @template_hash = Yajl::Parser.parse(raw) 24 | 25 | raw.rewind 26 | parse_off_headers(raw) 27 | @template_hash_symbolized = Yajl::Parser.parse(raw, :symbolize_keys => true) 28 | 29 | @deflate = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.deflate.dump'), 'r') 30 | @gzip = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.gzip.dump'), 'r') 31 | @body = "blah=foo&bar=baz" 32 | @hashed_body = {:blah => 'foo', 'bar' => 'baz'} 33 | @chunked_body = {"item"=>{"price"=>1.99, "updated_by_id"=>nil, "cached_tag_list"=>"", "name"=>"generated", "created_at"=>"2009-03-24T05:25:09Z", "cost"=>0.597, "delta"=>false, "created_by_id"=>nil, "updated_at"=>"2009-03-24T05:25:09Z", "import_tag"=>nil, "account_id"=>16, "id"=>1, "taxable"=>true, "unit"=>nil, "sku"=>"06317-0306", "company_id"=>0, "description"=>nil, "active"=>true}} 34 | end 35 | 36 | after(:each) do 37 | @file_path = nil 38 | end 39 | 40 | def prepare_mock_request_dump(format=:raw) 41 | @request = File.new(File.expand_path(File.dirname(__FILE__) + "/fixtures/http.#{format}.dump"), 'r') 42 | @uri = 'file://'+File.expand_path(File.dirname(__FILE__) + "/fixtures/http/http.#{format}.dump") 43 | expect(TCPSocket).to receive(:new).and_return(@request) 44 | expect(@request).to receive(:write) 45 | end 46 | 47 | it "should parse a raw response" do 48 | prepare_mock_request_dump :raw 49 | expect(@template_hash).to eq(Yajl::HttpStream.post(@uri, @body)) 50 | end 51 | 52 | it "should parse a raw response using instance method" do 53 | prepare_mock_request_dump :raw 54 | expect(@uri).to receive(:host) 55 | expect(@uri).to receive(:port) 56 | stream = Yajl::HttpStream.new 57 | expect(@template_hash).to eq(stream.post(@uri, @body)) 58 | end 59 | 60 | it "should parse a raw response with hashed body" do 61 | prepare_mock_request_dump :raw 62 | expect(@template_hash).to eq(Yajl::HttpStream.post(@uri, @hashed_body)) 63 | end 64 | 65 | it "should parse a raw response and symbolize keys" do 66 | prepare_mock_request_dump :raw 67 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.post(@uri, @body, :symbolize_keys => true)) 68 | end 69 | 70 | if defined?(Yajl::Bzip2::StreamReader) 71 | it "should parse a bzip2 compressed response" do 72 | prepare_mock_request_dump :bzip2 73 | expect(@template_hash).to eq(Yajl::HttpStream.post(@uri, @body)) 74 | end 75 | 76 | it "should parse a bzip2 compressed response and symbolize keys" do 77 | prepare_mock_request_dump :bzip2 78 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.post(@uri, @body, :symbolize_keys => true)) 79 | end 80 | end 81 | 82 | it "should parse a deflate compressed response" do 83 | prepare_mock_request_dump :deflate 84 | expect(@template_hash).to eq(Yajl::HttpStream.post(@uri, @body)) 85 | end 86 | 87 | it "should parse a deflate compressed response and symbolize keys" do 88 | prepare_mock_request_dump :deflate 89 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.post(@uri, @body, :symbolize_keys => true)) 90 | end 91 | 92 | it "should parse a gzip compressed response" do 93 | prepare_mock_request_dump :gzip 94 | expect(@template_hash).to eq(Yajl::HttpStream.post(@uri, @body)) 95 | end 96 | 97 | it "should parse a gzip compressed response and symbolize keys" do 98 | prepare_mock_request_dump :gzip 99 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.post(@uri, @body, :symbolize_keys => true)) 100 | end 101 | 102 | it "should parse a chunked raw response" do 103 | prepare_mock_request_dump :chunked 104 | Yajl::HttpStream.post(@uri, @body) do |obj| 105 | expect(obj).to eql(@chunked_body) 106 | end 107 | end 108 | 109 | it "should throw Exception if chunked response and no block given" do 110 | prepare_mock_request_dump :chunked 111 | expect {Yajl::HttpStream.post(@uri, @body)}.to raise_error(Exception) 112 | end 113 | 114 | it "should throw InvalidContentType if unable to handle the MIME type" do 115 | prepare_mock_request_dump :html 116 | expect {Yajl::HttpStream.post(@uri, @body)}.to raise_error(Yajl::HttpStream::InvalidContentType) 117 | end 118 | 119 | it "should raise when an HTTP code that isn't 200 is returned" do 120 | prepare_mock_request_dump :error 121 | expect { Yajl::HttpStream.post(@uri, @body) }.to raise_exception(Yajl::HttpStream::HttpError) 122 | end 123 | end 124 | -------------------------------------------------------------------------------- /spec/http/http_put_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | begin 3 | require 'yajl/bzip2' 4 | rescue 5 | warn "Couldn't load yajl/bzip2, maybe you don't have bzip2-ruby installed? Continuing without running bzip2 specs." 6 | end 7 | require 'yajl/gzip' 8 | require 'yajl/deflate' 9 | require 'yajl/http_stream' 10 | 11 | def parse_off_headers(io) 12 | io.each_line do |line| 13 | if line == "\r\n" # end of the headers 14 | break 15 | end 16 | end 17 | end 18 | 19 | describe "Yajl HTTP PUT request" do 20 | before(:all) do 21 | raw = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.raw.dump'), 'r') 22 | parse_off_headers(raw) 23 | @template_hash = Yajl::Parser.parse(raw) 24 | 25 | raw.rewind 26 | parse_off_headers(raw) 27 | @template_hash_symbolized = Yajl::Parser.parse(raw, :symbolize_keys => true) 28 | 29 | @deflate = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.deflate.dump'), 'r') 30 | @gzip = File.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/http.gzip.dump'), 'r') 31 | @body = "blah=foo&bar=baz" 32 | @hashed_body = {:blah => 'foo', 'bar' => 'baz'} 33 | end 34 | 35 | after(:each) do 36 | @file_path = nil 37 | end 38 | 39 | def prepare_mock_request_dump(format=:raw) 40 | @request = File.new(File.expand_path(File.dirname(__FILE__) + "/fixtures/http.#{format}.dump"), 'r') 41 | @uri = 'file://'+File.expand_path(File.dirname(__FILE__) + "/fixtures/http/http.#{format}.dump") 42 | expect(TCPSocket).to receive(:new).and_return(@request) 43 | expect(@request).to receive(:write) 44 | end 45 | 46 | it "should parse a raw response" do 47 | prepare_mock_request_dump :raw 48 | expect(@template_hash).to eq(Yajl::HttpStream.put(@uri, @body)) 49 | end 50 | 51 | it "should parse a raw response using instance method" do 52 | prepare_mock_request_dump :raw 53 | expect(@uri).to receive(:host) 54 | expect(@uri).to receive(:port) 55 | stream = Yajl::HttpStream.new 56 | expect(@template_hash).to eq(stream.put(@uri, @body)) 57 | end 58 | 59 | it "should parse a raw response with hashed body" do 60 | prepare_mock_request_dump :raw 61 | expect(@template_hash).to eq(Yajl::HttpStream.post(@uri, @hashed_body)) 62 | end 63 | 64 | it "should parse a raw response and symbolize keys" do 65 | prepare_mock_request_dump :raw 66 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.put(@uri, @body, :symbolize_keys => true)) 67 | end 68 | 69 | if defined?(Yajl::Bzip2::StreamReader) 70 | it "should parse a bzip2 compressed response" do 71 | prepare_mock_request_dump :bzip2 72 | expect(@template_hash).to eq(Yajl::HttpStream.put(@uri, @body)) 73 | end 74 | 75 | it "should parse a bzip2 compressed response and symbolize keys" do 76 | prepare_mock_request_dump :bzip2 77 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.put(@uri, @body, :symbolize_keys => true)) 78 | end 79 | end 80 | 81 | it "should parse a deflate compressed response" do 82 | prepare_mock_request_dump :deflate 83 | expect(@template_hash).to eq(Yajl::HttpStream.put(@uri, @body)) 84 | end 85 | 86 | it "should parse a deflate compressed response and symbolize keys" do 87 | prepare_mock_request_dump :deflate 88 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.put(@uri, @body, :symbolize_keys => true)) 89 | end 90 | 91 | it "should parse a gzip compressed response" do 92 | prepare_mock_request_dump :gzip 93 | expect(@template_hash).to eq(Yajl::HttpStream.put(@uri, @body)) 94 | end 95 | 96 | it "should parse a gzip compressed response and symbolize keys" do 97 | prepare_mock_request_dump :gzip 98 | expect(@template_hash_symbolized).to eq(Yajl::HttpStream.put(@uri, @body, :symbolize_keys => true)) 99 | end 100 | 101 | it "should raise when an HTTP code that isn't 200 is returned" do 102 | prepare_mock_request_dump :error 103 | expect { Yajl::HttpStream.put(@uri, @body) }.to raise_exception(Yajl::HttpStream::HttpError) 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /spec/http/http_stream_options_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | require 'yajl/http_stream' 3 | require 'socket' 4 | 5 | describe "Passing options to HttpStream instance methods" do 6 | before(:all) do 7 | @stream = Yajl::HttpStream.new 8 | end 9 | 10 | it "should not create a new socket it one is provided" do 11 | expect(TCPSocket).not_to receive(:new) 12 | options = {:socket => :my_provided_socket} 13 | 14 | @stream.send(:initialize_socket, URI.parse("http://google.com"), options) 15 | 16 | expect(options[:socket]).to eq(:my_provided_socket) 17 | end 18 | 19 | it "should create a new socket if one is not provided" do 20 | expect(TCPSocket).to receive(:new).with("google.com", 80).and_return( :tcp_socket ) 21 | options = {} 22 | 23 | @stream.send(:initialize_socket, URI.parse("http://google.com"), options) 24 | 25 | expect(options[:socket]).to eq(:tcp_socket) 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/json_gem_compatibility/compatibility_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 3 | 4 | class Dummy; end 5 | 6 | describe "JSON Gem compatability API" do 7 | it "shoud not mixin #to_json on base objects until compatability has been enabled" do 8 | d = Dummy.new 9 | 10 | expect(d.respond_to?(:to_json)).not_to be_truthy 11 | expect("".respond_to?(:to_json)).not_to be_truthy 12 | expect(1.respond_to?(:to_json)).not_to be_truthy 13 | expect("1.5".to_f.respond_to?(:to_json)).not_to be_truthy 14 | expect([].respond_to?(:to_json)).not_to be_truthy 15 | expect({:foo => "bar"}.respond_to?(:to_json)).not_to be_truthy 16 | expect(true.respond_to?(:to_json)).not_to be_truthy 17 | expect(false.respond_to?(:to_json)).not_to be_truthy 18 | expect(nil.respond_to?(:to_json)).not_to be_truthy 19 | end 20 | 21 | it "should mixin #to_json on base objects after compatability has been enabled" do 22 | require 'yajl/json_gem' 23 | d = Dummy.new 24 | 25 | expect(d.respond_to?(:to_json)).to be_truthy 26 | expect("".respond_to?(:to_json)).to be_truthy 27 | expect(1.respond_to?(:to_json)).to be_truthy 28 | expect("1.5".to_f.respond_to?(:to_json)).to be_truthy 29 | expect([].respond_to?(:to_json)).to be_truthy 30 | expect({:foo => "bar"}.respond_to?(:to_json)).to be_truthy 31 | expect(true.respond_to?(:to_json)).to be_truthy 32 | expect(false.respond_to?(:to_json)).to be_truthy 33 | expect(nil.respond_to?(:to_json)).to be_truthy 34 | end 35 | 36 | it "should require yajl/json_gem to enable the compatability API" do 37 | expect(defined?(JSON)).to be_truthy 38 | 39 | expect(JSON.respond_to?(:parse)).to be_truthy 40 | expect(JSON.respond_to?(:generate)).to be_truthy 41 | expect(JSON.respond_to?(:pretty_generate)).to be_truthy 42 | expect(JSON.respond_to?(:load)).to be_truthy 43 | expect(JSON.respond_to?(:dump)).to be_truthy 44 | end 45 | 46 | it "should allow default parsing options be set with JSON.default_options" do 47 | default = JSON.default_options[:symbolize_keys] 48 | expect(JSON.parse('{"foo": 1234}')).to be === {"foo" => 1234} 49 | JSON.default_options[:symbolize_keys] = true 50 | expect(JSON.parse('{"foo": 1234}')).to be === {:foo => 1234} 51 | JSON.default_options[:symbolize_keys] = default # ensure the rest of the test cases expect the default 52 | end 53 | 54 | it "should also allow the json gem's symbolize_names key" do 55 | expect(JSON.parse('{"foo": 1234}', :symbolize_names => true)).to be === {:foo => 1234} 56 | end 57 | 58 | it "should encode arbitrary classes via their default to_json method" do 59 | d = Dummy.new 60 | expect(d.to_json).to eq("\"#{d.to_s}\"") 61 | 62 | t = Time.now 63 | expect(t.to_json).to eq("\"#{t.to_s}\"") 64 | 65 | da = Date.today 66 | expect(da.to_json).to eq("\"#{da.to_s}\"") 67 | 68 | dt = DateTime.new 69 | expect(dt.to_json).to eq("\"#{dt.to_s}\"") 70 | end 71 | 72 | it "should have the standard parsing and encoding exceptions mapped" do 73 | expect(JSON::JSONError.new.is_a?(StandardError)).to be_truthy 74 | expect(JSON::ParserError.new.is_a?(JSON::JSONError)).to be_truthy 75 | expect(JSON::GeneratorError.new.is_a?(JSON::JSONError)).to be_truthy 76 | 77 | expect { 78 | JSON.parse("blah") 79 | }.to raise_error(JSON::ParserError) 80 | 81 | expect { 82 | JSON.generate(0.0/0.0) 83 | }.to raise_error(JSON::GeneratorError) 84 | end 85 | 86 | context "ported tests for Unicode" do 87 | it "should be able to encode and parse unicode" do 88 | expect('""').to eql(''.to_json) 89 | expect('"\\b"').to eql("\b".to_json) 90 | expect('"\u0001"').to eql(0x1.chr.to_json) 91 | expect('"\u001F"').to eql(0x1f.chr.to_json) 92 | expect('" "').to eql(' '.to_json) 93 | expect("\"#{0x7f.chr}\"").to eql(0x7f.chr.to_json) 94 | utf8 = [ "© ≠ €! \01" ] 95 | json = "[\"© ≠ €! \\u0001\"]" 96 | expect(json).to eql(utf8.to_json) 97 | expect(utf8).to eql(JSON.parse(json)) 98 | utf8 = ["\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"] 99 | json = "[\"あいうえお\"]" 100 | expect(json).to eql(utf8.to_json) 101 | expect(utf8).to eql(JSON.parse(json)) 102 | utf8 = ['საქართველო'] 103 | json = "[\"საქართველო\"]" 104 | expect(json).to eql(utf8.to_json) 105 | expect(utf8).to eql(JSON.parse(json)) 106 | expect('["Ã"]').to eql(JSON.generate(["Ã"])) 107 | expect(["€"]).to eql(JSON.parse('["\u20ac"]')) 108 | utf8_str = "\xf0\xa0\x80\x81" 109 | utf8 = [utf8_str] 110 | json = "[\"#{utf8_str}\"]" 111 | expect(json).to eql(JSON.generate(utf8)) 112 | expect(utf8).to eql(JSON.parse(json)) 113 | end 114 | end 115 | 116 | context "ported tests for generation" do 117 | before(:all) do 118 | @hash = { 119 | 'a' => 2, 120 | 'b' => 3.141, 121 | 'c' => 'c', 122 | 'd' => [ 1, "b", 3.14 ], 123 | 'e' => { 'foo' => 'bar' }, 124 | 'g' => "blah", 125 | 'h' => 1000.0, 126 | 'i' => 0.001 127 | } 128 | 129 | @json2 = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},"g":"blah","h":1000.0,"i":0.001}' 130 | 131 | @json3 = %{ 132 | { 133 | "a": 2, 134 | "b": 3.141, 135 | "c": "c", 136 | "d": [1, "b", 3.14], 137 | "e": {"foo": "bar"}, 138 | "g": "blah", 139 | "h": 1000.0, 140 | "i": 0.001 141 | } 142 | }.chomp 143 | end 144 | 145 | it "should be able to unparse" do 146 | json = JSON.generate(@hash) 147 | expect(JSON.parse(@json2)).to eq(JSON.parse(json)) 148 | parsed_json = JSON.parse(json) 149 | expect(@hash).to eq(parsed_json) 150 | json = JSON.generate({1=>2}) 151 | expect('{"1":2}').to eql(json) 152 | parsed_json = JSON.parse(json) 153 | expect({"1"=>2}).to eq(parsed_json) 154 | end 155 | 156 | it "should be able to unparse pretty" do 157 | json = JSON.pretty_generate(@hash) 158 | expect(JSON.parse(@json3)).to eq(JSON.parse(json)) 159 | parsed_json = JSON.parse(json) 160 | expect(@hash).to eq(parsed_json) 161 | json = JSON.pretty_generate({1=>2}) 162 | test = "{\n \"1\": 2\n}".chomp 163 | expect(test).to eq(json) 164 | parsed_json = JSON.parse(json) 165 | expect({"1"=>2}).to eq(parsed_json) 166 | end 167 | end 168 | 169 | context "ported fixture tests" do 170 | fixtures = File.join(File.dirname(__FILE__), '../parsing/fixtures/*.json') 171 | passed, failed = Dir[fixtures].partition { |f| f['pass'] } 172 | JSON_PASSED = passed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort 173 | JSON_FAILED = failed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort 174 | 175 | JSON_FAILED.each do |name, source| 176 | it "should not be able to parse #{File.basename(name)} as an IO" do 177 | expect { 178 | JSON.parse(StringIO.new(source)) 179 | }.to raise_error(JSON::ParserError) 180 | end 181 | end 182 | 183 | JSON_FAILED.each do |name, source| 184 | it "should not be able to parse #{File.basename(name)} as a string" do 185 | expect { 186 | JSON.parse(source) 187 | }.to raise_error(JSON::ParserError) 188 | end 189 | end 190 | 191 | JSON_PASSED.each do |name, source| 192 | it "should be able to parse #{File.basename(name)} as an IO" do 193 | expect { 194 | JSON.parse(StringIO.new(source)) 195 | }.not_to raise_error 196 | end 197 | end 198 | 199 | JSON_PASSED.each do |name, source| 200 | it "should be able to parse #{File.basename(name)} as a string" do 201 | expect { 202 | JSON.parse(source) 203 | }.not_to raise_error 204 | end 205 | end 206 | end 207 | end 208 | -------------------------------------------------------------------------------- /spec/parsing/active_support_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 3 | 4 | describe "ActiveSupport test cases" do 5 | TESTS = { 6 | %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}}, 7 | %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}}, 8 | %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}}, 9 | %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]}, 10 | %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]}, 11 | %({"a": "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"}, 12 | %({"a": "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"}, 13 | # multibyte 14 | %({"matzue": "松江", "asakusa": "浅草"}) => {"matzue" => "松江", "asakusa" => "浅草"}, 15 | %({"a": "2007-01-01"}) => {'a' => "2007-01-01"}, 16 | %({"a": "2007-01-01 01:12:34 Z"}) => {'a' => "2007-01-01 01:12:34 Z"}, 17 | # no time zone 18 | %({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"}, 19 | # needs to be *exact* 20 | %({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "}, 21 | %({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"}, 22 | %([]) => [], 23 | %({}) => {}, 24 | %({"a":1}) => {"a" => 1}, 25 | %({"a": ""}) => {"a" => ""}, 26 | %({"a":"\\""}) => {"a" => "\""}, 27 | %({"a": null}) => {"a" => nil}, 28 | %({"a": true}) => {"a" => true}, 29 | %({"a": false}) => {"a" => false}, 30 | %q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"}, 31 | %q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => ""}, 32 | %q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"}, 33 | %q({"a": "\u003cbr /\u003e"}) => {'a' => "
"}, 34 | %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["","",""]} 35 | } 36 | 37 | TESTS.each do |json, expected| 38 | it "should be able to parse #{json} as an IO" do 39 | expect { 40 | expect(Yajl::Parser.parse(StringIO.new(json))).to eq(expected) 41 | }.not_to raise_error 42 | end 43 | end 44 | 45 | TESTS.each do |json, expected| 46 | it "should be able to parse #{json} as a string" do 47 | expect { 48 | expect(Yajl::Parser.parse(json)).to eq(expected) 49 | }.not_to raise_error 50 | end 51 | end 52 | 53 | it "should fail parsing {: 1} as an IO" do 54 | expect { 55 | Yajl::Parser.parse(StringIO.new("{: 1}")) 56 | }.to raise_error(Yajl::ParseError) 57 | end 58 | 59 | it "should fail parsing {: 1} as a string" do 60 | expect { 61 | Yajl::Parser.parse("{: 1}") 62 | }.to raise_error(Yajl::ParseError) 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /spec/parsing/chunked_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | 3 | describe "Chunked parser" do 4 | before(:all) do 5 | @final = [{"abc" => 123}, {"def" => 456}] 6 | end 7 | 8 | before(:each) do 9 | @callback = lambda { |hash| 10 | # no-op 11 | } 12 | @parser = Yajl::Parser.new 13 | @parser.on_parse_complete = @callback 14 | end 15 | 16 | it "should parse a single chunk" do 17 | expect(@callback).to receive(:call).with(@final) 18 | @parser << '[{"abc": 123},{"def": 456}]' 19 | end 20 | 21 | it "should parse a single chunk, 3 times" do 22 | expect(@callback).to receive(:call).with(@final).exactly(3).times 23 | @parser << '[{"abc": 123},{"def": 456}]' 24 | @parser << '[{"abc": 123},{"def": 456}]' 25 | @parser << '[{"abc": 123},{"def": 456}]' 26 | end 27 | 28 | it "should parse in two chunks" do 29 | expect(@callback).to receive(:call).with(@final) 30 | @parser << '[{"abc": 123},' 31 | @parser << '{"def": 456}]' 32 | end 33 | 34 | it "should parse in 2 chunks, twice" do 35 | expect(@callback).to receive(:call).with(@final).exactly(2).times 36 | @parser << '[{"abc": 123},' 37 | @parser << '{"def": 456}]' 38 | @parser << '[{"abc": 123},' 39 | @parser << '{"def": 456}]' 40 | end 41 | 42 | it "should parse 2 JSON strings, in 3 chunks" do 43 | expect(@callback).to receive(:call).with(@final).exactly(2).times 44 | @parser << '[{"abc": 123},' 45 | @parser << '{"def": 456}][{"abc": 123},{"def":' 46 | @parser << ' 456}]' 47 | end 48 | 49 | it "should parse 2 JSON strings in 1 chunk" do 50 | expect(@callback).to receive(:call).with(@final).exactly(2).times 51 | @parser << '[{"abc": 123},{"def": 456}][{"abc": 123},{"def": 456}]' 52 | end 53 | 54 | it "should parse 2 JSON strings from an IO" do 55 | expect(@callback).to receive(:call).with(@final).exactly(2).times 56 | @parser.parse(StringIO.new('[{"abc": 123},{"def": 456}][{"abc": 123},{"def": 456}]')) 57 | end 58 | 59 | it "should parse a JSON string an IO and fire callback once" do 60 | expect(@callback).to receive(:call).with(@final) 61 | @parser.parse(StringIO.new('[{"abc": 123},{"def": 456}]')) 62 | end 63 | 64 | it "should parse twitter_stream.json and fire callback 430 times" do 65 | path = File.expand_path(File.dirname(__FILE__) + '/../../benchmark/subjects/twitter_stream.json') 66 | json = File.new(path, 'r') 67 | expect(@callback).to receive(:call).exactly(430).times 68 | expect { 69 | @parser.parse(json) 70 | }.not_to raise_error 71 | end 72 | 73 | it "should parse twitter_stream.json and fire callback 430 times, with a block as the callback" do 74 | path = File.expand_path(File.dirname(__FILE__) + '/../../benchmark/subjects/twitter_stream.json') 75 | json = File.new(path, 'r') 76 | expect(@callback).to receive(:call).exactly(0).times 77 | @parser.on_parse_complete = nil 78 | expect { 79 | times = 0 80 | @parser.parse(json) do |hsh| 81 | times += 1 82 | end 83 | expect(times).to eql(430) 84 | }.not_to raise_error 85 | end 86 | 87 | it "should raise a Yajl::ParseError error if multiple JSON strings were found when no on_parse_complete callback assigned" do 88 | path = File.expand_path(File.dirname(__FILE__) + '/../../benchmark/subjects/twitter_stream.json') 89 | json = File.new(path, 'r') 90 | @parser.on_parse_complete = nil 91 | expect(@callback).to receive(:call).exactly(0).times 92 | expect { 93 | @parser.parse(json) 94 | }.to raise_error(Yajl::ParseError) 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail.15.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \x15"] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail.16.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \'"] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail.17.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \017"] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail.26.json: -------------------------------------------------------------------------------- 1 | ["tab\ character\ in\ string\ "] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail11.json: -------------------------------------------------------------------------------- 1 | {"Illegal expression": 1 + 2} -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail12.json: -------------------------------------------------------------------------------- 1 | {"Illegal invocation": alert()} -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail13.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot have leading zeroes": 013} -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail14.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot be hex": 0x14} -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail19.json: -------------------------------------------------------------------------------- 1 | {"Missing colon" null} -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail20.json: -------------------------------------------------------------------------------- 1 | {"Double colon":: null} -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail21.json: -------------------------------------------------------------------------------- 1 | {"Comma instead of colon", null} -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail22.json: -------------------------------------------------------------------------------- 1 | ["Colon instead of comma": false] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail23.json: -------------------------------------------------------------------------------- 1 | ["Bad value", truth] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail24.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail25.json: -------------------------------------------------------------------------------- 1 | ["tab character in string "] 2 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail27.json: -------------------------------------------------------------------------------- 1 | ["line 2 | break"] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail28.json: -------------------------------------------------------------------------------- 1 | ["line\ 2 | break"] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail3.json: -------------------------------------------------------------------------------- 1 | {unquoted_key: "keys must be quoted"} -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail4.json: -------------------------------------------------------------------------------- 1 | ["extra comma",] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail5.json: -------------------------------------------------------------------------------- 1 | ["double extra comma",,] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail6.json: -------------------------------------------------------------------------------- 1 | [ , "<-- missing value"] -------------------------------------------------------------------------------- /spec/parsing/fixtures/fail9.json: -------------------------------------------------------------------------------- 1 | {"Extra comma": true,} -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.array.json: -------------------------------------------------------------------------------- 1 | ["foo", 2 | "bar", "baz", 3 | true,false,null,{"key":"value"}, 4 | [null,null,null,[]], 5 | "\n\r\\" 6 | ] 7 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.codepoints_from_unicode_org.json: -------------------------------------------------------------------------------- 1 | "\u004d\u0430\u4e8c\ud800\udf02" 2 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.dc_simple_with_comments.json: -------------------------------------------------------------------------------- 1 | { 2 | "this": "is", // ignore this 3 | "really": "simple", 4 | /* ignore 5 | this 6 | too * / 7 | ** // 8 | (/ 9 | ******/ 10 | "json": "right?" 11 | } 12 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.deep_arrays.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.difficult_json_c_test_case.json: -------------------------------------------------------------------------------- 1 | { "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML", "markup"] } ] } } } 2 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.difficult_json_c_test_case_with_comments.json: -------------------------------------------------------------------------------- 1 | { "glossary": { /* you */ "title": /**/ "example glossary", /*should*/"GlossDiv": { "title": /*never*/"S", /*ever*/"GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", /*see*/"GlossSeeAlso"/*this*/:/*coming*/[/*out*/"GML"/*of*/,/*the*/"XML"/*parser!*/, "markup"] /*hey*/}/*ho*/]/*hey*/}/*ho*/} } // and the parser won't even get this far, so chill. /* hah! 2 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.doubles.json: -------------------------------------------------------------------------------- 1 | [ 0.1e2, 1e1, 3.141569, 10000000000000e-10] 2 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.empty_array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.empty_string.json: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.escaped_bulgarian.json: -------------------------------------------------------------------------------- 1 | ["\u0414\u0430", 2 | "\u041c\u0443", 3 | "\u0415\u0431\u0430", 4 | "\u041c\u0430\u0439\u043a\u0430\u0442\u0430"] 5 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.escaped_foobar.json: -------------------------------------------------------------------------------- 1 | "\u0066\u006f\u006f\u0062\u0061\u0072" 2 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.item.json: -------------------------------------------------------------------------------- 1 | {"item": {"name": "generated", "cached_tag_list": "", "updated_at": "2009-03-24T05:25:09Z", "updated_by_id": null, "price": 1.99, "delta": false, "cost": 0.597, "account_id": 16, "unit": null, "import_tag": null, "taxable": true, "id": 1, "created_by_id": null, "description": null, "company_id": 0, "sku": "06317-0306", "created_at": "2009-03-24T05:25:09Z", "active": true}} -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.json-org-sample1.json: -------------------------------------------------------------------------------- 1 | { 2 | "glossary": { 3 | "title": "example glossary", 4 | "GlossDiv": { 5 | "title": "S", 6 | "GlossList": { 7 | "GlossEntry": { 8 | "ID": "SGML", 9 | "SortAs": "SGML", 10 | "GlossTerm": "Standard Generalized Markup Language", 11 | "Acronym": "SGML", 12 | "Abbrev": "ISO 8879:1986", 13 | "GlossDef": { 14 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 15 | "GlossSeeAlso": ["GML", "XML"] 16 | }, 17 | "GlossSee": "markup" 18 | } 19 | } 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.json-org-sample2.json: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "id": "file", 3 | "value": "File", 4 | "popup": { 5 | "menuitem": [ 6 | {"value": "New", "onclick": "CreateNewDoc()"}, 7 | {"value": "Open", "onclick": "OpenDoc()"}, 8 | {"value": "Close", "onclick": "CloseDoc()"} 9 | ] 10 | } 11 | }} 12 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.json-org-sample3.json: -------------------------------------------------------------------------------- 1 | {"widget": { 2 | "debug": "on", 3 | "window": { 4 | "title": "Sample Konfabulator Widget", 5 | "name": "main_window", 6 | "width": 500, 7 | "height": 500 8 | }, 9 | "image": { 10 | "src": "Images/Sun.png", 11 | "name": "sun1", 12 | "hOffset": 250, 13 | "vOffset": 250, 14 | "alignment": "center" 15 | }, 16 | "text": { 17 | "data": "Click Here", 18 | "size": 36, 19 | "style": "bold", 20 | "name": "text1", 21 | "hOffset": 250, 22 | "vOffset": 100, 23 | "alignment": "center", 24 | "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" 25 | } 26 | }} 27 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.json-org-sample4-nows.json: -------------------------------------------------------------------------------- 1 | {"web-app":{ 2 | "servlet":[ 3 | { 4 | "servlet-name": "cofaxCDS", 5 | "servlet-class": "org.cofax.cds.CDSServlet", 6 | "init-param": { 7 | "configGlossary:installationAt": "Philadelphia, PA", 8 | "configGlossary:adminEmail": "ksm@pobox.com", 9 | "configGlossary:poweredBy": "Cofax", 10 | "configGlossary:poweredByIcon": "/images/cofax.gif", 11 | "configGlossary:staticPath": "/content/static", 12 | "templateProcessorClass": "org.cofax.WysiwygTemplate", 13 | "templateLoaderClass": "org.cofax.FilesTemplateLoader", 14 | "templatePath": "templates", 15 | "templateOverridePath": "", 16 | "defaultListTemplate": "listTemplate.htm", 17 | "defaultFileTemplate": "articleTemplate.htm", 18 | "useJSP": false, 19 | "jspListTemplate": "listTemplate.jsp", 20 | "jspFileTemplate": "articleTemplate.jsp", 21 | "cachePackageTagsTrack": 200, 22 | "cachePackageTagsStore": 200, 23 | "cachePackageTagsRefresh": 60, 24 | "cacheTemplatesTrack": 100, 25 | "cacheTemplatesStore": 50, 26 | "cacheTemplatesRefresh": 15, 27 | "cachePagesTrack": 200, 28 | "cachePagesStore": 100, 29 | "cachePagesRefresh": 10, 30 | "cachePagesDirtyRead": 10, 31 | "searchEngineListTemplate": "forSearchEnginesList.htm", 32 | "searchEngineFileTemplate": "forSearchEngines.htm", 33 | "searchEngineRobotsDb": "WEB-INF/robots.db", 34 | "useDataStore": true, 35 | "dataStoreClass": "org.cofax.SqlDataStore", 36 | "redirectionClass": "org.cofax.SqlRedirection", 37 | "dataStoreName": "cofax", 38 | "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", 39 | "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", 40 | "dataStoreUser": "sa", 41 | "dataStorePassword": "dataStoreTestQuery", 42 | "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", 43 | "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", 44 | "dataStoreInitConns": 10, 45 | "dataStoreMaxConns": 100, 46 | "dataStoreConnUsageLimit": 100, 47 | "dataStoreLogLevel": "debug", 48 | "maxUrlLength": 500}}, 49 | { 50 | "servlet-name": "cofaxEmail", 51 | "servlet-class": "org.cofax.cds.EmailServlet", 52 | "init-param": { 53 | "mailHost": "mail1", 54 | "mailHostOverride": "mail2"}}, 55 | { 56 | "servlet-name": "cofaxAdmin", 57 | "servlet-class": "org.cofax.cds.AdminServlet"}, 58 | 59 | { 60 | "servlet-name": "fileServlet", 61 | "servlet-class": "org.cofax.cds.FileServlet"}, 62 | { 63 | "servlet-name": "cofaxTools", 64 | "servlet-class": "org.cofax.cms.CofaxToolsServlet", 65 | "init-param": { 66 | "templatePath": "toolstemplates/", 67 | "log": 1, 68 | "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", 69 | "logMaxSize": "", 70 | "dataLog": 1, 71 | "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", 72 | "dataLogMaxSize": "", 73 | "removePageCache": "/content/admin/remove?cache=pages&id=", 74 | "removeTemplateCache": "/content/admin/remove?cache=templates&id=", 75 | "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", 76 | "lookInContext": 1, 77 | "adminGroupID": 4, 78 | "betaServer": true}}], 79 | "servlet-mapping": { 80 | "cofaxCDS": "/", 81 | "cofaxEmail": "/cofaxutil/aemail/*", 82 | "cofaxAdmin": "/admin/*", 83 | "fileServlet": "/static/*", 84 | "cofaxTools": "/tools/*"}, 85 | "taglib": { 86 | "taglib-uri": "cofax.tld", 87 | "taglib-location": "/WEB-INF/tlds/cofax.tld"} 88 | }} 89 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.json-org-sample4.json: -------------------------------------------------------------------------------- 1 | {"web-app": { 2 | "servlet": [ 3 | { 4 | "servlet-name": "cofaxCDS", 5 | "servlet-class": "org.cofax.cds.CDSServlet", 6 | "init-param": { 7 | "configGlossary:installationAt": "Philadelphia, PA", 8 | "configGlossary:adminEmail": "ksm@pobox.com", 9 | "configGlossary:poweredBy": "Cofax", 10 | "configGlossary:poweredByIcon": "/images/cofax.gif", 11 | "configGlossary:staticPath": "/content/static", 12 | "templateProcessorClass": "org.cofax.WysiwygTemplate", 13 | "templateLoaderClass": "org.cofax.FilesTemplateLoader", 14 | "templatePath": "templates", 15 | "templateOverridePath": "", 16 | "defaultListTemplate": "listTemplate.htm", 17 | "defaultFileTemplate": "articleTemplate.htm", 18 | "useJSP": false, 19 | "jspListTemplate": "listTemplate.jsp", 20 | "jspFileTemplate": "articleTemplate.jsp", 21 | "cachePackageTagsTrack": 200, 22 | "cachePackageTagsStore": 200, 23 | "cachePackageTagsRefresh": 60, 24 | "cacheTemplatesTrack": 100, 25 | "cacheTemplatesStore": 50, 26 | "cacheTemplatesRefresh": 15, 27 | "cachePagesTrack": 200, 28 | "cachePagesStore": 100, 29 | "cachePagesRefresh": 10, 30 | "cachePagesDirtyRead": 10, 31 | "searchEngineListTemplate": "forSearchEnginesList.htm", 32 | "searchEngineFileTemplate": "forSearchEngines.htm", 33 | "searchEngineRobotsDb": "WEB-INF/robots.db", 34 | "useDataStore": true, 35 | "dataStoreClass": "org.cofax.SqlDataStore", 36 | "redirectionClass": "org.cofax.SqlRedirection", 37 | "dataStoreName": "cofax", 38 | "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", 39 | "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", 40 | "dataStoreUser": "sa", 41 | "dataStorePassword": "dataStoreTestQuery", 42 | "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", 43 | "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", 44 | "dataStoreInitConns": 10, 45 | "dataStoreMaxConns": 100, 46 | "dataStoreConnUsageLimit": 100, 47 | "dataStoreLogLevel": "debug", 48 | "maxUrlLength": 500}}, 49 | { 50 | "servlet-name": "cofaxEmail", 51 | "servlet-class": "org.cofax.cds.EmailServlet", 52 | "init-param": { 53 | "mailHost": "mail1", 54 | "mailHostOverride": "mail2"}}, 55 | { 56 | "servlet-name": "cofaxAdmin", 57 | "servlet-class": "org.cofax.cds.AdminServlet"}, 58 | 59 | { 60 | "servlet-name": "fileServlet", 61 | "servlet-class": "org.cofax.cds.FileServlet"}, 62 | { 63 | "servlet-name": "cofaxTools", 64 | "servlet-class": "org.cofax.cms.CofaxToolsServlet", 65 | "init-param": { 66 | "templatePath": "toolstemplates/", 67 | "log": 1, 68 | "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", 69 | "logMaxSize": "", 70 | "dataLog": 1, 71 | "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", 72 | "dataLogMaxSize": "", 73 | "removePageCache": "/content/admin/remove?cache=pages&id=", 74 | "removeTemplateCache": "/content/admin/remove?cache=templates&id=", 75 | "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", 76 | "lookInContext": 1, 77 | "adminGroupID": 4, 78 | "betaServer": true}}], 79 | "servlet-mapping": { 80 | "cofaxCDS": "/", 81 | "cofaxEmail": "/cofaxutil/aemail/*", 82 | "cofaxAdmin": "/admin/*", 83 | "fileServlet": "/static/*", 84 | "cofaxTools": "/tools/*"}, 85 | 86 | "taglib": { 87 | "taglib-uri": "cofax.tld", 88 | "taglib-location": "/WEB-INF/tlds/cofax.tld"} 89 | }} 90 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.json-org-sample5.json: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "header": "SVG Viewer", 3 | "items": [ 4 | {"id": "Open"}, 5 | {"id": "OpenNew", "label": "Open New"}, 6 | null, 7 | {"id": "ZoomIn", "label": "Zoom In"}, 8 | {"id": "ZoomOut", "label": "Zoom Out"}, 9 | {"id": "OriginalView", "label": "Original View"}, 10 | null, 11 | {"id": "Quality"}, 12 | {"id": "Pause"}, 13 | {"id": "Mute"}, 14 | null, 15 | {"id": "Find", "label": "Find..."}, 16 | {"id": "FindAgain", "label": "Find Again"}, 17 | {"id": "Copy"}, 18 | {"id": "CopyAgain", "label": "Copy Again"}, 19 | {"id": "CopySVG", "label": "Copy SVG"}, 20 | {"id": "ViewSVG", "label": "View SVG"}, 21 | {"id": "ViewSource", "label": "View Source"}, 22 | {"id": "SaveAs", "label": "Save As"}, 23 | null, 24 | {"id": "Help"}, 25 | {"id": "About", "label": "About Adobe CVG Viewer..."} 26 | ] 27 | }} 28 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.numbers-fp-4k.json: -------------------------------------------------------------------------------- 1 | [[-4.0517697E24,-4.6834714E9,2.3016275E-5,429379.38,4.1035245E-35,-3.0304818E-8,-6.054423E8,1.2708386E-15,-1.715156E27,-277.43622,2.0346915E-38,-0.01638545,-1.2856552E32,-4.69584413E11,7.477022E-10,1.07893673E12,-3.5855834,103206.47,0.0017756876,-1.61412621E9,-54.93887,-139561.4,-2.378658E22,-3.158278E-35,5.233813E-31,1.76682848E15],[1.0974016E37,5.3739964E-11,-4.9716053E-33,-1.66076738E14,-4.0119002E37,-1.4027267E-32,-2.72471598E18,2.5744203E-19,-4.572614E-38,3.2234583E31,8.654537E19,-3.4919776E-29,-3.25070671E12,-9.000992E-29,1.0441233E36,4.079525E25,1.2051055E-15,-2.29235541E14,-3.2437188E-13,-1.5618475E-4,-4.0124833E-25,2.8310637E-38,-2.7477381E37,1.32944947E9,2.18171494E12,-1.25300354E17,6.0274116E15,-2.107706E23,6.3065464E34,2.51101692E11,5.254233E25,-2.0404816E-19,1.7693594E-33,-1.1974275E35,2.8162636E34,6.4890817E-21,7.184675E-25,7.5984363E34,-5.618655E-11,-3280961.8,1.28438128E8,8.6140408E18,1.1140984E25,1.47108772E10,3.3097485E24,-2052130.9,1.63728826E17,-6256.014,2835.2756,-2.4856512E24,1.2163494E-7,-1.1225695E13,3185.818],[-5.7091426E35,-7.046804E-12,2.8546067E37,-772.3046,-2.1437726E-18,7.247147E36,-1.5350201E29,-8.961063E-10,0.85318434,-7.483097E-33] 2 | ,[-1.2860384E8,-8.602547E-36],[-2.944476E-12,2.77460487E13,2.2238986E-12,-4.3412906E19,-5175.8833,-0.0073129623,-2.4091398E-20,-4.1746454E-10,4.45905856E8,1.2805583E28,2.5504562E20,5048020.5,-2.664713E28,-1.3501865E-10,4659.968,-5.82742E-35,-1679.142,-3.875056E-26,-4.033507E24,-4.6903224,1.9332838E38,-2.0680365E29,8.525517E-14,-5.230842E-32,3.673353E-35,-1.7281757E38,-8.2598E-9,-17152.049,-4.852759E-29,-1.0426323E-22,-0.020246392,-3.1350626E-6,1.2408656E-37,1.120012E-28,2.4116303E-15,-0.4785474,346436.97,-5.232122E-33,-1.91926374E9,-3.2487415E19,-8.650112E24,-5.055328E-34,-7.409502E-23,1.2598161E-17,5.4119855E13,-1.1477772E-4,4.6083254E-12,-254158.67,-3562.668,6.329796E-33,1.8004916E-23,9.1474255E-32,2.3754586E-25,-0.3737642,-3.8334996E-8,1.6320389E-21,1.00855703E-16,2.8689735E-36,-1.4815323E20] 3 | ,[1.06485072E8,-1.0298127E-36,0.24806988,-1.49687634E10,-3.6207398E32,-1.0312921E-5,-1.2935636E-31,-1.2929703E37,-3.9697367E-19],[1.0102053E15,3.1466665E20,0.08864031,-3.9789494E-35,-2.5044518E-17,4.97892847E17,3.361501E-38,1.9492607E-32,2.0493702E-34,3.00903369E16,-1.6402363E-7,-2.6451675E-18,1.262038E-30,-9.804624E30,-1.2246598E34,-3.315567E25,182204.17,-3.130359E-19,-7.119018E26,-1.48141686E17,4.419125E-31,-2.8471037E-15] 4 | ,[8.0939505E9,1.1374584E-19,-1.4202437E-27,1.313552E33,-4.2573942E12,-5.8381478E13],[-2.6502555E30,4.1753343E-29,9.083372E19,-0.068183176,-1.1031515E-26,-2.4913055E-16,-3.6719114E-37,5.8186E37,5.715726,-1.0163735E34,-8.84853E37,-1.1815134E-37,1.0027934E-16] 5 | ,[-1.4073724E34,1.30061288E13,0.008461121,-1.3376654E-10,-6.0671164E20,1.1833966E-16,14.809583,3.5770768E-22,-7.530457E-32,-1.5393923E-12,-7.8060027E34,2.1101567E-16,-6.2677943E-17,2.2152926E-20,-1.1757083E-31,2.3695316E19,1.4274136E-12,-1.9480981E26,6.291982E-10,-9.367635E-8,6.9291846E15,4.72749638E11,1.0033393E-12,6.817596E31,-1.2097972E-24,-1.9492175E-8,3.22030314E13,-7.977198E24,-3.4311988,-9.747453,1.6084044E-20,-9.820089E-30,-121.80733,-1.6177538E-27,-8.8467775E-4,5.6503555E-11,2.0995368E26,-5.455361E-9,1.8685779E-32,8.574378E-4,2.1685172E-30],[6.861861E-37,-4.4493197E35] 6 | ,[-1.1613617E-18,-4.8534297E20,1.0546074E-20,6.6119614E-25,-2.24921029E17,1.5837627E-19,-186516.12,-3.640935E-33,8.555976E-17,3.2709814E-30,3.63576335E18,1.4442433E-30,2.4232822E-36,-9.666912E31,1.5853016E35,3.73195E21,-125.010605,-2.1777477E-17,1.00537485E-29,-3.1489299E-30,3540.4128,-1.2457142E19,0.002879089,3316.8232,-2.399002E-8,1.2665383E-9,-6.6589328E-21,1.569398E37,-4.0816245E33,7.659948E-29,3.50496255E15,5.2147024E-14,-7.601605E23,3.6567388E7,9.476331E29,6.5074084E7,-3.8742284E-16,-2.8865025E38,-5.8460764E-21,-2.8586424E-36,-1.7062408E32,4.27118324E14,-6.7125395E-28],[3.56796591E16,-618868.25,2.933427E-12,7.236035E-39,1.2127505E-37,9.672922E-34,-4.398644E7,3.5170867E-22,-4.2779222E-30,1.7244597E-28,-2.516157E-4,2.8513992E7,5.198693E-23,1.4477405E19,-1.13826478E10,-2.3829098E-36,18.335575,1.8759609E-13,-1.968288E-22,1.7264434E-37,2.1186231E-17,-1.366064E-37,-2.3724215E-26,-1.83045278E15,-4.5891318E20,1.4144087E33,5517011.0,-1.80326367E18,-3.4664499E-31,8.6163241E12,-3.4160834E-37,1.6376802E-32,-4.1883656E-29,2.1600535E-8,142394.83,-7.924927E24,6.102368E31,5.108181E-15,-3.3982544E21,-0.7968685,1.1872208E35,-5.3212889E17,1.4372333E-9,-2.59713466E11,-1.2630338E34,3.519925E10,7.971905E22,7.0312736E-12,-8.266714E-27],[-1588131.2]] 7 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.numbers-int-4k.json: -------------------------------------------------------------------------------- 1 | [[ -6815,-15 ,25 ,-2379,-30,20,8 ,-148966676 ,-25,-15 ,-475215790,27 ,-21 ,-18 ,-10 ,-860 ,-2703 ,-747,2886 ,-13,-390],[-242 ,22,-55475680,-11,70 ,8,21 ,-5712,22 ,41741460 ,25,-28 ,175967856,20 ,180766425,425383080,-15,100 ,-22 ,0,-4,-1656 ,-195903072 ,-14 ,103871680 ,1,-30,22,5,30,-7 ,-6566160 ,3,0 ,-5100 ,1,4207210 ,2568240 ,262598850 ,3885852 ,-2968],[30,-14421168 ,16,-30 ,21 ,21,-89984160 ,-36689745 ,656 ,-8 ,29 ,27 ,-45057880 ,-2320 ,31,-24 ,-12,22,22],[0 ,840 ,-12,4548996 ,-4,-15 ,21887400 ,27,2255 ,-15,9 ,28,30 ,-4867 ,-19,4 ,5,-12 ,-3,-2964] 2 | ,[-2288,-27,0 ,-450877856,-25 ,-1428,288,68410304 ,-2783,10283700,25,0,3360,3220,2,-14,-3 ,-12,162483684,26,962325,-336726192] 3 | ,[2080 ,-18 ,-226446836,24,-9010575],[572,-14 ,0,10,9 ,18,4228 ,474152068 ,-9 ,-249 ,-3504],[29,-8 ,88136384 ,0 ,-31 ,26,-5425,342 ,-6 ,29,22 ,-3 ,29 ,4300 ,9710532,-10,-4,-1326 ,19 ,1420,-11 ,15447796 ,-9,11],[-4,101 ,-26148096,2086410 ,-5100,13 ,-396,-11835750,-1204,-15 ,-2562,25 ,-2418,-65220672 ,0 ,-5200,2],[12 ,25 ,1768,29 ,10,-266238792 ,190918080 ,-66498600 ,74835240,-14,-753 ,-31] 4 | ,[-19424880,14 ,673847790 ,2088],[1909 ,-6] 5 | ,[-1150 ,864 ,1043,24003072 ,-446 ,-12532509 ,31,-1,26,23 ,29 ,27,-234 ,23,-27,8 ,-5424,59461944,-24 ,-37243800 ,-31 ,429 ,-12950162,-741951 ,330,-1513 ,3744 ,-104324880 ,-1363,13723920 ,1072,0 ,-66401460,-7 ,-28 ,14,-496 ,222896688 ,2392 ,10 ,852 ,10,710600 ,-702268,252678888,31,8],[107921457,0,-69005788 ,-110735688,-2,21 ,620 ,-1],[4,-27,-4,16 ,-1197 ,12575995 ,3248 ,-17 ,-341727540 ,25385304 ,265557816 ,-341890794,44668932,-686426364,-27 ,6 ,-2,850],[59970240,-12 ,-30,26 ,-24 ,640498719,5425,-48,-2418 ,83878272,-948 ,-26,308087920,-22 ,-7320,28,18,-2312,-5084 ,24,18229519 ,-833,30],[17082996 ,7,-12,-493723332 ,184624128,-364 ,10 ,-1950 ,-51792480 ,3,1742,21150360 ,9 ,-730,11 ,153 ,7,-2,-25,342078609 ,123,5 ,48,-19,6500592 ,0,-11] 6 | ,[-13,-31 ,-1683 ,-26,-4264 ,1005 ,-18,195189561 ,-13780200 ,-3842 ,19,-109547490 ,-13,22,15] 7 | ,[-4247 ,163096443 ,4455,4312824 ,-39474240,221,896] 8 | ,[18 ,563669100,-4975,-18,-12 ,8,-14 ,11,12 ,0,24,-337153320,5,237760740,-4520,490,-36,54106920,5 ,1337,-31355456,-26,-5751 ,21 ,-91954704 ,-2952 ,-23,468 ,-97562412,2080,28,5 ,14 ,262828602 ,-1 ,7,-7,6000 ,-28 ,-193977180,-24 ,546,-1615 ,-1,-357052350 ,15,-20,7,-71564800 ,-30,-21,4867 ,-11,14 ,12,-13 ,-8,23],[339311000,-20 ,-459,-20,0] 9 | ,[-16,-920,1116 ,11 ,14 ,-6,452 ,-4025 ,20,-347848875 ,-5640,-185852250,6604,-174912615 ,-9 ,11,-38637780 ,-26,19,-3,-2757977,-29,92153700 ,17 ,-341 ,-9 ,1 ,19,17 ,2527,19 ,-10 ,5673,-14 ,30 ,5456,398044154 ,-12 ,27 ,-5,-6356 ,-1 ,0 ,-24,-429469920,9,-30],[449989148 ,-6,37694916 ,26 ,980 ,18 ,-11484696,-14 ,0,7 ,1408 ,3689,22 ,-560 ,-349350300,28238400,702 ,4104 ,1701 ,-13,-2,-17058312 ,-31 ,-25832520 ,31700160 ,-2508,1 ,865 ,-376597728,3484 ,16,83891808,-111926304,0 ,180025335 ,-10,-7 ,-21,2044,73 ,-23,-221454648],[-2875 ,0,-13 ,14 ,-7 ,6448 ,9,-24,48582105 ,-20 ,4885162 ,650,-3770 ,-17632350,-32004840 ,-468,26955450 ,-25,-2223 ,2040 ,246021300 ,3720 ,-71730560,-27,-88855200 ,88889504,-20,16 ,-137357280,-69545280 ,-4,87012325 ,111810816,-415,8 ,14,9,27,-14592798,3,-31,-5060 ,216 ,-9,-6,-3696,-24 ,427221360,-8,-20,16 ,-99887940 ,13 ,11 ,-2596] 10 | ,[19 ,8 ,154626318 ,1],[-3072 ,-792 ,27 ,-3438 ,5 ,-13,-5 ,27,-1824 ,9,-75,-108 ,-12,-4028 ,26 ,-2442 ,420,59505320 ,-6],[7 ,97876512 ,-300 ,1955,19],[-3750 ,-3 ,-945,-5,0 ,2028,-5 ,6 ,3 ,5928,357979776 ,-4,-24 ,22,-18,3458,-25363756 ,-28 ,-1816,17 ,9 ,-45321881 ,-30,-26,0,20 ,-15,16520672,-4 ,13 ,-19] 11 | ,[93313272,-252644854,3 ,-233450 ,899,6,-26,295789200 ,-840,-13,9,-12 ,-24 ,-5675,-18],[2522 ,339500832 ,0 ,-21 ,14 ,-31,184500,-4 ,0 ,1695330 ,6,-7 ,-27 ,6,-16470210,-4420 ,-15 ,28,2712 ,4,212084622,-26 ,26780400 ,-15,468084708 ,870,-54512648,30923640,59129470,166213800,-69060576,110 ,5,22,47040588,155440992,10],[-759 ,168 ,2938,24 ,1312 ,-18 ,-210243550,171418600,107993520,6,-1918 ,1720 ,3819,20 ,21,-261,-205366356 ,-750675750 ,5 ,19 ,-176472244 ,110 ,194590704 ,-2 ,-23 ,1,278327610,-6 ,0,11,-1,-244155912,15,8,11,-1,-1 ,27 ,-15 ,-22 ,-3696],[-15]] 12 | -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.twitter-search.json: -------------------------------------------------------------------------------- 1 | {"results":[{"text":"@stroughtonsmith You need to add a "Favourites" tab to TC\/iPhone. Like what TwitterFon did. I can't WAIT for your Twitter App!! :) Any ETA?","to_user_id":815309,"to_user":"stroughtonsmith","from_user":"Shaun_R","id":1125687077,"from_user_id":855523,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/68778135\/Safari_Dude_normal.jpg","created_at":"Sat, 17 Jan 2009 06:14:13 +0000"},{"text":"Beginning to understand the Twitter world...and liking it.","to_user_id":null,"from_user":"AWheeler15","id":1125687050,"from_user_id":3694831,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/71564236\/Photo_2_normal.jpg","created_at":"Sat, 17 Jan 2009 06:14:11 +0000"},{"text":"@genar hehe, she cant twitter from work, hasnt got it set up on the phone, and on our workout nights generally the computer is untouched too","to_user_id":1089113,"to_user":"genar","from_user":"donro","id":1125687042,"from_user_id":1907789,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/68316085\/stef_and_don_normal.jpg","created_at":"Sat, 17 Jan 2009 06:14:11 +0000"},{"text":"My morning routine: mail, flickr, google reader, friendfeed, twitter replies http:\/\/ff.im\/-DMrn","to_user_id":null,"from_user":"hakandahlstrom","id":1125686913,"from_user_id":213116,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/67707376\/squarelg_normal.jpg","created_at":"Sat, 17 Jan 2009 06:14:04 +0000"},{"text":"@LeeCollins If you have not seen Lee's Website..Check it out ..Perfect layout. Also.. Twitter Photo tool","to_user_id":381690,"to_user":"leecollins","from_user":"MichaelGPerry","id":1125686877,"from_user_id":2765433,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/70614206\/MG_Perry_normal.JPG","created_at":"Sat, 17 Jan 2009 06:14:02 +0000"},{"text":"Just Buzzed My Blog:: New Friend @AlohaArlene Gets Twooted From Twitter http:\/\/tinyurl.com\/8hd7qy","to_user_id":null,"from_user":"BabyBloggerBrie","id":1125686854,"from_user_id":3593267,"iso_language_code":"nl","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/70969980\/brie_normal.jpg","created_at":"Sat, 17 Jan 2009 06:14:02 +0000"},{"text":"Current will air the inauguration while streaming tweets from the twitter audience on the TV as we watch. Check it - http:\/\/ub0.cc\/7C\/2d","to_user_id":null,"from_user":"my3rdeye","id":1125686843,"from_user_id":2553098,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/67353656\/Charlie_Boognish_normal.jpg","created_at":"Sat, 17 Jan 2009 06:14:01 +0000"},{"text":"milestone: Twitter Grader has now graded 1,000,000 unique twitter accounts. Woo hoo! (via @grader)","to_user_id":null,"from_user":"christyitamoto","id":1125686812,"from_user_id":1549031,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/60294809\/MyPicture_normal.jpg","created_at":"Sat, 17 Jan 2009 06:13:59 +0000"},{"text":"Twitter-Yahoo Mashup Yields Impressive News Search Engine http:\/\/twurl.nl\/pg8sxs","to_user_id":null,"from_user":"synectic","id":1125686791,"from_user_id":2563073,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/67483750\/8yplOv7l.kokopelli_trans_normal.png","created_at":"Sat, 17 Jan 2009 06:13:58 +0000"},{"text":"RT: @sarahamrin You really know how to work Twitter. *scribbles another mark for Sarah on the International T.. http:\/\/tinyurl.com\/7xt8hb","to_user_id":null,"from_user":"howtotweets","id":1125686790,"from_user_id":3437258,"iso_language_code":"en","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Sat, 17 Jan 2009 06:13:58 +0000"},{"text":"IPhone App Reviews - Breaking News in the 09s: iPhone and Twitter: Breaking News in the 09s: iPhone and Twitter .. http:\/\/tinyurl.com\/922qcl","to_user_id":null,"from_user":"ifones","id":1125686749,"from_user_id":1412337,"iso_language_code":"en","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Sat, 17 Jan 2009 06:13:56 +0000"},{"text":"RT: @davidall's book about how to use twitter RULES!! You can get it here: http:\/\/tinyurl.com\/495nm2 http:\/\/tinyurl.com\/8kuva5","to_user_id":null,"from_user":"howtotweets","id":1125686716,"from_user_id":3437258,"iso_language_code":"en","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Sat, 17 Jan 2009 06:13:54 +0000"},{"text":"@ev new 2 twitter & already hooked, thx 4 the welcome. It's rough being a newbie","to_user_id":5621,"to_user":"ev","from_user":"jgordo","id":1125686687,"from_user_id":3696186,"iso_language_code":"en","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/68508879\/Img00020_normal.jpg","created_at":"Sat, 17 Jan 2009 06:13:53 +0000"},{"text":"Twitter applicatie TweetDeck heeft een investering v $500k binnengehaald: http:\/\/twurl.nl\/gfei3i","to_user_id":null,"from_user":"gvenkdaily","id":1125686526,"from_user_id":230616,"iso_language_code":"nl","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/55316327\/gvenkdaily-logo-vierkant_normal.png","created_at":"Sat, 17 Jan 2009 06:13:46 +0000"},{"text":"We are like Twitter Retards.. HA ha ha. I thought I was going to be gay, but I totally changed my mind after being chewed on the other night","to_user_id":null,"from_user":"Aroyal88","id":1125686475,"from_user_id":3219428,"iso_language_code":"en","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Sat, 17 Jan 2009 06:13:43 +0000"}],"since_id":0,"max_id":1125687077,"refresh_url":"?since_id=1125687077&q=twitter","results_per_page":15,"next_page":"?page=2&max_id=1125687077&q=twitter","completed_in":0.01338,"page":1,"query":"twitter"} -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass.twitter-search2.json: -------------------------------------------------------------------------------- 1 | {"results":[{"text":"RT @tmornini: Engine Yard Express = perfect way to test merb or rails deployment - http:\/\/express.engineyard.com\/","to_user_id":null,"from_user":"seanhealy","id":1429979943,"from_user_id":4485910,"iso_language_code":"en","source":"<a href="http:\/\/iconfactory.com\/software\/twitterrific">twitterrific<\/a>","profile_image_url":"https:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/62254150\/irish_noir_normal.jpg","created_at":"Wed, 01 Apr 2009 07:06:16 +0000"},{"text":"RT: Engine Yard Express = perfect way to test merb or rails deployment - http:\/\/express.engineyard.com\/ (via @digsby)","to_user_id":null,"from_user":"tmornini","id":1429966620,"from_user_id":168963,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/49018042\/Tom_Icon_64x64_normal.png","created_at":"Wed, 01 Apr 2009 07:02:00 +0000"},{"text":"Engine Yard Express = perfect way to test merb or rails deployment - http:\/\/express.engineyard.com\/","to_user_id":null,"from_user":"richardholland","id":1428644441,"from_user_id":1608628,"iso_language_code":"en","source":"<a href="http:\/\/www.digsby.com\/">digsby<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/63723025\/mesarah_normal.jpg","created_at":"Wed, 01 Apr 2009 02:07:30 +0000"},{"text":"RT @wycats: How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic.com\/2nl7x","to_user_id":null,"from_user":"AmandaMorin","id":1427373261,"from_user_id":1756964,"iso_language_code":"en","source":"<a href="http:\/\/www.tweetdeck.com\/">TweetDeck<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/67971839\/avatar_normal.jpg","created_at":"Tue, 31 Mar 2009 22:19:29 +0000"},{"text":"engineyard added jarnold to mongrel: \n\n \n \n \n mongrel is at engineyard\/mongrel http:\/\/tinyurl.com\/dm7ldz","to_user_id":null,"from_user":"_snax","id":1427357028,"from_user_id":118386,"iso_language_code":"en","source":"<a href="http:\/\/twitterfeed.com">twitterfeed<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/19934062\/logo_large_normal.gif","created_at":"Tue, 31 Mar 2009 22:16:38 +0000"},{"text":"RT: LOL! RT @wycats:How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic... http:\/\/tinyurl.com\/cgs2hj","to_user_id":null,"from_user":"howtotweets","id":1427228937,"from_user_id":3437258,"iso_language_code":"en","source":"<a href="http:\/\/twitterfeed.com">twitterfeed<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/81039760\/images_normal.jpg","created_at":"Tue, 31 Mar 2009 21:54:32 +0000"},{"text":"LOL! RT @wycats:How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic.com\/2nl7x","to_user_id":null,"from_user":"tsykoduk","id":1427225099,"from_user_id":71236,"iso_language_code":"en","source":"<a href="http:\/\/www.nambu.com">Nambu<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/63278451\/Photo_33_normal.jpg","created_at":"Tue, 31 Mar 2009 21:53:52 +0000"},{"text":"RT @wycats: How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic.com\/2nl7x","to_user_id":null,"from_user":"bratta","id":1427177698,"from_user_id":8376,"iso_language_code":"en","source":"<a href="http:\/\/thecosmicmachine.com\/eventbox\/">EventBox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/80333638\/photo_normal.jpg","created_at":"Tue, 31 Mar 2009 21:45:46 +0000"},{"text":"additional infos on the engineyard outage: http:\/\/tinyurl.com\/cbhbkn","to_user_id":null,"from_user":"aentos","id":1427149457,"from_user_id":6459508,"iso_language_code":"en","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/66789130\/aentos_a_normal.png","created_at":"Tue, 31 Mar 2009 21:40:47 +0000"},{"text":"http:\/\/twitpic.com\/2nl9z - Surviving monster attacks. A PSA from your friends @engineyard","to_user_id":null,"from_user":"carllerche","id":1427108503,"from_user_id":880629,"iso_language_code":"en","source":"<a href="http:\/\/twitpic.com\/">TwitPic<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/56520194\/fry_coffee2_normal.jpg","created_at":"Tue, 31 Mar 2009 21:33:38 +0000"},{"text":"How to survive monster attacks. Some tips from your friends at EngineYard http:\/\/twitpic.com\/2nl7x","to_user_id":null,"from_user":"wycats","id":1427099726,"from_user_id":18414,"iso_language_code":"en","source":"<a href="http:\/\/twitterfon.net\/">TwitterFon<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/51747258\/Yehuda_-_Looking_at_Sky_normal.jpg","created_at":"Tue, 31 Mar 2009 21:32:07 +0000"},{"text":"RT @engineyard: Our CEO posted an update on yesterday's outage: http:\/\/bit.ly\/yA4p5 Good job keeping people in the loop!","to_user_id":null,"from_user":"fatnutz","id":1426857591,"from_user_id":706358,"iso_language_code":"en","source":"<a href="http:\/\/www.tweetdeck.com\/">TweetDeck<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/55573179\/snipe_normal.jpg","created_at":"Tue, 31 Mar 2009 20:50:21 +0000"},{"text":"loving our @entryway @engineyard solo instance, we built an integrity server in mins flat with @atmos lovely chef scripts: http:\/\/is.gd\/pVXw","to_user_id":null,"from_user":"gustin","id":1426653742,"from_user_id":3736601,"iso_language_code":"en","source":"<a href="http:\/\/83degrees.com\/to\/powertwitter">Power Twitter<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/116498033\/face_normal.png","created_at":"Tue, 31 Mar 2009 20:16:36 +0000"},{"text":"RT: Our CEO posted an update on yesterday's outage: http:\/\/bit.ly\/yA4p5 (via @engineyard)","to_user_id":null,"from_user":"tmornini","id":1426483075,"from_user_id":168963,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/49018042\/Tom_Icon_64x64_normal.png","created_at":"Tue, 31 Mar 2009 19:47:00 +0000"},{"text":"#engineyard #github very impressive - both the reason and the response - I must have missed the blog sorry","to_user_id":null,"from_user":"rickwindham","id":1426328592,"from_user_id":1819414,"iso_language_code":"en","source":"<a href="http:\/\/www.tweetdeck.com\/">TweetDeck<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/73617189\/me_new_normal.jpg","created_at":"Tue, 31 Mar 2009 19:16:30 +0000"}],"since_id":1386843259,"max_id":1429979943,"refresh_url":"?since_id=1429979943&q=engineyard","results_per_page":15,"next_page":"?page=2&max_id=1429979943&since_id=1386843259&q=engineyard","warning":"adjusted since_id, it was older than allowed","completed_in":0.037275,"page":1,"query":"engineyard"} -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass1.json: -------------------------------------------------------------------------------- 1 | [ 2 | "JSON Test Pattern pass1", 3 | {"object with 1 member":["array with 1 element"]}, 4 | {}, 5 | [], 6 | -42, 7 | true, 8 | false, 9 | null, 10 | { 11 | "integer": 1234567890, 12 | "real": -9876.543210, 13 | "e": 0.123456789e-12, 14 | "E": 1.234567890E+34, 15 | "": 23456789012E66, 16 | "zero": 0, 17 | "one": 1, 18 | "space": " ", 19 | "quote": "\"", 20 | "backslash": "\\", 21 | "controls": "\b\f\n\r\t", 22 | "slash": "/ & \/", 23 | "alpha": "abcdefghijklmnopqrstuvwyz", 24 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 25 | "digit": "0123456789", 26 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 27 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", 28 | "true": true, 29 | "false": false, 30 | "null": null, 31 | "array":[ ], 32 | "object":{ }, 33 | "address": "50 St. James Street", 34 | "url": "http://www.JSON.org/", 35 | "comment": "// /* */": " ", 37 | " s p a c e d " :[1,2 , 3 38 | 39 | , 40 | 41 | 4 , 5 , 6 ,7 ], 42 | "compact": [1,2,3,4,5,6,7], 43 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 44 | "quotes": "" \u0022 %22 0x22 034 "", 45 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" 46 | : "A key can be any string" 47 | }, 48 | 0.5 ,98.6 49 | , 50 | 99.44 51 | , 52 | 53 | 1066 54 | 55 | 56 | ,"rosebud"] -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass2.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /spec/parsing/fixtures/pass3.json: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": { 3 | "The outermost value": "must be an object or array.", 4 | "In this test": "It is an object." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /spec/parsing/fixtures_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | 3 | describe "Parsing JSON Fixtures" do 4 | fixtures = File.join(File.dirname(__FILE__), 'fixtures/*.json') 5 | passed, failed = Dir[fixtures].partition { |f| f['pass'] } 6 | PASSED = passed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort 7 | FAILED = failed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort 8 | 9 | FAILED.each do |name, source| 10 | it "should not be able to parse #{File.basename(name)} as an IO" do 11 | expect { 12 | Yajl::Parser.parse(StringIO.new(source)) 13 | }.to raise_error(Yajl::ParseError) 14 | end 15 | end 16 | 17 | FAILED.each do |name, source| 18 | it "should not be able to parse #{File.basename(name)} as a string" do 19 | expect { 20 | Yajl::Parser.parse(source) 21 | }.to raise_error(Yajl::ParseError) 22 | end 23 | end 24 | 25 | PASSED.each do |name, source| 26 | it "should be able to parse #{File.basename(name)} as an IO" do 27 | expect { 28 | Yajl::Parser.parse(StringIO.new(source)) 29 | }.not_to raise_error 30 | end 31 | end 32 | 33 | PASSED.each do |name, source| 34 | it "should be able to parse #{File.basename(name)} as a string" do 35 | expect { 36 | Yajl::Parser.parse(source) 37 | }.not_to raise_error 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/parsing/large_number_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Parsing very long text' do 4 | shared_examples 'running script successfully' do |script| 5 | def dup_pipe(parent_half, child_half, new_io) 6 | parent_half.close 7 | new_io.reopen(child_half) 8 | child_half.close 9 | end 10 | 11 | def capture(cmd, stdin_data) 12 | child_in, child_out, child_err = IO::pipe, IO::pipe, IO::pipe 13 | 14 | child_pid = fork do 15 | dup_pipe(child_in[1], child_in[0], STDIN) 16 | dup_pipe(child_out[0], child_out[1], STDOUT) 17 | dup_pipe(child_err[0], child_err[1], STDERR) 18 | 19 | exec(cmd) 20 | end 21 | 22 | [ 23 | child_in[0], 24 | child_out[1], 25 | child_err[1], 26 | ].each(&:close) 27 | 28 | child_in[1].write(stdin_data) 29 | child_in[1].close 30 | _, status = Process.waitpid2(child_pid) 31 | 32 | return child_out[0].read, child_err[0].read, status 33 | ensure 34 | [ 35 | child_in[1], 36 | child_out[0], 37 | child_err[0], 38 | ].reject(&:closed?).each(&:close) 39 | end 40 | 41 | it 'runs successfully' do 42 | out, err, status = capture('ruby', script) 43 | expect([err, status.exitstatus]).to eq(['', 0]) 44 | end 45 | end 46 | 47 | context 'when parseing big floats' do 48 | include_examples('running script successfully', <<-EOS) 49 | require "yajl" 50 | Yajl::Parser.parse('[0.' + '1' * 2**23 + ']') 51 | EOS 52 | end 53 | 54 | context 'when parseing long hash key with symbolize_keys option' do 55 | include_examples('running script successfully', <<-EOS) 56 | require "yajl" 57 | Yajl::Parser.parse('{"' + 'a' * 2**23 + '": 0}', :symbolize_keys => true) 58 | EOS 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/parsing/one_off_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 3 | 4 | describe "One-off JSON examples" do 5 | it "should not blow up with a bad surrogate trailer" do 6 | # https://github.com/brianmario/yajl-ruby/issues/176 7 | bad_json = "{\"e\":{\"\\uD800\\\\DC00\":\"a\"}}" 8 | 9 | Yajl::Parser.new.parse(bad_json) 10 | end 11 | 12 | it "should parse 23456789012E666 and return Infinity" do 13 | infinity = (1.0/0) 14 | silence_warnings do 15 | expect(Yajl::Parser.parse(StringIO.new('{"key": 23456789012E666}'))).to eq({"key" => infinity}) 16 | end 17 | end 18 | 19 | it "should not parse JSON with a comment, with :allow_comments set to false" do 20 | json = StringIO.new('{"key": /* this is a comment */ "value"}') 21 | expect { 22 | Yajl::Parser.parse(json, :allow_comments => false) 23 | }.to raise_error(Yajl::ParseError) 24 | end 25 | 26 | it "should parse JSON with a comment, with :allow_comments set to true" do 27 | json = StringIO.new('{"key": /* this is a comment */ "value"}') 28 | expect { 29 | Yajl::Parser.parse(json, :allow_comments => true) 30 | }.not_to raise_error 31 | end 32 | 33 | it "should not parse invalid UTF8 with :check_utf8 set to true" do 34 | parser = Yajl::Parser.new(:check_utf8 => true) 35 | expect { 36 | parser.parse("[\"#{"\201\203"}\"]") 37 | }.to raise_error(Yajl::ParseError) 38 | end 39 | 40 | it "should parse invalid UTF8 with :check_utf8 set to false" do 41 | parser = Yajl::Parser.new(:check_utf8 => false) 42 | parser.parse("[\"#{"\201\203"}\"]").inspect 43 | end 44 | 45 | it "should parse using it's class method, from an IO" do 46 | io = StringIO.new('{"key": 1234}') 47 | expect(Yajl::Parser.parse(io)).to eq({"key" => 1234}) 48 | end 49 | 50 | it "should parse using it's class method, from a string with symbolized keys" do 51 | expect(Yajl::Parser.parse('{"key": 1234}', :symbolize_keys => true)).to eq({:key => 1234}) 52 | end 53 | 54 | it "should parse using it's class method, from a utf-8 string with multibyte characters, with symbolized keys" do 55 | expect(Yajl::Parser.parse('{"日本語": 1234}', :symbolize_keys => true)).to eq({:"日本語" => 1234}) 56 | end 57 | 58 | it "should parse using it's class method, from a string" do 59 | expect(Yajl::Parser.parse('{"key": 1234}')).to eq({"key" => 1234}) 60 | end 61 | 62 | it "should parse using it's class method, from a string with a block" do 63 | output = nil 64 | Yajl::Parser.parse('{"key": 1234}') do |obj| 65 | output = obj 66 | end 67 | expect(output).to eq({"key" => 1234}) 68 | end 69 | 70 | it "should parse numbers greater than 2,147,483,648" do 71 | expect(Yajl::Parser.parse("{\"id\": 2147483649}")).to eql({"id" => 2147483649}) 72 | expect(Yajl::Parser.parse("{\"id\": 5687389800}")).to eql({"id" => 5687389800}) 73 | expect(Yajl::Parser.parse("{\"id\": 1046289770033519442869495707521600000000}")).to eql({"id" => 1046289770033519442869495707521600000000}) 74 | end 75 | 76 | if RUBY_VERSION =~ /^1.9/ 77 | it "should encode non-ascii symbols in utf-8" do 78 | parsed = Yajl::Parser.parse('{"曦": 1234}', :symbolize_keys => true) 79 | expect(parsed.keys.fetch(0).encoding).to eq(Encoding::UTF_8) 80 | end 81 | 82 | it "should return strings and hash keys in utf-8 if Encoding.default_internal is nil" do 83 | Encoding.default_internal = nil 84 | expect(Yajl::Parser.parse('{"key": "value"}').keys.first.encoding).to eql(Encoding.find('utf-8')) 85 | expect(Yajl::Parser.parse('{"key": "value"}').values.first.encoding).to eql(Encoding.find('utf-8')) 86 | end 87 | 88 | it "should return strings and hash keys encoded as specified in Encoding.default_internal if it's set" do 89 | Encoding.default_internal = Encoding.find('utf-8') 90 | expect(Yajl::Parser.parse('{"key": "value"}').keys.first.encoding).to eql(Encoding.default_internal) 91 | expect(Yajl::Parser.parse('{"key": "value"}').values.first.encoding).to eql(Encoding.default_internal) 92 | Encoding.default_internal = Encoding.find('us-ascii') 93 | expect(Yajl::Parser.parse('{"key": "value"}').keys.first.encoding).to eql(Encoding.default_internal) 94 | expect(Yajl::Parser.parse('{"key": "value"}').values.first.encoding).to eql(Encoding.default_internal) 95 | end 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /spec/projection/project_file.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') 2 | 3 | require 'benchmark' 4 | require 'benchmark/memory' 5 | 6 | describe "file projection" do 7 | it "projects file streams" do 8 | schema = { 9 | "forced" => nil, 10 | "created" => nil, 11 | "pusher" => { 12 | "name" => nil, 13 | }, 14 | "repository" => { 15 | "name" => nil, 16 | "full_name" => nil, 17 | }, 18 | "ref" => nil, 19 | "compare" => nil, 20 | "commits" => { 21 | "distinct" => nil, 22 | "message" => nil, 23 | "url" => nil, 24 | "id" => nil, 25 | "author" => { 26 | "username" => nil, 27 | } 28 | } 29 | } 30 | 31 | file_path = ENV['JSON_FILE'] 32 | if file_path.nil? || file_path.empty? 33 | return 34 | end 35 | 36 | Benchmark.memory { |x| 37 | x.report("project (yajl)") { Yajl::Projector.new(File.open(file_path, 'r')).project(schema) } 38 | x.compare! 39 | } 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/rcov.opts: -------------------------------------------------------------------------------- 1 | --exclude spec,gem 2 | --text-summary 3 | --sort coverage --sort-reverse 4 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'yajl' 3 | require 'date' 4 | require 'stringio' 5 | 6 | module Kernel 7 | def silence_warnings 8 | old_verbose, $VERBOSE = $VERBOSE, nil 9 | yield 10 | ensure 11 | $VERBOSE = old_verbose 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /tasks/compile.rake: -------------------------------------------------------------------------------- 1 | require 'rake/extensiontask' 2 | 3 | def gemspec 4 | @clean_gemspec ||= eval(File.read(File.expand_path('../../yajl-ruby.gemspec', __FILE__))) 5 | end 6 | 7 | Rake::ExtensionTask.new('yajl', gemspec) do |ext| 8 | # automatically add build options to avoid need of manual input 9 | ext.cross_compile = true 10 | ext.cross_platform = ['x86-mingw32', 'x86-mswin32-60'] 11 | 12 | # inject 1.8/1.9 pure-ruby entry point when cross compiling only 13 | ext.cross_compiling do |spec| 14 | spec.files << 'lib/yajl/yajl.rb' 15 | end 16 | 17 | ext.lib_dir = File.join 'lib', 'yajl' 18 | 19 | # clean compiled extension 20 | CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}" 21 | end 22 | Rake::Task[:spec].prerequisites << :compile 23 | 24 | file 'lib/yajl/yajl.rb' do |t| 25 | File.open(t.name, 'wb') do |f| 26 | f.write <<-eoruby 27 | RUBY_VERSION =~ /(\\d+.\\d+)/ 28 | require "yajl/\#{$1}/yajl" 29 | eoruby 30 | end 31 | end 32 | 33 | if Rake::Task.task_defined?(:cross) 34 | Rake::Task[:cross].prerequisites << 'lib/yajl/yajl.rb' 35 | end 36 | -------------------------------------------------------------------------------- /tasks/rspec.rake: -------------------------------------------------------------------------------- 1 | begin 2 | require 'rspec' 3 | require 'rspec/core/rake_task' 4 | 5 | desc "Run all examples with RCov" 6 | RSpec::Core::RakeTask.new('spec:rcov') do |t| 7 | t.rcov = true 8 | end 9 | RSpec::Core::RakeTask.new('spec') do |t| 10 | t.verbose = true 11 | end 12 | 13 | task :default => :spec 14 | rescue LoadError 15 | puts "rspec, or one of its dependencies, is not available. Install it with: sudo gem install rspec" 16 | end 17 | -------------------------------------------------------------------------------- /yajl-ruby.gemspec: -------------------------------------------------------------------------------- 1 | require './lib/yajl/version' 2 | 3 | Gem::Specification.new do |s| 4 | s.name = %q{yajl-ruby} 5 | s.version = Yajl::VERSION 6 | s.license = "MIT" 7 | s.authors = ["Brian Lopez", "Lloyd Hilaiel"] 8 | s.email = %q{seniorlopez@gmail.com} 9 | s.extensions = ["ext/yajl/extconf.rb"] 10 | s.files = `git ls-files`.split("\n") 11 | s.homepage = %q{https://github.com/brianmario/yajl-ruby} 12 | s.require_paths = ["lib"] 13 | s.summary = %q{Ruby C bindings to the excellent Yajl JSON stream-based parser library.} 14 | s.required_ruby_version = ">= 2.6.0" 15 | 16 | # tests 17 | s.add_development_dependency 'rake-compiler' 18 | s.add_development_dependency 'rspec' 19 | # benchmarks 20 | s.add_development_dependency 'activesupport' 21 | s.add_development_dependency 'json' 22 | s.add_development_dependency "benchmark-memory" 23 | end 24 | --------------------------------------------------------------------------------