Giter Club home page Giter Club logo

yajl-ruby's Introduction

YAJL C Bindings for Ruby

This gem is a C binding to the excellent YAJL JSON parsing and generation library.

You can read more info at the project's website http://lloyd.github.com/yajl or check out its code at http://github.com/lloyd/yajl.

Features

  • JSON parsing and encoding directly to and from an IO stream (file, socket, etc) or String. Compressed stream parsing and encoding supported for Bzip2, Gzip and Deflate.
  • Parse and encode multiple JSON objects to and from streams or strings continuously.
  • JSON gem compatibility API - allows yajl-ruby to be used as a drop-in replacement for the JSON gem
  • Basic HTTP client (only GET requests supported for now) which parses JSON directly off the response body as it's being received
  • ~3.5x faster than JSON.generate
  • ~1.9x faster than JSON.parse
  • ~4.5x faster than YAML.load
  • ~377.5x faster than YAML.dump
  • ~1.5x faster than Marshal.load
  • ~2x faster than Marshal.dump

How to install

Go ahead and install it as usual:

gem install yajl-ruby

Or use your Gemfile:

gem 'yajl-ruby', require: 'yajl'

Example of use

NOTE: I'm building up a collection of small examples in the examples (http://github.com/brianmario/yajl-ruby/tree/master/examples) folder.

First, you're probably gonna want to require it:

require 'yajl'

Parsing

Then maybe parse some JSON from:

a File IO

json = File.new('test.json', 'r')
parser = Yajl::Parser.new
hash = parser.parse(json)

or maybe a StringIO

json = StringIO.new("...some JSON...")
parser = Yajl::Parser.new
hash = parser.parse(json)

or maybe STDIN

cat someJsonFile.json | ruby -ryajl -e "puts Yajl::Parser.parse(STDIN).inspect"

Or lets say you didn't have access to the IO object that contained JSON data, but instead only had access to chunks of it at a time. No problem!

(Assume we're in an EventMachine::Connection instance)

def post_init
  @parser = Yajl::Parser.new(:symbolize_keys => true)
end

def object_parsed(obj)
  puts "Sometimes one pays most for the things one gets for nothing. - Albert Einstein"
  puts obj.inspect
end

def connection_completed
  # once a full JSON object has been parsed from the stream
  # object_parsed will be called, and passed the constructed object
  @parser.on_parse_complete = method(:object_parsed)
end

def receive_data(data)
  # continue passing chunks
  @parser << data
end

Or if you don't need to stream it, it'll just return the built object from the parse when it's done. NOTE: if there are going to be multiple JSON strings in the input, you must specify a block or callback as this is how yajl-ruby will hand you (the caller) each object as it's parsed off the input.

obj = Yajl::Parser.parse(str_or_io)

Or how about a JSON API HTTP request? This actually makes a request using a raw TCPSocket, then parses the JSON body right off the socket. While it's being received over the wire!

require 'uri'
require 'yajl/http_stream'

url = URI.parse("http://search.twitter.com/search.json?q=engineyard")
results = Yajl::HttpStream.get(url)

Or do the same request, with Gzip and Deflate output compression support (also supports Bzip2, if loaded): (this does the same raw socket Request, but transparently parses the compressed response body)

require 'uri'
require 'yajl/gzip'
require 'yajl/deflate'
require 'yajl/http_stream'

url = URI.parse("http://search.twitter.com/search.json?q=engineyard")
results = Yajl::HttpStream.get(url)

Since yajl-ruby parses JSON as a stream, supporting APIs like Twitter's Streaming API are a piece-of-cake. You can simply supply a block to Yajl::HttpStream.get, which is used as the callback for when a JSON object has been unserialized off the stream. For the case of this Twitter Streaming API call, the callback gets fired a few times a second (depending on your connection speed). The code below is all that's needed to make the request and stream unserialized Ruby hashes off the response, continuously. You'll note that I've enabled the :symbolize_keys parser option as well. Doing so is much more efficient for parsing JSON streams with lots of repetitive keys - for things like result sets or multiple API requests - than the same parse with string keys. This is because Ruby will reuse (and never GC) its symbol table. Be that as it may, if you want to parse JSON strings with random key names it's much better to leave string keys enabled (the default), so they can get GC'd later.

require 'uri'
require 'yajl/http_stream'

uri = URI.parse("http://#{username}:#{password}@stream.twitter.com/spritzer.json")
Yajl::HttpStream.get(uri, :symbolize_keys => true) do |hash|
  puts hash.inspect
end

Or how about parsing directly from a compressed file?

require 'yajl/bzip2'

file = File.new('some.json.bz2', 'r')
result = Yajl::Bzip2::StreamReader.parse(file)

Encoding

Since yajl-ruby does everything using streams, you simply need to pass the object to encode, and the IO to write the stream to (this happens in chunks).

This allows you to encode JSON as a stream, writing directly to a socket

socket = TCPSocket.new('192.168.1.101', 9000)
hash = {:foo => 12425125, :bar => "some string", ... }
Yajl::Encoder.encode(hash, socket)

Or what if you wanted to compress the stream over the wire?

require 'yajl/gzip'
socket = TCPSocket.new('192.168.1.101', 9000)
hash = {:foo => 12425125, :bar => "some string", ... }
Yajl::Gzip::StreamWriter.encode(hash, socket)

Or what about encoding multiple objects to JSON over the same stream? This example will encode and send 50 JSON objects over the same stream, continuously.

socket = TCPSocket.new('192.168.1.101', 9000)
encoder = Yajl::Encoder.new
50.times do
  hash = {:current_time => Time.now.to_f, :foo => 12425125}
  encoder.encode(hash, socket)
end

Using EventMachine and you want to encode and send in chunks? (Assume we're in an EventMachine::Connection instance)

def post_init
   # Passing a :terminator character will let us determine when the encoder
   # is done encoding the current object
   @encoder = Yajl::Encoder.new
   motd_contents = File.read("/path/to/motd.txt")
   status = File.read("/path/to/huge/status_file.txt")
   @motd = {:motd => motd_contents, :system_status => status}
end

def connection_completed
  # The encoder will do its best to hand you data in chunks that
  # are around 8kb (but you may see some that are larger)
  #
  # It should be noted that you could have also assigned the _on_progress_ callback
  # much like you can assign the _on_parse_complete_ callback with the parser class.
  # Passing a block (like below) essentially tells the encoder to use that block
  # as the callback normally assigned to _on_progress_.
  #
  # Send our MOTD and status
  @encoder.encode(@motd) do |chunk|
    if chunk.nil? # got our terminator, encoding is done
      close_connection_after_writing
    else
      send_data(chunk)
    end
  end
end

But to make things simple, you might just want to let yajl-ruby do all the hard work for you and just hand back a string when it's finished. In that case, just don't provide and IO or block (or assign the on_progress callback).

str = Yajl::Encoder.encode(obj)

You can also use Yajl::Bzip2::StreamWriter and Yajl::Deflate::StreamWriter. So you can pick whichever fits your CPU/bandwidth sweet-spot.

HTML Safety

If you plan on embedding the output from the encoder in the DOM, you'll want to make sure you use the html_safe option on the encoder. This will escape all '/' characters to ensure no closing tags can be injected, preventing XSS.

Meaning the following should be perfectly safe:

<script type="text/javascript">
  var escaped_str = <%= Yajl::Encoder.encode("</script><script>alert('hi!');</script>", :html_safe => true) %>;
</script>

JSON gem Compatibility API

The JSON gem compatibility API isn't enabled by default. You have to explicitly require it like so:

require 'yajl/json_gem'

That's right, you can just replace "require 'json'" with the line above and you're done!

This will require yajl-ruby itself, as well as enable its JSON gem compatibility API.

This includes the following API:

JSON.parse, JSON.generate, JSON.pretty_generate, JSON.load, JSON.dump and all of the #to_json instance method overrides for Ruby's primitive objects

Once the compatibility API is enabled, your existing or new project should work as if the JSON gem itself were being used. Only you'll be using Yajl ;)

There are a lot more possibilities that I'd love to see other gems/plugins for someday.

Some ideas:

Benchmarks

After I finished implementation - this library performs close to the same as the current JSON.parse (C gem) does on small/medium files.

But on larger files, and higher amounts of iteration, this library was around 2x faster than JSON.parse.

The main benefit of this library is in its memory usage. Since it's able to parse the stream in chunks, its memory requirements are very, very low.

Here's what parsing a 2.43MB JSON file off the filesystem 20 times looks like:

Memory Usage

Average

  • Yajl::Parser#parse: 32MB
  • JSON.parse: 54MB
  • ActiveSupport::JSON.decode: 63MB

Peak

  • Yajl::Parser#parse: 32MB
  • JSON.parse: 57MB
  • ActiveSupport::JSON.decode: 67MB

Parse Time

  • Yajl::Parser#parse: 4.54s
  • JSON.parse: 5.47s
  • ActiveSupport::JSON.decode: 64.42s

Encode Time

  • Yajl::Encoder#encode: 3.59s
  • JSON#to_json: 6.2s
  • ActiveSupport::JSON.encode: 45.58s

Compared to YAML

NOTE: I converted the 2.4MB JSON file to YAML for this test.

Parse Time (from their respective formats)

  • Yajl::Parser#parse: 4.33s
  • JSON.parse: 5.37s
  • YAML.load: 19.47s

Encode Time (to their respective formats)

  • Yajl::Encoder#encode: 3.47s
  • JSON#to_json: 6.6s
  • YAML.dump(obj, io): 1309.93s

Compared to Marshal.load/Marshal.dump

NOTE: I converted the 2.4MB JSON file to a Hash and a dump file from Marshal.dump for this test.

Parse Time (from their respective formats)

  • Yajl::Parser#parse: 4.54s
  • JSON.parse: 7.40s
  • Marshal.load: 7s

Encode Time (to their respective formats)

  • Yajl::Encoder#encode: 2.39s
  • JSON#to_json: 8.37s
  • Marshal.dump: 4.66s

Third Party Sources Bundled

This project includes code from the BSD licensed yajl project, copyright 2007-2009 Lloyd Hilaiel

Special Thanks & Contributors

For those of you using yajl-ruby out in the wild, please hit me up on Twitter (brianmario) or send me a message here on the Githubs describing the site and how you're using it. I'd love to get a list going!

I've had a lot of inspiration, and a lot of help. Thanks to everyone who's been a part of this and those to come!

  • Lloyd Hilaiel - http://github.com/lloyd - for writing Yajl!!
  • Josh Ferguson - http://github.com/besquared - for peer-pressuring me into getting back into C; it worked ;) Also tons of support over IM
  • Jonathan Novak - http://github.com/cypriss - pointer-hacking help
  • Tom Smith - http://github.com/rtomsmith - pointer-hacking help
  • Rick Olson - http://github.com/technoweenie - for making an ActiveSupport patch with support for this library and teasing me that it might go into Rails 3. You sure lit a fire under my ass and I got a ton of work done because of it! :)
  • The entire Github Crew - http://github.com/ - my inspiration, time spent writing this, finding Yajl, So many-MANY other things wouldn't have been possible without this awesome service. I owe you guys some whiskey at Kilowatt.
  • Ben Burkert - http://github.com/benburkert
  • Aman Gupta - http://github.com/tmm1 - tons of suggestions and inspiration for the most recent features, and hopefully more to come ;)
  • Filipe Giusti
  • Jonathan George
  • Luke Redpath
  • Neil Berkman
  • Pavel Valodzka
  • Rob Sharp

yajl-ruby's People

Contributors

avsej avatar benweint avatar brianmario avatar conradirwin avatar coolo avatar d avatar eileencodes avatar filipegiusti avatar flameeyes avatar fxn avatar ganmacs avatar hsbt avatar jdg avatar jhawthorn avatar keithduncan avatar koic avatar lloyd avatar mishina2228 avatar nfo avatar pbanos avatar qnm avatar sferik avatar shwoodard avatar srushti avatar technoweenie avatar tenderlove avatar timcraft avatar timfel avatar timgates42 avatar vandrijevik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yajl-ruby's Issues

Could it be a memory leak issue?

yajl-ruby is called in our system for several thousand times with "valgrind" tracking memory issue, then got the following memory leak info. Could it be a memory leak issue?
We are using latest 0.78 version. Ruby 1.8.7 p302

==14699== 153,192 bytes in 982 blocks are definitely lost in loss record 15,308 of 15,316

==14699== at 0x4027020: malloc (vg_replace_malloc.c:236)

==14699== by 0x56912BC: yajl_internal_malloc (yajl_alloc.c:44)

==14699== by 0x56936E9: yajl_render_error_string (yajl_parser.c:113)

==14699== by 0x568DEC1: yajl_get_error (yajl.c:146)

==14699== by 0x568EC26: yajl_parse_chunk (yajl_ext.c:222)

==14699== by 0x568FBFD: rb_yajl_parser_parse (yajl_ext.c:450)

==14699== by 0x8057D2C: call_cfunc (eval.c:5778)

==14699== by 0x8061BFB: rb_call0 (eval.c:5928)

==14699== by 0x8061D88: rb_call (eval.c:6176)

==14699== by 0x805F411: rb_eval (eval.c:3506)

==14699== by 0x806AD1A: block_pass (eval.c:9193)

==14699== by 0x805D517: rb_eval (eval.c:3222)

==14699== by 0x8061ACD: rb_call0 (eval.c:6079)

==14699== by 0x8061D88: rb_call (eval.c:6176)

==14699== by 0x805F411: rb_eval (eval.c:3506)
==14699==


==14699== LEAK SUMMARY:

==14699== definitely lost: 153,192 bytes in 982 blocks

==14699== indirectly lost: 0 bytes in 0 blocks

==14699== possibly lost: 22,504 bytes in 933 blocks

==14699== still reachable: 9,829,826 bytes in 136,397 blocks

==14699== suppressed: 0 bytes in 0 blocks

==14699== Reachable blocks (those to which a pointer was found) are not shown.

==14699== To see them, rerun with: --leak-check=full --show-reachable=yes

Ubuntu 32 Bit Segfault when encoding a BigDecimal

I seem to get the following error whenever i try to encode any Ruby object that has a BigDecimal attribute in it.

SystemStackError: stack level too deep
from /usr/lib/ruby/gems/1.8/gems/yajl-ruby-0.7.5/lib/yajl.rb:75:in encode' from /usr/lib/ruby/gems/1.8/gems/yajl-ruby-0.7.5/lib/yajl.rb:75:inencode'
from (irb):16

I looked into the c code and dont see that it supports BigDecimal conversion, but only BigNum conversion. Is that the issue?

Kiran

Decimals are converted to strings in 0.7.1

This is pretty strange. Im encoding objects in rails to json. With 0.7.0 decimal fields are converted correctly to 12.1245 but with 0.7.1 they are converted to strings.

yajl/json_gem & json conflict in ohai+chef

With this commit to ohai: http://github.com/opscode/ohai/commit/f89baccc3b9ab587d23e0b6257f6fedffe223c02

However, if you remove 'json, 'json_pure', then run 'rake spec' from another project [chef] that requires ohai (HAS NOT BEEN SWITCHED TO YAJL YET):

aj@AJ-Christensens-MacBook (branch: master) ~/Development/chef/chef$ rake spec
(in /Users/aj/Development/chef/chef) /Users/aj/.gem/ruby/1.8/gems/yajl-ruby-0.6.3/lib/yajl/json_gem/parsing.rb:5: superclass mismatch for class ParserError (TypeError)
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from /Users/aj/.gem/ruby/1.8/gems/yajl-ruby-0.6.3/lib/yajl/json_gem.rb:3
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
from /opt/local/lib/ruby/gems/1.8/gems/ohai-0.3.4/lib/ohai/system.rb:27
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from /opt/local/lib/ruby/gems/1.8/gems/ohai-0.3.4/lib/ohai.rb:23
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
from /Users/aj/Development/chef/chef/spec/../lib/chef/client.rb:31
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from /Users/aj/Development/chef/chef/spec/../lib/chef/application/client.rb:19
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from /Users/aj/Development/chef/chef/spec/spec_helper.rb:34
from /Users/aj/Development/chef/chef/spec/spec_helper.rb:26:in `each'
from /Users/aj/Development/chef/chef/spec/spec_helper.rb:26
from ./spec/unit/client_spec.rb:19:in `require'
from ./spec/unit/client_spec.rb:19

Any ideas? chef project ticket ref# http://tickets.opscode.com/browse/CHEF-592

Changing the require to straight up 'yajl' supposedly works, although I haven't verified this.

0.5.11 Encoding of objects is really broken now

in 0.5.10 it was doube quoting Time.now all other objects seemed to be ok

in 0.5.11 it is only encoding strings
p obj
#<Znq::Dm::Fee id=7 fee_group_id=2 name="Setup" finance_fee=true private=false value_string=nil value_decimal=#BigDecimal:7f3cc5329728,'0.35E3',9(18) display=nil explanation=>
p obj.to_json # Yajl 0.5.11
"{ id: 7, fee_group_id: 2, name: "Setup", finance_fee: true, private: false, value_string: null, value_decimal: 0.35E3, display: null, explanation: null }"
p obj.to_json # Json 1.1.6
"{ "id": 7, "fee_group_id": 2, "name": "Setup", "finance_fee": true, "private": false, "value_string": null, "value_decimal": "0.35E3", "display": null, "explanation": null }"

encoding ActiveSupport::JSON::Variable

Hello Brian!

We encode json strings which have javascript variable names in them ( or other arbitrary code). consider the following:

require 'json
command_name = ActiveSupport::JSON::Variable.new("alert('new')")
JSON.generate({'command'=>command_name})
=> "{"command":alert('new')}"

while

Yajl::Encoder.encode({'command'=>command_name})
=> "{"command":"alert('new')"}"

Notice the extra "" around the Variable ? It does not look like Yajl-ruby supports ActiveSupport::JSON::Variable. Is this correct?

Thanks
Eric Smith

Strange issue when parsing Campfire's JSON stream

I wish I could provide more than an example that highlights the failure, but I'm not sure what exactly is breaking here. In short, while parsing Campfire's JSON Stream, if I follow the provided example everything works fine. However, if I tweet the information using the Twitter gem, the tweet succeeds but streaming discontinues and can't be started up again.

Here's the gist:
http://gist.github.com/285370

To test, fill in the appropriate Campfire and Twitter info. Proceed your message with @test to have the script attempt to tweet the campfire message; after it does so streaming will cease.

Encoding a Date or Time using yajl-ruby (0.6.1) causes double quoting (using Rails 2.3.2)

Steps to reproduce (for Dates)
1.) Create new Rails project called 'grr'
2.) Inside the project, run the following commands

require 'yajl'
a_date = Date.parse("2001-10-08") #=> Mon, 08 Oct 2001
Yajl::Encoder.encode(a_date) #=> ""\"2001-10-08\"""
a_date.to_json #=> ""2001-10-08""

Description:
I noticed that in a comment on another ruby-yajl bug at http://github.com/brianmario/yajl-ruby/issues#issue/3/comment/40297 that for Dates and Times the encoder should fall back to calling to_json. From the above output it seems that this is not the case

Also affects Times:
Yajl::Encoder.encode(Time.now) #=> ""\"2009-08-25T17:08:54+01:00\"""
Time.now.to_json => ""2009-08-25T17:09:05+01:00""

Possible solution
1.) Calling to_s before to_json seems to give better output
Yajl::Encoder.encode(a_date.to_s) => ""2001-10-08""
2.) However this may be a bit of a hack!
3.) Will not work for Times

Thanks again for writing yajl-ruby. It kicks ass!

Please clarify "encode and send in chunks"

Hi, the example in the README file about "Using EventMachine and you want to encode and send in chunks?" is as follows:

def post_init
    # Passing a :terminator character will let us determine when the encoder
    # is done encoding the current object
    @encoder = Yajl::Encoder.new
    motd_contents = File.read("/path/to/motd.txt")
    status = File.read("/path/to/huge/status_file.txt")
    @motd = {:motd => motd_contents, :system_status => status}
end

def connection_completed
   # The encoder will do its best to hand you data in chunks that
   # are around 8kb (but you may see some that are larger)
   #
   # It should be noted that you could have also assigned the _on_progress_ callback
   # much like you can assign the _on_parse_complete_ callback with the parser class.
   # Passing a block (like below) essentially tells the encoder to use that block
   # as the callback normally assigned to _on_progress_.
   #
   # Send our MOTD and status
   @encoder.encode(@motd) do |chunk|
     if chunk.nil? # got our terminator, encoding is done
       close_connection_after_writing
     else
       send_data(chunk)
     end
   end
 end

I've tryed it and 'chunk' is never nil. And I get chunks of 17kb rather than 8kb. Neither I understand what ":terminator character" means or where it appears in this example.

Thanks for any clarification. Cheers.

PS: Awesome library!

Strange behaviour with buffer size

Parsing code (big json file):

j = Yajl::Parser.new(:check_utf8 => false)
data = j.parse(File.new(@report_path, 'r'), BUFFER_SIZE)

On windows: works when buffer size 0x5000, when it 0x10000 -

 loader.rb:339: [BUG] Segmentation fault

On linux: works when buffer size 0x10000, when it 0x100000 -

 loader.rb:339:in `parse': lexical error: invalid character inside string. (Yajl::ParseError)
 name":"2",                     (right here) ------^

PS:
I've investigated more, behaviour is different for different files but general problem still remains - it has unpredictable behaviour for bigger buffer size

Windows:

ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mingw32]
yajl-ruby (0.7.4)
gcc version 3.4.5 (mingw-vista special r3)

Linux:

ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-linux], MBARI 0x8770, Ruby Enterprise Edition 2009.10
yajl-ruby (0.7.4)
gcc version 4.3.2 (Debian 4.3.2-1.1)

Ruby 1.9.2-p0 compatibility

Running tests in project wich use twitter gem (depend on yajl).
rake test
(in /Users/snowak/Documents/Workspace/szuflada/socialist)
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/yajl-ruby-0.7.7/lib/yajl_ext.bundle:
[BUG] Segmentation fault
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-darwin10.4.0]

-- control frame ----------
c:0046 p:-541640026 s:0150 b:0150 l:000149 d:000149 TOP
c:0045 p:---- s:0148 b:0148 l:000147 d:000147 CFUNC :require
c:0044 p:0012 s:0144 b:0144 l:000127 d:000143 BLOCK
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219
c:0043 p:0005 s:0142 b:0142 l:000132 d:000141 BLOCK
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:205
c:0042 p:0046 s:0140 b:0140 l:000139 d:000139 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:570
c:0041 p:0041 s:0133 b:0133 l:000132 d:000132 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:205
c:0040 p:0013 s:0128 b:0128 l:000127 d:000127 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219
c:0039 p:0011 s:0123 b:0123 l:000122 d:000122 TOP
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/yajl-ruby-0.7.7/lib/yajl.rb:2
c:0038 p:---- s:0121 b:0121 l:000120 d:000120 FINISH
c:0037 p:---- s:0119 b:0119 l:000118 d:000118 CFUNC :require
c:0036 p:0012 s:0115 b:0115 l:000098 d:000114 BLOCK
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219
c:0035 p:0005 s:0113 b:0113 l:000103 d:000112 BLOCK
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:205
c:0034 p:0046 s:0111 b:0111 l:000110 d:000110 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:570
c:0033 p:0041 s:0104 b:0104 l:000103 d:000103 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:205
c:0032 p:0013 s:0099 b:0099 l:000098 d:000098 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219
c:0031 p:0059 s:0094 b:0094 l:000093 d:000093 TOP
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/twitter-0.9.8/lib/twitter.rb:5
c:0030 p:---- s:0091 b:0091 l:000090 d:000090 FINISH
c:0029 p:---- s:0089 b:0089 l:000088 d:000088 CFUNC :require
c:0028 p:0026 s:0085 b:0085 l:000066 d:000084 BLOCK
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:64
c:0027 p:---- s:0082 b:0082 l:000081 d:000081 FINISH
c:0026 p:---- s:0080 b:0080 l:000079 d:000079 CFUNC :each
c:0025 p:0091 s:0077 b:0077 l:000066 d:000076 BLOCK
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:62
c:0024 p:---- s:0072 b:0072 l:000071 d:000071 FINISH
c:0023 p:---- s:0070 b:0070 l:000069 d:000069 CFUNC :each
c:0022 p:0046 s:0067 b:0067 l:000066 d:000066 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:51
c:0021 p:0021 s:0063 b:0063 l:000062 d:000062 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler.rb:107
c:0020 p:0079 s:0059 b:0059 l:000058 d:000058 TOP
/Users/snowak/Documents/Workspace/szuflada/socialist/config/application.rb:7
c:0019 p:---- s:0057 b:0057 l:000056 d:000056 FINISH
c:0018 p:---- s:0055 b:0055 l:000054 d:000054 CFUNC :require
c:0017 p:0013 s:0051 b:0051 l:000050 d:000050 METHOD
internal:lib/rubygems/custom_require:29
c:0016 p:0026 s:0046 b:0046 l:000045 d:000045 TOP
/Users/snowak/Documents/Workspace/szuflada/socialist/Rakefile:4
c:0015 p:---- s:0044 b:0044 l:000043 d:000043 FINISH
c:0014 p:---- s:0042 b:0042 l:000041 d:000041 CFUNC :load
c:0013 p:0334 s:0038 b:0038 l:000037 d:000037 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2383
c:0012 p:0009 s:0033 b:0033 l:000026 d:000032 BLOCK
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2017
c:0011 p:0009 s:0031 b:0031 l:000030 d:000030 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2068
c:0010 p:0011 s:0027 b:0027 l:000026 d:000026 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2016
c:0009 p:0019 s:0024 b:0024 l:000017 d:000023 BLOCK
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2000
c:0008 p:0009 s:0022 b:0022 l:000021 d:000021 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2068
c:0007 p:0011 s:0018 b:0018 l:000017 d:000017 METHOD
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:1998
c:0006 p:0036 s:0015 b:0015 l:000014 d:000014 TOP
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/bin/rake:31
c:0005 p:---- s:0013 b:0013 l:000012 d:000012 FINISH
c:0004 p:---- s:0011 b:0011 l:000010 d:000010 CFUNC :load
c:0003 p:0127 s:0007 b:0007 l:001598 d:0009e0 EVAL
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/bin/rake:19
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH

c:0001 p:0000 s:0002 b:0002 l:001598 d:001598 TOP

-- Ruby level backtrace information ----------------------------------------
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/bin/rake:19:in <main>' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/bin/rake:19:inload'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/bin/rake:31:in
<top (required)>' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:1998:inrun'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2068:in
standard_exception_handling' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2000:in block in run'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2016:in
load_rakefile' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2068:in standard_exception_handling'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2017:in
block in load_rakefile' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2383:in raw_load_rakefile'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/rake-0.8.7/lib/rake.rb:2383:in load' /Users/snowak/Documents/Workspace/szuflada/socialist/Rakefile:4:in <top (required)>'
internal:lib/rubygems/custom_require:29:in require' <internal:lib/rubygems/custom_require>:29:inrequire'
/Users/snowak/Documents/Workspace/szuflada/socialist/config/application.rb:7:in
<top (required)>' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler.rb:107:in require'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:51:in
require' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:51:in each'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:62:in
block in require' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:62:in each'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:64:in
block (2 levels) in require' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/bundler-1.0.0.rc.5/lib/bundler/runtime.rb:64:in require'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/twitter-0.9.8/lib/twitter.rb:5:in
<top (required)>' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219:in require'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:205:in
load_dependency' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:570:in new_constants_in'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:205:in
block in load_dependency' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219:in block in require'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219:in
require' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/yajl-ruby-0.7.7/lib/yajl.rb:2:in <top (required)>'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219:in
require' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:205:in load_dependency'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:570:in
new_constants_in' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:205:in block in load_dependency'
/Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219:in
block in require' /Users/snowak/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc/lib/active_support/dependencies.rb:219:in require'

Works fine in 1.9.2-preview3

Expose parsing event callbacks to Ruby

It would be great if we could register callback blocks on a Yajl::Parser instance that would be called whenever an interesting parse event happens. I think the minimum set of event callbacks would be: start_document, end_document, start_object, end_object, start_array, end_array, key {|k| }, value {|value| }. I think only the key and value callbacks need to receive an argument.

With these callbacks in place, we can parse huge JSON documents incrementally without needing much memory. Huge JSON documents are rare, but some databases, like Apache CouchDB, use JSON to return map/reduce query results, which can potentially be quite large.

Parser callbacks

I've spent a few hours on this and I don't know enough about wiring Ruby to C to figure it out. I need to get yajl_end_map to be a ruby land callback with the Hash value so I can extend the hash with modules (depending on keys/values). Currently, I am having to recursively iterate lots of data in on_parse_complete with lots of arrays of embedded objects and such.

Thanks,

Troy

yajl-ruby/json_gem breaks ActiveSupport JSON encoder

$ rails new blog
# Add "gem yajl-ruby" to Gemfile
$ bundle install
$ rails generate scaffold posts title:string
$ rake db:migrate
$ rails console
> Post.create :title => 'hi'
> Post.create :title => 'yo'

> puts Post.all.to_json
[{"post":{"created_at":"2010-08-10T08:23:05Z","id":1,"title":"hi","updated_at":"2010-08-10T08:23:05Z"}},{"post":{"created_at":"2010-08-10T08:23:05Z","id":2,"title":"yo","updated_at":"2010-08-10T08:23:05Z"}}]

> require 'yajl/json_gem'
> puts Post.all.to_json
["#<Post:0x00000102a21e50>","#<Post:0x00000102a21bd0>"]

Noticed the problem because rest-graph requires 'yajl/json_gem'.

Error when placing the Gem Yajl-ruby in the vendor/gems

I get this error:
no such file to load -- yajl_ext

This only happens when i put it in my vendor/gems directory.

i have to put the gem in the vendor directory because my host does not have this gem installed.

Any ideas on how i can get past this?

Dumping a Date or Time fails

>> require 'yajl/json_gem'
=> true
>> JSON.dump(Time.now)
SystemStackError: stack level too deep
from /opt/local/lib/ruby/gems/1.8/gems/brianmario-yajl-ruby-0.5.7/lib/yajl.rb:62:in `to_json'
from /opt/local/lib/ruby/gems/1.8/gems/brianmario-yajl-ruby-0.5.7/lib/yajl.rb:62:in `encode'
from /opt/local/lib/ruby/gems/1.8/gems/brianmario-yajl-ruby-0.5.7/lib/yajl.rb:62:in `encode'
from /opt/local/lib/ruby/gems/1.8/gems/brianmario-yajl-ruby-0.5.7/lib/yajl/json_gem/encoding.rb:35:in `dump'
from (irb):2

yajl 0.6.7 incompatible with Twitter Streaming API

I recently upgraded to yajl 0.6.7 - it seems this version disconnects after receiving one result from the Twitter streaming API. Digging into some pcaps, it seems that version 0.6.4 sends a "Connection: close" in the HTTP request while 0.6.7 does not. (I haven't installed/tested anything in between.) This causes different behavior on Twitter's side.

When the "Connection: close" is not sent (0.6.7), Twitter sends a delimited response as mentioned in the API - I'm assuming this is short-circuiting yajl. When the "Connection: close" is sent in 0.6.4, Twitter returns a stream of json with no length delimiters.

rails 2.3.4

Hi
I have an application running rails 2.3.2. I try to upgrade it to 2.3.4 but I have an error in YAJL:

superclass mismatch for class ParserError
/Library/Ruby/Gems/1.8/gems/brianmario-yajl-ruby-0.6.3/lib/yajl/json_gem/parsing.rb:5

Any idea?
Thanks

extension library not installed under expected path

yajl.rb requires 'yajl/yajl' and with certain LOAD_PATHs when yajl-ruby is installed as a library rather than as a gem, Ruby can fail to find the extension.

$ irb
irb(main):001:0> require 'yajl'
LoadError: no such file to load -- yajl/yajl
    from /usr/lib/ruby/vendor_ruby/yajl.rb:2:in `require'
    from /usr/lib/ruby/vendor_ruby/yajl.rb:2
    from (irb):1:in `require'
    from (irb):1
    from :0
irb(main):002:0> quit
$ ruby -e 'puts $LOAD_PATH'
/usr/local/lib/site_ruby/1.8
/usr/local/lib/site_ruby/1.8/i686-linux
/usr/local/lib/site_ruby/1.8/i486-linux
/usr/local/lib/site_ruby
/usr/lib/ruby/vendor_ruby/1.8
/usr/lib/ruby/vendor_ruby/1.8/i686-linux
/usr/lib/ruby/vendor_ruby
/usr/lib/ruby/1.8
/usr/lib/ruby/1.8/i686-linux
/usr/lib/ruby/1.8/i486-linux
.
$ dpkg -c *i386.deb | grep '\.so'
-rw-r--r-- root/root     50884 2011-04-15 23:31 ./usr/lib/ruby/vendor_ruby/1.9.1/i686-linux/yajl.so
-rw-r--r-- root/root     46596 2011-04-15 23:31 ./usr/lib/ruby/vendor_ruby/1.8/i686-linux/yajl.so

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621500

Antonio Terceiro offers a patch to yajl-ruby that creates a working directory structure.

From 240afe9b14a886f14f48163251073f433406d730 Mon Sep 17 00:00:00 2001
From: Antonio Terceiro <[email protected]>
Date: Tue, 19 Apr 2011 21:19:27 -0700
Subject: [PATCH 1/2] Fix installation path of native extension

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621500

---
 ext/yajl/extconf.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/ext/yajl/extconf.rb b/ext/yajl/extconf.rb
index 9db2689..09edd51 100644
--- a/ext/yajl/extconf.rb
+++ b/ext/yajl/extconf.rb
@@ -5,4 +5,4 @@ require 'rbconfig'
 $CFLAGS << ' -Wall -funroll-loops'
 $CFLAGS << ' -Wextra -O0 -ggdb3' if ENV['DEBUG']

-create_makefile("yajl")
+create_makefile("yajl/yajl")
-- 
1.7.4.1

It appears to me that the gem may contain an extraneous copy of the extension, and thus change this does not actually affect it.

# Without patch
$ find /var/lib/gems/1.8/gems -name 'yajl.so'
/var/lib/gems/1.8/gems/yajl-ruby-0.8.2/ext/yajl/yajl.so
/var/lib/gems/1.8/gems/yajl-ruby-0.8.2/lib/yajl.so

# With patch
$ find /var/lib/gems/1.8/gems -name 'yajl.so'
/var/lib/gems/1.8/gems/yajl-ruby-0.8.2/ext/yajl/yajl.so
/var/lib/gems/1.8/gems/yajl-ruby-0.8.2/lib/yajl/yajl.so

"null" versus null versus nil

So encoding and decoding the same Ruby hash results in lossy encoding/decoding of nil/null values:

ree-1.8.7-2010.02 > f = Yajl::Parser.parse('{"p":1,"blah":null,"hello":"world"}')
=> {"p"=>1, "blah"=>nil, "hello"=>"world"}

ree-1.8.7-2010.02 > f.to_json
=> "{"p":1,"blah":"null","hello":"world"}"

ree-1.8.7-2010.02 > Yajl::Parser.parse(f.to_json)
=> {"p"=>1, "blah"=>"null", "hello"=>"world"}

Note that "blah" is originally Javascript null, though when run through the process, is converted into "null".

I'm running yajl-ruby 0.8.0

Encoding a Hash with symbol values using yajl-ruby (0.6.1) causes double quoting (using Rails 2.3.3)

Steps to reproduce (for Dates)
1.) Create new Rails project called 'grr' Inside the project, run the following commands

require 'yajl'
sym_hash = {:first_key => :first_value} #=> {:first_key=>:first_value}
Yajl::Encoder.encode(sym_hash) #=> "{"first_key":"\"first_value\""}"
sym_hash.to_json # => "{"first_key":"first_value"}"

Expected result:
Yajl::Encoder should not have double quoted the first_value

Inconsistencies for Ruby Mongo BSON::ObjectId (and possibly others)

Running into an issue with Yajl and turning Mongoid objects into JSON.

Yajl turns a record into:

"{\"_id\":{\"$oid\": \"4d583d682249c719f0000001\"},\"name\":\"dffdasdfsa\",\"restaurant_id\":{\"$oid\": \"4d54c08f2249c72588000005\"}}"

Where switching to the JSON gem produces:

"{\"_id\":\"4d583d682249c719f0000001\",\"name\":\"dffdasdfsa\",\"restaurant_id\":\"4d54c08f2249c72588000005\"}"

I'm not sure if this is an issue with Yajl or a problem with BSON::ObjectId, but since switching out Yajl seems to fix it then I'm assuming it's an inconsistency with how properties are serialized.

Any suggestions or thoughts? Thanks.

UTF-8 encoding problem

I have some text encoding problems when using Yajl. As you can see, my UTF-8 encoded text is not returned correctly:

# coding: utf-8
require 'yajl'

utlop = ["#utløp"]

puts utlop.inspect #=> ["#utløp"]
puts Yajl::Encoder.encode(utlop).inspect #=> "[\"#utl\xC3\xB8p\"]"
puts Yajl::Parser.parse(Yajl::Encoder.encode(utlop)).inspect #=> ["#utl\xC3\xB8p"]

I would expect the parser to return the same as the input to the encoding. Have I misunderstood something, or is there a bug in the library?

compile errors on Windows VC++

When I installed yajl-ruby-0.7.6, I got compile errors on Windows XP with Microsoft Visual Studio 2008 VC++.

I modified ext sources as below and succeed in compiling.

diff -Naur ext/yajl_ext.c yajl_ext/yajl_ext.c
--- ext/yajl_ext.c  2010-06-21 11:03:54.703125000 +0900
+++ yajl_ext/yajl_ext.c 2010-06-21 10:49:38.062500000 +0900
@@ -122,12 +122,13 @@
     }

     switch (TYPE(obj)) {
+        VALUE keys;
+        VALUE entry, keyStr;
         case T_HASH:
             status = yajl_gen_map_open(w->encoder);

             /* TODO: itterate through keys in the hash */
-            VALUE keys = rb_funcall(obj, intern_keys, 0);
-            VALUE entry, keyStr;
+            keys = rb_funcall(obj, intern_keys, 0);
             for(idx=0; idx<RARRAY_LEN(keys); idx++) {
                 entry = rb_ary_entry(keys, idx);
                 keyStr = rb_funcall(entry, intern_to_s, 0); /* key must be a string */
@@ -230,7 +231,7 @@
 }

 static int yajl_found_number(void * ctx, const char * numberVal, unsigned int numberLen) {
-    char buf[numberLen+1];
+    char *buf = (char *)malloc(numberLen+1);
     buf[numberLen] = 0;
     memcpy(buf, numberVal, numberLen);

@@ -241,6 +242,7 @@
     } else {
         yajl_set_static_value(ctx, rb_cstr2inum(buf, 10));
     }
+    free(buf);
     return 1;
 }

@@ -256,14 +258,15 @@

 static int yajl_found_hash_key(void * ctx, const unsigned char * stringVal, unsigned int stringLen) {
     yajl_parser_wrapper * wrapper;
-    GetParser((VALUE)ctx, wrapper);
     VALUE keyStr;
+    GetParser((VALUE)ctx, wrapper);

     if (wrapper->symbolizeKeys) {
-        char buf[stringLen+1];
+        char *buf = (char *)malloc(stringLen+1);
         memcpy(buf, stringVal, stringLen);
         buf[stringLen] = 0;
         yajl_set_static_value(ctx, ID2SYM(rb_intern(buf)));
+        free(buf);
     } else {
         keyStr = rb_str_new((const char *)stringVal, stringLen);
 #ifdef HAVE_RUBY_ENCODING_H
@@ -355,7 +358,8 @@
             symbolizeKeys = 1;
         }
     }
-    cfg = (yajl_parser_config){allowComments, checkUTF8};
+    cfg.allowComments = allowComments;
+    cfg.checkUTF8 = checkUTF8;

     obj = Data_Make_Struct(klass, yajl_parser_wrapper, yajl_parser_wrapper_mark, yajl_parser_wrapper_free, wrapper);
     wrapper->parser = yajl_alloc(&callbacks, &cfg, NULL, (void *)obj);
@@ -545,7 +549,8 @@
             }
         }
     }
-    cfg = (yajl_gen_config){beautify, indentString};
+    cfg.beautify = beautify;
+    cfg.indentString = indentString;

     obj = Data_Make_Struct(klass, yajl_encoder_wrapper, yajl_encoder_wrapper_mark, yajl_encoder_wrapper_free, wrapper);
     wrapper->encoder = yajl_gen_alloc(&cfg, NULL);
diff -Naur ext/yajl_gen.c yajl_ext/yajl_gen.c
--- ext/yajl_gen.c  2010-06-21 11:03:54.718750000 +0900
+++ yajl_ext/yajl_gen.c 2010-06-21 10:57:33.953125000 +0900
@@ -184,7 +184,7 @@
     return yajl_gen_status_ok;
 }

-#ifdef WIN32
+#ifdef _WIN32
 #include <float.h>
 #define isnan _isnan
 #define isinf !_finite

0.7.0 error "[BUG] Segmentation fault" on x86_64 server running Ubuntu 8.10

Using the basic example from the readme throws an error:

[BUG] Segmentation fault

Removing version 0.7.0 and install 0.6.9 fixes the issue for me.

Any thoughts on why this might be happening? Let me know if there is any other troubleshooting info I can provide.

x86_64 Sever
Ubuntu 8.10 (server edition)
ruby 1.8.6 (2008-08-11 patchlevel 287) [x86_64-linux]
Ruby Enterprise Edition 20090610
yajl-1.0.9

Installs but fails to load on OS X 10.6.2

I've installed yajl-ruby both on Ruby 1.8.6 and Ruby 1.9.1. It installs fine, but fails to load.

In Ruby 1.9.1:

>> require 'yajl'
LoadError: dlopen(/usr/local/lib/ruby19/gems/1.9.1/gems/yajl-ruby-0.6.6/lib/yajl_ext.bundle, 9): no suitable image found.  Did find:
    /usr/local/lib/ruby19/gems/1.9.1/gems/yajl-ruby-0.6.6/lib/yajl_ext.bundle: mach-o, but wrong architecture - /usr/local/lib/ruby19/gems/1.9.1/gems/yajl-ruby-0.6.6/lib/yajl_ext.bundle
    from /usr/local/lib/ruby19/gems/1.9.1/gems/yajl-ruby-0.6.6/lib/yajl.rb:2:in `require'
    from /usr/local/lib/ruby19/gems/1.9.1/gems/yajl-ruby-0.6.6/lib/yajl.rb:2:in `'
    from (irb):1:in `require'
    from (irb):1
    from /usr/local/bin/irb19:12:in `'

Environment info:

$ gem19 env
RubyGems Environment:
  - RUBYGEMS VERSION: 1.3.5
  - RUBY VERSION: 1.9.1 (2009-05-12 patchlevel 129) [i386-darwin9.7.0]
  - INSTALLATION DIRECTORY: /usr/local/lib/ruby19/gems/1.9.1
  - RUBYGEMS PREFIX: /usr/local/lib/ruby19/gems/1.9.1/gems/rubygems-update-1.3.5
  - RUBY EXECUTABLE: /usr/local/bin/ruby19
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86-darwin-9
  - GEM PATHS:
     - /usr/local/lib/ruby19/gems/1.9.1
     - /Users/lucashungaro/.gem/ruby/1.9.1
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :benchmark => false
     - :backtrace => false
     - :bulk_threshold => 1000
     - :sources => ["http://gemcutter.org", "http://gems.rubyforge.org/", "http://gems.github.com/"]
     - "rdoc" => "--inline-source --line-numbers --format=html --template=hanna"
  - REMOTE SOURCES:
     - http://gemcutter.org
     - http://gems.rubyforge.org/
     - http://gems.github.com/

In Ruby 1.8.6:

>> require 'yajl'
LoadError: Failed to load /usr/local/lib/ruby/gems/1.8/gems/yajl-ruby-0.6.6/lib/yajl_ext.bundle
    from /usr/local/lib/ruby/gems/1.8/gems/yajl-ruby-0.6.6/lib/yajl_ext.bundle
    from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
    from /usr/local/lib/ruby/gems/1.8/gems/yajl-ruby-0.6.6/lib/yajl.rb:2
    from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'
    from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
    from (irb):1

Environment info:

$ gem env
RubyGems Environment:
  - RUBYGEMS VERSION: 1.3.5
  - RUBY VERSION: 1.8.6 (2009-03-31 patchlevel 368) [i686-darwin9.7.0]
  - INSTALLATION DIRECTORY: /usr/local/lib/ruby/gems/1.8
  - RUBY EXECUTABLE: /usr/local/bin/ruby
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86-darwin-9
  - GEM PATHS:
     - /usr/local/lib/ruby/gems/1.8
     - /Users/lucashungaro/.gem/ruby/1.8
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :benchmark => false
     - :backtrace => false
     - :bulk_threshold => 1000
     - :sources => ["http://gemcutter.org", "http://gems.rubyforge.org/", "http://gems.github.com/"]
     - "rdoc" => "--inline-source --line-numbers --format=html --template=hanna"
  - REMOTE SOURCES:
     - http://gemcutter.org
     - http://gems.rubyforge.org/
     - http://gems.github.com/

Suggestion: a method to reset the parser

When parsing fails, Yajl::Parser instance gets useless (any new data, even valid, would raise Yajl::ParseError). This means that the parser cannot be reused after a parsing error.

So I suggest a method Yajl::Parser#reset which resets the parser by discarding pending status and buffered data.

This is useful in some kind of scenarios such a UDP server. In EventMachine just a single EM::Connection exists when creating a UDP server (which would contain a single Yajl::Parser instance), and it can receive data from different IP's (of course, each UDP datagram must contain full JSON object).
In this scenario, it's common to receive wrong data from a client. With the above suggestion (reset method) the parser could be reused rather than having to re-create it again.

Complete JSON gem compatibility (recreating objects)

Currently yajl-ruby does not support building objects from parsed input like the JSON gem does. I've created a gist (http://gist.github.com/642163) to illustrate how this works with the JSON gem. What's very nice about the functionality is that the JSON gem reconstructs the objects recursively (by calling json_create on the class corresponding to the json_class-field - which is configureable via JSON.create_id, IIRC).

This is a really useful feature, if you want to encode (nested) business objects for storing them to a document-oriented database, like CouchDB.

The top-level decoding and setting the correct classes can be done with this "hack":
obj = JSON.parse(obj)
obj = Object.const_get(obj["json_class"]).json_create(obj) if obj["json_class"]

FFI Branch

Hi, just a short question: How far is the FFI branch of the parser?
I'd love to be able to use yajl in jruby :)

thanks,
Marc

wildly varying performance depending on system

I have two systems, both using rvm and the same ruby versions.
One is an osx laptop, and the other is a linux vps server.

osx laptop running OSX-10.6.6 and ruby 1.9.2p136 (2010-12-25 revision 30365) [x86_64-darwin10.5.0]
linux vps server running centos-5.5 with kernel 2.6.18 and ruby 1.9.2p136 (2010-12-25 revision 30365) [i686-linux].

running benchmark encode_json_and_marshal.rb on the two systems.

osx laptop:

Starting benchmark encoding benchmark/subjects/ohai.json 1000 times

Rehearsal ------------------------------------
 Yajl::Encoder#encode
  0.710000   0.010000   0.720000 (  0.720439)
 JSON's #to_json
  0.940000   0.000000   0.940000 (  0.941257)
 Marshal.dump
  1.400000   0.000000   1.400000 (  1.395559)
--------------------------- total: 3.060000sec

       user     system      total        real
 Yajl::Encoder#encode
  0.690000   0.010000   0.700000 (  0.703585)
 JSON's #to_json
  0.940000   0.000000   0.940000 (  0.945706)
 Marshal.dump
  1.390000   0.000000   1.390000 (  1.394173)

and on the linux vps

Starting benchmark encoding benchmark/subjects/ohai.json 1000 times

Rehearsal ------------------------------------
 Yajl::Encoder#encode
  4.440000   0.010000   4.450000 (  4.448676)
 JSON's #to_json
  1.510000   0.000000   1.510000 (  1.503832)
 Marshal.dump
  2.020000   0.000000   2.020000 (  2.027906)
--------------------------- total: 7.980000sec

       user     system      total        real
 Yajl::Encoder#encode
  4.480000   0.000000   4.480000 (  4.478577)
 JSON's #to_json
  1.500000   0.000000   1.500000 (  1.508347)
 Marshal.dump
  2.020000   0.010000   2.030000 (  2.023818)

Both are using the same version of the gem yajl-ruby (0.7.8).

Any ideas why the version on the linux vps is so much slower? I could understand if it was slower across the board (as it seems marshall and to_json are). However, yajl-ruby is orders of magnitude slower, which seems very odd.

Is this a gcc version specific compilation bug?

gcc on linux vps: gcc version 4.1.2 20080704 (Red Hat 4.1.2-48)
gcc on osx: gcc version 4.2.1 (Apple Inc. build 5664)

Waits for timeout when using keep-alive connection

When making a request against a service that uses keep-alive, Yajl::HttpStream will not identify the end of the request, and will wait for timeout before returning. eg:

require 'uri'
require 'yajl/http_stream'

uri = URI.parse("http://api.videojuicer.com/presentations/1.json?seed_name=imama-tv")

puts Yajl::HttpStream.get(uri).inspect  # should take 1 minute or so before this returns

By adding the "Connection: close" header to the request, you can signal that you do not support persistent connections, and the server will close the connection after the response.

Cucumber and Yajl.

Brian, We recently implemented yajl-ruby and have been really impressed with its performance. We are noticing some strange behavior with cucumber. The issue only occurs in cucumber, not in dev or production. We are running Rails 2.3.8 with Ruby 1.9.2. Our test cucumber environment uses capybara and selenium-webdriver. We also have json loaded.
Cucumber does not seem to respect ActiveSupport::JSON.backend = 'JSONgem.' It reports that it it using json but yajl is actually called. We have also tried using rufus-json to manage which gem is called with the same effect.

"[BUG] Bus Error" with ActiveSupport 2.3.x

ruby 1.9.1p378 and 1.8.7p174 on Mac OS X 10.5.8

Calling

require 'active_support'
require 'yajl/json_gem'
ActiveSupport::JSON.encode(:a => 'b')

actually calls

{:a => 'b'}.to_json({:seen=>[{:a=>"b"}]})

And this call has the following effect:

(irb):2: [BUG] Bus Error
ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin9.8.0]
-- control frame ----------
c:0024 p:---- s:0086 b:0086 l:000085 d:000085 CFUNC  :to_json
c:0023 p:0026 s:0082 b:0082 l:002104 d:000081 EVAL   (irb):2

Twitter Streaming API Example

Getting an odd error when trying to use the streaming API example.

uri = URI.parse("http://#{username}:#{password}@stream.twitter.com/spritzer.json")
Yajl::HttpStream.get(uri, :symbolize_keys => true) do |hash|
?> puts hash.inspect
end
Yajl::ParseError: Found multiple JSON objects in the stream but no block or the on_parse_complete callback was assigned to handle them.
from /Library/Ruby/Gems/1.8/gems/brianmario-yajl-ruby-0.6.0/lib/yajl/http_stream.rb:117:in parse' from /Library/Ruby/Gems/1.8/gems/brianmario-yajl-ruby-0.6.0/lib/yajl/http_stream.rb:117:inrequest'
from /Library/Ruby/Gems/1.8/gems/brianmario-yajl-ruby-0.6.0/lib/yajl/http_stream.rb:20:in `get'
from (irb):16

seg fault with selenium driver

I don't know if this is really a selenium issue but I thought I would mention that I was getting seg faults when running selenium cucumber features when yajl-ruby 0.7.6 was present. It seems that selenium webdriver 0.0.18 will use yajl if present. This started happening for me due to using twitter gem.

.../Users/jonathangreenberg/.rvm/gems/ruby-1.8.7-p174/gems/activesupport-2.3.5/lib/active_support/json/encoding.rb:70: [BUG] Bus Error
ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin9.8.0]

Yajl can't consume JSON it produces

Yajl can produce the following JSON just fine:

{"theodor":{"cpu-0":{"cpu-system":[1252680210,1252683820,["value"],[[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[NaN],[3.2],[5.12],[10.86],[3.16],[2.88],[1.1],[2.16],[1.84],[3.6],[6.3],[3.78],[1.6],[1.6],[3.56],[5.1],[5.14],[3.82],[4.34],[4.08],[2.5],[3.28],[4.6],[3.62],[2.66],[1.94],[2.72],[3.1],[6.96],[5.32],[7.86],[8.26],[3.16],[5.02],[1.94],[2.16],[2.68],[3.54],[2.52],[2.32],[1.16],[1.08],[1.42],[1.78],[3.58],[5.42],[1.9],[2.44],[4.32],[3.02],[2.38],[2.44],[1.26],[0.78],[1.44],[2.6],[1.66],[1.28],[2.12],[2.28],[1.2],[1.98],[1.9],[1.92],[2.08],[2.5],[2.98],[3.24],[2.74],[1.96],[2.66],[1.44],[2.2],[3.04],[3.14],[2.68],[1.68],[1.14],[0.96],[1.28],[1.44],[0.84],[0.98],[0.96],[1.24],[1.46],[1.5],[0.7],[0.64],[0.52],[0.9],[0.52],[0.54],[0.42],[0.86],[0.62],[0.36],[0.56],[0.52],[0.98],[0.96],[1.8],[5.42],[10.78],[11.98],[7.52],[1.34],[1.82],[1.5],[1.38],[1.0],[1.52],[1.92],[1.64],[1.8],[1.88],[1.98],[1.28],[3.4],[9.4],[10.88],[8.66],[3.86],[11.62],[7.58],[5.6],[6.48],[7.26],[3.92],[7.86],[3.66],[3.64],[11.04],[12.26],[10.48],[11.1],[7.58],[7.64],[6.86],[8.42],[10.38],[8.88],[5.96],[10.48],[8.64],[4.24],[9.1],[11.12],[8.08],[7.24],[3.78],[7.8],[4.5],[3.94],[9.78],[8.2],[1.32],[3.92],[2.38],[1.06],[2.44],[1.92],[0.72],[0.66],[1.72],[1.58],[0.72],[0.78],[0.74],[1.08],[1.7],[1.44],[1.66],[0.3],[0.38],[0.74],[0.86],[0.68],[0.64],[0.72],[0.38],[1.46],[5.6],[3.4],[2.34],[1.82],[3.34],[1.28],[2.2],[2.86],[2.24],[1.82],[1.0],[0.64],[0.72],[0.38],[0.32],[0.56],[1.84],[3.68],[0.7],[0.3],[0.36],[0.52],[0.24],[0.4],[0.44],[0.6],[1.04],[2.52],[1.3],[1.08],[1.6],[0.88],[1.08],[0.66],[0.76],[0.32],[0.68],[0.24],[0.36],[0.36],[1.22],[2.02],[1.58],[2.28],[6.02],[1.88],[1.0],[0.9],[0.48],[0.36],[0.26],[0.46],[0.28],[0.3],[0.72],[0.72],[1.04],[3.52],[2.76],[1.02],[1.46],[2.92],[NaN],[NaN],[0.0]],{"value":"#cc0000"}]}}}

But when Yajl tries to consume it, the following happens:

lexical error: invalid char in json text.
            80550,1252684160,["value"],[[NaN],[NaN],[NaN],[NaN],[NaN],[N
                       (right here) ------^
(Yajl::ParseError)

The source data is an RRD, if that's any help.

parsing in chunks is buggy

When parsing multiple JSON strings from a single stream or in chunks, there may be unpredictable results.

http_stream not parsing '[{...}]' array wrapped responses

When a JSON request is made to facebook, they wrap their response in an array. http_stream doesn't parse that and throws an error. From the command line:
curl 'https://api.facebook.com/method/fql.query?format=json&query=SELECT+total_count+FROM+link_stat+WHERE+url%3D%27http%3A%2F%2Fwww.facebook.com%27'
[{"total_count":2135474}]

When I try to hit the same URL from the http_stream, it errors:
# Ruby
p query_url
json = Yajl::HttpStream.get(query_url)

# Output
#<URI::HTTPS:0x00000100ab7858 URL:https://api.facebook.com/method/fql.query?format=json&query=SELECT+total_count+FROM+link_stat+WHERE+url%3D%27http%3A%2F%2Fwww.facebook.com%27>
#<Yajl::HttpStream::HttpError: Yajl::HttpStream::HttpError>
nil

I'm not sure if there is an option that can be passed to http_stream or yajl in general to allow it to accept these types of responses or if this is just a bug. I know Facebook allows you to set how it sends JSON to a Facebook app, but that doesn't apply to general FQL queries.

Endoding with yajl-ruby for rails 3

Is there any reason the yajl-ruby gem and the official support in rails/activesupport 3 using yajl-ruby only for decoding json, but not for encoding? Am I missing something obvious here?

Yajl::HttpStream does ignore closed connection

I'm experimenting with Yajl::HttpStream as a consumer to CouchDB's _changs-API. The _changes API (see http://wiki.apache.org/couchdb/HTTP_database_API#Changes) has an continuous mode, where CouchDB holds the connection and sends one line of JSON when changes to documents occur. You can provide &timeout=X to the request to make CouchDB close the connection after X ms.

Yajl::HttpStream seems a perfect match for my problem, but however it seems to ignore the closing connection:

uri = URI.parse("http://couch-1:5984/foo/_changes?feed=continuous&timeout=1000")
res = Yajl::HttpStream.get(uri) do |change|
  puts change.inspect
end
puts "I never get here..."

procudes:
{"id"=>"99fa2c776d21a09d3f0c8dcbe50000be", "changes"=>[{"rev"=>"1-967a00dff5e02add41819138abb3284d"}], "seq"=>27}
{"id"=>"99fa2c776d21a09d3f0c8dcbe5000bae", "changes"=>[{"rev"=>"5-6182c9c954200ab5e3c6bd5e76a1549f"}], "seq"=>32}
{"id"=>"3cc9d2118918b82c412e7593d6000d7f", "changes"=>[{"rev"=>"9-8448f2f6bd56d18058558c0d19256b32"}], "seq"=>37}
{"last_seq"=>57}

CouchDB closes the connection immediately after sending {"last_seq"=>57}. But I have to interrupt my script with ^C otherwise it will run forever:
^C/Users/basti/.gem/gems/yajl-ruby-0.7.5/lib/yajl/http_stream.rb:150:in eof?': Interrupt from /Users/basti/.gem/gems/yajl-ruby-0.7.5/lib/yajl/http_stream.rb:150:inrequest'
from /Users/basti/.gem/gems/yajl-ruby-0.7.5/lib/yajl/http_stream.rb:30:in `get'
from cacheinvalidation.rb:11

Any ideas?

Yajl::HttpStream chunked response disconnects after seemingly random chunks

I was getting random disconnects against the Twitter streaming API. Yajl would successfully give me anywhere from 1 to 15 tweets, then disconnect as if the server was done responding. Curl showed no such problem and would continue passing me tweets.

I traced it back to 0cf854e where this line was added to the chunked response handler:
break if line.match /0.*?\r\n/

This matches a chunk size of "0", but also of "601" and "1012", etc. Changing the regex to /^0.*?\r\n/ fixed the problem.

Wish: Sort Keys

I'm using Yajl to dump data structures into a readable format for version control. It would be nice if the keys in the JSON output would be sorted to get a stable representation of the data. A option like :pretty would be nice...

Report consumed ammount of bytes in on_parse_complete (or limit the JSON max size)

I'm coding a JSONRPC server in EventMachine using yajl-ruby. It already works (similar as the provided in README documentation). However there is something I cannot figure how to achieve: avoid DoS attacks.

This is, imagine an attacker initially sends:

{ "method": "attack

This is processed in EM receive_data(data) in which we run @parser << data.

After a while (using same connection) the attacker sends:

lalalalala

It's again processed and appended to the parser. The attacker sends lalala continually (in different TCP packets, which would cause a leak in the server.

A half-solution could be counting data.bytesize and close connection if it reachs some limit. But this is a wrong solution: in case the same TCP data contains a valid JSON data followed by valid but non complete JSON data, we have no way to know when to reset the data size counter.

Two possible solutions I suggest:

Option :maxsize in Yajl::Parser.

@parser = Yajl::Parser.new(:maxsize => 5000)

In case the accumulated buffer in the Parser object exceeds such limit, the parser would raise some exception as Yajl::MaxSizeExceeded.

Report consumed bytes when calling on_parse_complete method

@parser.on_parse_complete = method(:data_parsed)

def data_parsed(obj, consumed_bytes)
  [...]
end

Getting this value, we can substract it from the above data size counter, so it would contain just the size of the incomplete data the parser contains. Of course, first solution seems much easier.

Yajl fails to decode null characters in strings

Yajl fails to decode null characters in json-encoded strings, silently discarding them.

Yajl::Parser.parse("\"\\u0000\"")

results in "" when it should be "\000".

JSON gem gets this right, for example (array added because JSON gem doesn't like parsing strings on their own):

>> JSON.parse("[\"\\u0000\"]")
=> ["\000"]

Whatever else is in the string, the null bytes are just discarded:

>> Yajl::Parser.parse("\"foo\\u0000bar \\u0000\"")
=> "foobar "
>> JSON.parse("[\"foo\\u0000bar \\u0000\"]")
=> ["foo\000bar \000"]

Fix for OpenBSD (gcc3)

OpenBSD is still unsing gcc3 which doesn't have -Wextra. I've created a patch for that in my clone of yajl-ruby. (commit 446eb38)

I'm checking for OpenBSD which isn't really nice because there might be other operating systems which still use gcc3. (I hope not. ;) ) But I don't know of a portable way to check the gcc version from ruby.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.