benofsky-yajl-ruby 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. data/.gitignore +9 -0
  2. data/CHANGELOG.md +281 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +320 -0
  5. data/Rakefile +40 -0
  6. data/VERSION.yml +5 -0
  7. data/benchmark/encode.rb +58 -0
  8. data/benchmark/encode_json_and_marshal.rb +42 -0
  9. data/benchmark/encode_json_and_yaml.rb +53 -0
  10. data/benchmark/http.rb +32 -0
  11. data/benchmark/parse.rb +59 -0
  12. data/benchmark/parse_json_and_marshal.rb +50 -0
  13. data/benchmark/parse_json_and_yaml.rb +55 -0
  14. data/benchmark/parse_stream.rb +54 -0
  15. data/benchmark/subjects/item.json +1 -0
  16. data/benchmark/subjects/ohai.json +1216 -0
  17. data/benchmark/subjects/ohai.marshal_dump +0 -0
  18. data/benchmark/subjects/ohai.yml +975 -0
  19. data/benchmark/subjects/twitter_search.json +1 -0
  20. data/benchmark/subjects/twitter_stream.json +430 -0
  21. data/benchmark/subjects/unicode.json +1 -0
  22. data/examples/encoding/chunked_encoding.rb +27 -0
  23. data/examples/encoding/one_shot.rb +13 -0
  24. data/examples/encoding/to_an_io.rb +12 -0
  25. data/examples/http/twitter_search_api.rb +12 -0
  26. data/examples/http/twitter_stream_api.rb +26 -0
  27. data/examples/parsing/from_file.rb +14 -0
  28. data/examples/parsing/from_stdin.rb +9 -0
  29. data/examples/parsing/from_string.rb +13 -0
  30. data/ext/api/yajl_common.h +85 -0
  31. data/ext/api/yajl_gen.h +159 -0
  32. data/ext/api/yajl_parse.h +196 -0
  33. data/ext/extconf.rb +9 -0
  34. data/ext/yajl.c +164 -0
  35. data/ext/yajl_alloc.c +65 -0
  36. data/ext/yajl_alloc.h +50 -0
  37. data/ext/yajl_buf.c +119 -0
  38. data/ext/yajl_buf.h +73 -0
  39. data/ext/yajl_bytestack.h +85 -0
  40. data/ext/yajl_encode.c +188 -0
  41. data/ext/yajl_encode.h +50 -0
  42. data/ext/yajl_ext.c +911 -0
  43. data/ext/yajl_ext.h +128 -0
  44. data/ext/yajl_gen.c +317 -0
  45. data/ext/yajl_lex.c +747 -0
  46. data/ext/yajl_lex.h +135 -0
  47. data/ext/yajl_parser.c +450 -0
  48. data/ext/yajl_parser.h +82 -0
  49. data/lib/yajl/bzip2/stream_reader.rb +32 -0
  50. data/lib/yajl/bzip2/stream_writer.rb +15 -0
  51. data/lib/yajl/bzip2.rb +11 -0
  52. data/lib/yajl/deflate/stream_reader.rb +44 -0
  53. data/lib/yajl/deflate/stream_writer.rb +21 -0
  54. data/lib/yajl/deflate.rb +6 -0
  55. data/lib/yajl/gzip/stream_reader.rb +31 -0
  56. data/lib/yajl/gzip/stream_writer.rb +14 -0
  57. data/lib/yajl/gzip.rb +6 -0
  58. data/lib/yajl/http_stream.rb +197 -0
  59. data/lib/yajl/json_gem/encoding.rb +50 -0
  60. data/lib/yajl/json_gem/parsing.rb +27 -0
  61. data/lib/yajl/json_gem.rb +14 -0
  62. data/lib/yajl.rb +93 -0
  63. data/spec/encoding/encoding_spec.rb +234 -0
  64. data/spec/global/global_spec.rb +55 -0
  65. data/spec/http/fixtures/http.bzip2.dump +0 -0
  66. data/spec/http/fixtures/http.chunked.dump +11 -0
  67. data/spec/http/fixtures/http.deflate.dump +0 -0
  68. data/spec/http/fixtures/http.error.dump +12 -0
  69. data/spec/http/fixtures/http.gzip.dump +0 -0
  70. data/spec/http/fixtures/http.html.dump +1220 -0
  71. data/spec/http/fixtures/http.raw.dump +1226 -0
  72. data/spec/http/http_delete_spec.rb +99 -0
  73. data/spec/http/http_error_spec.rb +33 -0
  74. data/spec/http/http_get_spec.rb +110 -0
  75. data/spec/http/http_post_spec.rb +124 -0
  76. data/spec/http/http_put_spec.rb +106 -0
  77. data/spec/json_gem_compatibility/compatibility_spec.rb +203 -0
  78. data/spec/parsing/active_support_spec.rb +64 -0
  79. data/spec/parsing/chunked_spec.rb +98 -0
  80. data/spec/parsing/fixtures/fail.15.json +1 -0
  81. data/spec/parsing/fixtures/fail.16.json +1 -0
  82. data/spec/parsing/fixtures/fail.17.json +1 -0
  83. data/spec/parsing/fixtures/fail.26.json +1 -0
  84. data/spec/parsing/fixtures/fail11.json +1 -0
  85. data/spec/parsing/fixtures/fail12.json +1 -0
  86. data/spec/parsing/fixtures/fail13.json +1 -0
  87. data/spec/parsing/fixtures/fail14.json +1 -0
  88. data/spec/parsing/fixtures/fail19.json +1 -0
  89. data/spec/parsing/fixtures/fail20.json +1 -0
  90. data/spec/parsing/fixtures/fail21.json +1 -0
  91. data/spec/parsing/fixtures/fail22.json +1 -0
  92. data/spec/parsing/fixtures/fail23.json +1 -0
  93. data/spec/parsing/fixtures/fail24.json +1 -0
  94. data/spec/parsing/fixtures/fail25.json +1 -0
  95. data/spec/parsing/fixtures/fail27.json +2 -0
  96. data/spec/parsing/fixtures/fail28.json +2 -0
  97. data/spec/parsing/fixtures/fail3.json +1 -0
  98. data/spec/parsing/fixtures/fail4.json +1 -0
  99. data/spec/parsing/fixtures/fail5.json +1 -0
  100. data/spec/parsing/fixtures/fail6.json +1 -0
  101. data/spec/parsing/fixtures/fail9.json +1 -0
  102. data/spec/parsing/fixtures/pass.array.json +6 -0
  103. data/spec/parsing/fixtures/pass.codepoints_from_unicode_org.json +1 -0
  104. data/spec/parsing/fixtures/pass.contacts.json +1 -0
  105. data/spec/parsing/fixtures/pass.db100.xml.json +1 -0
  106. data/spec/parsing/fixtures/pass.db1000.xml.json +1 -0
  107. data/spec/parsing/fixtures/pass.dc_simple_with_comments.json +11 -0
  108. data/spec/parsing/fixtures/pass.deep_arrays.json +1 -0
  109. data/spec/parsing/fixtures/pass.difficult_json_c_test_case.json +1 -0
  110. data/spec/parsing/fixtures/pass.difficult_json_c_test_case_with_comments.json +1 -0
  111. data/spec/parsing/fixtures/pass.doubles.json +1 -0
  112. data/spec/parsing/fixtures/pass.empty_array.json +1 -0
  113. data/spec/parsing/fixtures/pass.empty_string.json +1 -0
  114. data/spec/parsing/fixtures/pass.escaped_bulgarian.json +4 -0
  115. data/spec/parsing/fixtures/pass.escaped_foobar.json +1 -0
  116. data/spec/parsing/fixtures/pass.item.json +1 -0
  117. data/spec/parsing/fixtures/pass.json-org-sample1.json +23 -0
  118. data/spec/parsing/fixtures/pass.json-org-sample2.json +11 -0
  119. data/spec/parsing/fixtures/pass.json-org-sample3.json +26 -0
  120. data/spec/parsing/fixtures/pass.json-org-sample4-nows.json +88 -0
  121. data/spec/parsing/fixtures/pass.json-org-sample4.json +89 -0
  122. data/spec/parsing/fixtures/pass.json-org-sample5.json +27 -0
  123. data/spec/parsing/fixtures/pass.map-spain.xml.json +1 -0
  124. data/spec/parsing/fixtures/pass.ns-invoice100.xml.json +1 -0
  125. data/spec/parsing/fixtures/pass.ns-soap.xml.json +1 -0
  126. data/spec/parsing/fixtures/pass.numbers-fp-4k.json +6 -0
  127. data/spec/parsing/fixtures/pass.numbers-fp-64k.json +61 -0
  128. data/spec/parsing/fixtures/pass.numbers-int-4k.json +11 -0
  129. data/spec/parsing/fixtures/pass.numbers-int-64k.json +154 -0
  130. data/spec/parsing/fixtures/pass.twitter-search.json +1 -0
  131. data/spec/parsing/fixtures/pass.twitter-search2.json +1 -0
  132. data/spec/parsing/fixtures/pass.unicode.json +3315 -0
  133. data/spec/parsing/fixtures/pass.yelp.json +1 -0
  134. data/spec/parsing/fixtures/pass1.json +56 -0
  135. data/spec/parsing/fixtures/pass2.json +1 -0
  136. data/spec/parsing/fixtures/pass3.json +6 -0
  137. data/spec/parsing/fixtures_spec.rb +41 -0
  138. data/spec/parsing/one_off_spec.rb +81 -0
  139. data/spec/rcov.opts +3 -0
  140. data/spec/spec.opts +2 -0
  141. data/spec/spec_helper.rb +16 -0
  142. data/yajl-ruby.gemspec +203 -0
  143. metadata +232 -0
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+ module Yajl
3
+ module Bzip2
4
+ # This is a wrapper around Bzip::Reader to allow it's #read method to adhere
5
+ # to the IO spec, allowing for two parameters (length, and buffer)
6
+ class StreamReader < ::Bzip2::Reader
7
+ # A helper method to allow use similar to IO#read
8
+ def read(len=nil, buffer=nil)
9
+ if val = super(len)
10
+ unless buffer.nil?
11
+ buffer.replace(val)
12
+ return buffer
13
+ end
14
+ super(len)
15
+ else
16
+ nil
17
+ end
18
+ end
19
+
20
+ # Helper method for one-off parsing from a bzip2-compressed stream
21
+ #
22
+ # See Yajl::Parser#parse for parameter documentation
23
+ def self.parse(input, options={}, buffer_size=nil, &block)
24
+ if input.is_a?(String)
25
+ input = StringIO.new(input)
26
+ end
27
+
28
+ Yajl::Parser.new(options).parse(new(input), buffer_size, &block)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+ module Yajl
3
+ module Bzip2
4
+ # A wrapper around the Bzip2::Writer class for easier JSON stream encoding
5
+ class StreamWriter < ::Bzip2::Writer
6
+
7
+ # A helper method for encoding to a bzip2-compressed stream
8
+ #
9
+ # Look up Yajl::Encoder#encode for parameter documentation
10
+ def self.encode(obj, io)
11
+ Yajl::Encoder.new.encode(obj, new(io))
12
+ end
13
+ end
14
+ end
15
+ end
data/lib/yajl/bzip2.rb ADDED
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
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 => e
10
+ raise "Unable to load the bzip2 library. Is the bzip2-ruby gem installed?"
11
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+ module Yajl
3
+ module Deflate
4
+ # This is a wrapper around Zlib::Inflate, creating a #read method that adheres
5
+ # to the IO spec, allowing for two parameters (length, and buffer)
6
+ class StreamReader < ::Zlib::Inflate
7
+
8
+ # Wrapper to the initialize method so we can set the initial IO to parse from.
9
+ def initialize(io, options)
10
+ @io = io
11
+ super(options)
12
+ end
13
+
14
+ # A helper method to allow use similar to IO#read
15
+ def read(len=nil, buffer=nil)
16
+ if val = @io.read(len)
17
+ unless buffer.nil?
18
+ buffer.replace(inflate(val))
19
+ return buffer
20
+ end
21
+ inflate(@io.read(len))
22
+ else
23
+ nil
24
+ end
25
+ end
26
+
27
+ # Helper method for one-off parsing from a deflate-compressed stream
28
+ #
29
+ # See Yajl::Parser#parse for parameter documentation
30
+ def self.parse(input, options={}, buffer_size=nil, &block)
31
+ if input.is_a?(String)
32
+ input = StringIO.new(input)
33
+ end
34
+
35
+ if options.is_a?(Hash)
36
+ deflate_options = options.delete(:deflate_options)
37
+ Yajl::Parser.new(options).parse(new(input, deflate_options), buffer_size, &block)
38
+ elsif options.is_a?(Fixnum)
39
+ Yajl::Parser.new.parse(new(input, options), buffer_size, &block)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ module Yajl
3
+ module Deflate
4
+ # A wrapper around the Zlib::Deflate class for easier JSON stream parsing
5
+ class StreamWriter < ::Zlib::Deflate
6
+
7
+ # A helper method to allow use similar to IO#write
8
+ def write(str)
9
+ deflate(str)
10
+ str.size unless str.nil?
11
+ end
12
+
13
+ # A helper method for one-off encoding to a deflate-compressed stream
14
+ #
15
+ # Look up Yajl::Encoder#encode for parameter documentation
16
+ def self.encode(obj, io)
17
+ Yajl::Encoder.new.encode(obj, new(io))
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: UTF-8
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'
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+ module Yajl
3
+ module Gzip
4
+ # This is a wrapper around Zlib::GzipReader to allow it's #read method to adhere
5
+ # to the IO spec, allowing for two parameters (length, and buffer)
6
+ class StreamReader < ::Zlib::GzipReader
7
+ # A helper method to allow use similar to IO#read
8
+ def read(len=nil, buffer=nil)
9
+ if val = super(len)
10
+ unless buffer.nil?
11
+ buffer.replace(val)
12
+ return buffer
13
+ end
14
+ super(len)
15
+ else
16
+ nil
17
+ end
18
+ end
19
+
20
+ # Helper method for one-off parsing from a gzip-compressed stream
21
+ #
22
+ # See Yajl::Parser#parse for parameter documentation
23
+ def self.parse(input, options={}, buffer_size=nil, &block)
24
+ if input.is_a?(String)
25
+ input = StringIO.new(input)
26
+ end
27
+ Yajl::Parser.new(options).parse(new(input), buffer_size, &block)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+ module Yajl
3
+ module Gzip
4
+ # Wraper around the Zlib::GzipWriter class
5
+ class StreamWriter < ::Zlib::GzipWriter
6
+ # A helper method for one-off encoding to a gzip-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
data/lib/yajl/gzip.rb ADDED
@@ -0,0 +1,6 @@
1
+ # encoding: UTF-8
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'
@@ -0,0 +1,197 @@
1
+ # encoding: UTF-8
2
+ require 'socket' unless defined?(Socket)
3
+ require 'yajl' unless defined?(Yajl::Parser)
4
+ require 'uri' unless defined?(URI)
5
+
6
+ module Yajl
7
+ # This module is for making HTTP requests to which the response bodies (and possibly requests in the near future)
8
+ # are streamed directly into Yajl.
9
+ class HttpStream
10
+
11
+ # This Exception is thrown when an HTTP response isn't in ALLOWED_MIME_TYPES
12
+ # and therefore cannot be parsed.
13
+ class InvalidContentType < Exception; end
14
+ class HttpError < StandardError
15
+
16
+ attr_reader :message, :headers
17
+
18
+ def initialize(message, headers)
19
+ @message = message
20
+ @headers = headers
21
+ end
22
+ end
23
+
24
+ # The mime-type we expect the response to be. If it's anything else, we can't parse it
25
+ # and an InvalidContentType is raised.
26
+ ALLOWED_MIME_TYPES = ["application/json", "text/plain"]
27
+
28
+ # Makes a basic HTTP GET request to the URI provided
29
+ def self.get(uri, opts = {}, &block)
30
+ request("GET", uri, opts, &block)
31
+ end
32
+
33
+ # Makes a basic HTTP GET request to the URI provided allowing the user to terminate the connection
34
+ def get(uri, opts = {}, &block)
35
+ initialize_socket(uri, opts)
36
+ HttpStream::get(uri, opts, &block)
37
+ rescue IOError => e
38
+ raise e unless @intentional_termination
39
+ end
40
+
41
+ # Makes a basic HTTP POST request to the URI provided
42
+ def self.post(uri, body, opts = {}, &block)
43
+ request("POST", uri, opts.merge({:body => body}), &block)
44
+ end
45
+
46
+ # Makes a basic HTTP POST request to the URI provided allowing the user to terminate the connection
47
+ def post(uri, body, opts = {}, &block)
48
+ initialize_socket(uri, opts)
49
+ HttpStream::post(uri, body, opts, &block)
50
+ rescue IOError => e
51
+ raise e unless @intentional_termination
52
+ end
53
+
54
+ # Makes a basic HTTP PUT request to the URI provided
55
+ def self.put(uri, body, opts = {}, &block)
56
+ request("PUT", uri, opts.merge({:body => body}), &block)
57
+ end
58
+
59
+ # Makes a basic HTTP PUT request to the URI provided allowing the user to terminate the connection
60
+ def put(uri, body, opts = {}, &block)
61
+ initialize_socket(uri, opts)
62
+ HttpStream::put(uri, body, opts, &block)
63
+ rescue IOError => e
64
+ raise e unless @intentional_termination
65
+ end
66
+
67
+ # Makes a basic HTTP DELETE request to the URI provided
68
+ def self.delete(uri, opts = {}, &block)
69
+ request("DELETE", uri, opts, &block)
70
+ end
71
+
72
+ # Makes a basic HTTP DELETE request to the URI provided allowing the user to terminate the connection
73
+ def delete(uri, opts = {}, &block)
74
+ initialize_socket(uri, opts)
75
+ HttpStream::delete(uri, opts, &block)
76
+ rescue IOError => e
77
+ raise e unless @intentional_termination
78
+ end
79
+
80
+ # Terminate a running HTTPStream instance
81
+ def terminate
82
+ @intentional_termination = true
83
+ @socket.close
84
+ end
85
+
86
+ protected
87
+ def self.request(method, uri, opts = {}, &block)
88
+ if uri.is_a?(String)
89
+ uri = URI.parse(uri)
90
+ end
91
+
92
+ user_agent = opts.has_key?('User-Agent') ? opts.delete(['User-Agent']) : "Yajl::HttpStream #{Yajl::VERSION}"
93
+ if method == "POST" || method == "PUT"
94
+ content_type = opts.has_key?('Content-Type') ? opts.delete(['Content-Type']) : "application/x-www-form-urlencoded"
95
+ body = opts.delete(:body)
96
+ if body.is_a?(Hash)
97
+ body = body.keys.collect {|param| "#{URI.escape(param.to_s)}=#{URI.escape(body[param].to_s)}"}.join('&')
98
+ end
99
+ end
100
+
101
+ socket = opts.has_key?(:socket) ? opts.delete(:socket) : TCPSocket.new(uri.host, uri.port)
102
+ request = "#{method} #{uri.path}#{uri.query ? "?"+uri.query : nil} HTTP/1.1\r\n"
103
+ request << "Host: #{uri.host}\r\n"
104
+ request << "Authorization: Basic #{[uri.userinfo].pack('m').strip!}\r\n" unless uri.userinfo.nil?
105
+ request << "User-Agent: #{user_agent}\r\n"
106
+ request << "Accept: */*\r\n"
107
+ if method == "POST" || method == "PUT"
108
+ request << "Content-Length: #{body.length}\r\n"
109
+ request << "Content-Type: #{content_type}\r\n"
110
+ end
111
+ encodings = []
112
+ encodings << "bzip2" if defined?(Yajl::Bzip2)
113
+ encodings << "gzip" if defined?(Yajl::Gzip)
114
+ encodings << "deflate" if defined?(Yajl::Deflate)
115
+ request << "Accept-Encoding: #{encodings.join(',')}\r\n" if encodings.any?
116
+ request << "Accept-Charset: utf-8\r\n\r\n"
117
+ if method == "POST" || method == "PUT"
118
+ request << body
119
+ end
120
+ socket.write(request)
121
+ response_head = {}
122
+ response_head[:headers] = {}
123
+
124
+ socket.each_line do |line|
125
+ if line == "\r\n" # end of the headers
126
+ break
127
+ else
128
+ header = line.split(": ")
129
+ if header.size == 1
130
+ header = header[0].split(" ")
131
+ response_head[:version] = header[0]
132
+ response_head[:code] = header[1].to_i
133
+ response_head[:msg] = header[2]
134
+ # this is the response code line
135
+ else
136
+ response_head[:headers][header[0]] = header[1].strip
137
+ end
138
+ end
139
+ end
140
+
141
+ if (response_head[:code] != 200)
142
+ raise HttpError.new("Code 200 expected got #{response_head[:code]}", response_head[:headers])
143
+ end
144
+
145
+ parser = Yajl::Parser.new(opts)
146
+ parser.on_parse_complete = block if block_given?
147
+ if response_head[:headers]["Transfer-Encoding"] == 'chunked'
148
+ if block_given?
149
+ chunkLeft = 0
150
+ while !socket.eof? && (line = socket.gets)
151
+ break if line.match /0.*?\r\n/
152
+ next if line == "\r\n"
153
+ size = line.hex
154
+ json = socket.read(size)
155
+ next if json.nil?
156
+ chunkLeft = size-json.size
157
+ if chunkLeft == 0
158
+ parser << json
159
+ else
160
+ # received only part of the chunk, grab the rest
161
+ parser << socket.read(chunkLeft)
162
+ end
163
+ end
164
+ else
165
+ raise Exception, "Chunked responses detected, but no block given to handle the chunks."
166
+ end
167
+ else
168
+ content_type = response_head[:headers]["Content-Type"].split(';')
169
+ content_type = content_type.first
170
+ if ALLOWED_MIME_TYPES.include?(content_type)
171
+ case response_head[:headers]["Content-Encoding"]
172
+ when "gzip"
173
+ return Yajl::Gzip::StreamReader.parse(socket, opts, &block)
174
+ when "deflate"
175
+ return Yajl::Deflate::StreamReader.parse(socket, opts.merge({:deflate_options => -Zlib::MAX_WBITS}), &block)
176
+ when "bzip2"
177
+ return Yajl::Bzip2::StreamReader.parse(socket, opts, &block)
178
+ else
179
+ return parser.parse(socket)
180
+ end
181
+ else
182
+ raise InvalidContentType, "The response MIME type #{content_type}"
183
+ end
184
+ end
185
+ ensure
186
+ socket.close if !socket.nil? and !socket.closed?
187
+ end
188
+
189
+ private
190
+ # Initialize socket and add it to the opts
191
+ def initialize_socket(uri, opts = {})
192
+ @socket = TCPSocket.new(uri.host, uri.port)
193
+ opts.merge!({:socket => @socket})
194
+ @intentional_termination = false
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: UTF-8
2
+ require 'yajl' unless defined?(Yajl::Parser)
3
+
4
+ # NOTE: this is probably temporary until I can split out the JSON compat C code into it's own
5
+ # extension that can be included when this file is.
6
+ Yajl::Encoder.enable_json_gem_compatability
7
+
8
+ # Our fallback to_json definition
9
+ class Object
10
+ def to_json(*args, &block)
11
+ "\"#{to_s}\""
12
+ end
13
+ end
14
+
15
+ module JSON
16
+ class JSONError < StandardError; end unless defined?(JSON::JSONError)
17
+ class GeneratorError < JSONError; end unless defined?(JSON::GeneratorError)
18
+
19
+ def self.generate(obj, opts={})
20
+ begin
21
+ options_map = {}
22
+ if opts.has_key?(:indent)
23
+ options_map[:pretty] = true
24
+ options_map[:indent] = opts[:indent]
25
+ end
26
+ Yajl::Encoder.encode(obj, options_map)
27
+ rescue Yajl::EncodeError => e
28
+ raise JSON::GeneratorError, e.message
29
+ end
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
@@ -0,0 +1,27 @@
1
+ # encoding: UTF-8
2
+ require 'yajl' unless defined?(Yajl::Parser)
3
+
4
+ module JSON
5
+ class JSONError < StandardError; end unless defined?(JSON::JSONError)
6
+ class ParserError < JSONError; end unless defined?(JSON::ParserError)
7
+
8
+ def self.default_options
9
+ @default_options ||= {:symbolize_keys => false}
10
+ end
11
+
12
+ def self.parse(str, opts=JSON.default_options)
13
+ begin
14
+ Yajl::Parser.parse(str, opts)
15
+ rescue Yajl::ParseError => e
16
+ raise JSON::ParserError, e.message
17
+ end
18
+ end
19
+
20
+ def self.load(input, *args)
21
+ begin
22
+ Yajl::Parser.parse(input, default_options)
23
+ rescue Yajl::ParseError => e
24
+ raise JSON::ParserError, e.message
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+ require 'yajl' unless defined?(Yajl::Parser)
3
+ require 'yajl/json_gem/parsing'
4
+ require 'yajl/json_gem/encoding'
5
+
6
+ module ::Kernel
7
+ def JSON(object, opts = {})
8
+ if object.respond_to? :to_s
9
+ JSON.parse(object.to_s, JSON.default_options.merge(opts))
10
+ else
11
+ JSON.generate(object, opts)
12
+ end
13
+ end
14
+ end
data/lib/yajl.rb ADDED
@@ -0,0 +1,93 @@
1
+ # encoding: UTF-8
2
+ require 'yajl_ext'
3
+
4
+ # = Extras
5
+ # We're not going to load these auotmatically, because you might not need them ;)
6
+ #
7
+ # require 'yajl/http_stream.rb' unless defined?(Yajl::HttpStream)
8
+ # require 'yajl/gzip.rb' unless defined?(Yajl::Gzip)
9
+ # require 'yajl/deflate.rb' unless defined?(Yajl::Deflate)
10
+ # require 'yajl/bzip2.rb' unless defined?(Yajl::Bzip2)
11
+
12
+ # = Yajl
13
+ #
14
+ # Ruby bindings to the excellent Yajl (Yet Another JSON Parser) ANSI C library.
15
+ module Yajl
16
+ VERSION = "0.7.6"
17
+
18
+ # For compatibility, has the same signature of Yajl::Parser.parse
19
+ def self.load(str_or_io, options={}, read_bufsize=nil, &block)
20
+ Parser.parse(str_or_io, options, read_bufsize, &block)
21
+ end
22
+
23
+ # For compatibility, has the same signature of Yajl::Encoder.encode
24
+ def self.dump(obj, *args, &block)
25
+ Encoder.encode(obj, args, &block)
26
+ end
27
+
28
+ class Parser
29
+ # A helper method for parse-and-forget use-cases
30
+ #
31
+ # +io+ is the stream to parse JSON from
32
+ #
33
+ # The +options+ hash allows you to set two parsing options - :allow_comments and :check_utf8
34
+ #
35
+ # :allow_comments accepts a boolean will enable/disable checks for in-line comments in the JSON stream
36
+ #
37
+ # :check_utf8 accepts a boolean will enable/disable UTF8 validation for the JSON stream
38
+ def self.parse(str_or_io, options={}, read_bufsize=nil, &block)
39
+ new(options).parse(str_or_io, read_bufsize, &block)
40
+ end
41
+ end
42
+
43
+ class Encoder
44
+ # A helper method for encode-and-forget use-cases
45
+ #
46
+ # Examples:
47
+ # Yajl::Encoder.encode(obj[, io, :pretty => true, :indent => "\t", &block])
48
+ #
49
+ # output = Yajl::Encoder.encode(obj[, :pretty => true, :indent => "\t", &block])
50
+ #
51
+ # +obj+ is a ruby object to encode to JSON format
52
+ #
53
+ # +io+ is the optional IO stream to encode the ruby object to.
54
+ # If +io+ isn't passed, the resulting JSON string is returned. If +io+ is passed, nil is returned.
55
+ #
56
+ # The +options+ hash allows you to set two encoding options - :pretty and :indent
57
+ #
58
+ # :pretty accepts a boolean and will enable/disable "pretty printing" the resulting output
59
+ #
60
+ # :indent accepts a string and will be used as the indent character(s) during the pretty print process
61
+ #
62
+ # If a block is passed, it will be used as (and work the same as) the +on_progress+ callback
63
+ def self.encode(obj, *args, &block)
64
+ # TODO: this code smells, any ideas?
65
+ args.flatten!
66
+ options = {}
67
+ io = nil
68
+ args.each do |arg|
69
+ if arg.is_a?(Hash)
70
+ options = arg
71
+ elsif arg.respond_to?(:read)
72
+ io = arg
73
+ end
74
+ end if args.any?
75
+ new(options).encode(obj, io, &block)
76
+ end
77
+ end
78
+
79
+ # DEPRECATED - See Yajl::Parser and Yajl::Encoder
80
+ module Stream
81
+ # DEPRECATED - See Yajl::Parser
82
+ def self.parse(str_or_io)
83
+ warn "WARNING: Yajl::Stream has be deprecated and will most likely be gone in the next release. Use the Yajl::Parser class instead."
84
+ Parser.new.parse(str_or_io)
85
+ end
86
+
87
+ # DEPRECATED - See Yajl::Encoder
88
+ def self.encode(obj, str_or_io=nil)
89
+ warn "WARNING: Yajl::Stream has be deprecated and will most likely be gone in the next release. Use the Yajl::Encoder class instead."
90
+ Encoder.new.encode(obj, str_or_io)
91
+ end
92
+ end
93
+ end