yajl-ruby 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of yajl-ruby might be problematic. Click here for more details.

@@ -5,9 +5,24 @@
5
5
  #define READ_BUFSIZE 8092
6
6
  #define WRITE_BUFSIZE 8092
7
7
 
8
+ // Older versions of Ruby (< 1.8.6) need these
9
+ #ifndef RSTRING_PTR
10
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
11
+ #endif
12
+ #ifndef RSTRING_LEN
13
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
14
+ #endif
15
+ #ifndef RARRAY_PTR
16
+ #define RARRAY_PTR(s) (RARRAY(s)->ptr)
17
+ #endif
18
+ #ifndef RARRAY_LEN
19
+ #define RARRAY_LEN(s) (RARRAY(s)->len)
20
+ #endif
21
+
8
22
  static VALUE cParseError, cEncodeError, mYajl, cParser, cEncoder;
9
- static ID intern_io_read, intern_eof, intern_call, intern_keys, intern_to_s, intern_to_json, intern_has_key,
10
- sym_allow_comments, sym_check_utf8, sym_pretty, sym_indent, sym_terminator, sym_symbolize_keys;
23
+ static ID intern_io_read, intern_eof, intern_call, intern_keys, intern_to_s,
24
+ intern_to_json, intern_has_key, intern_to_sym;
25
+ static ID sym_allow_comments, sym_check_utf8, sym_pretty, sym_indent, sym_terminator, sym_symbolize_keys;
11
26
 
12
27
  #define GetParser(obj, sval) (sval = (struct yajl_parser_wrapper*)DATA_PTR(obj));
13
28
  #define GetEncoder(obj, sval) (sval = (struct yajl_encoder_wrapper*)DATA_PTR(obj));
@@ -80,4 +95,6 @@ static VALUE rb_yajl_json_ext_string_to_json(int argc, VALUE * argv, VALUE self)
80
95
  static VALUE rb_yajl_json_ext_true_to_json(int argc, VALUE * argv, VALUE self);
81
96
  static VALUE rb_yajl_json_ext_false_to_json(int argc, VALUE * argv, VALUE self);
82
97
  static VALUE rb_yajl_json_ext_nil_to_json(int argc, VALUE * argv, VALUE self);
83
- static VALUE rb_yajl_encoder_enable_json_gem_ext(VALUE klass);
98
+ static VALUE rb_yajl_encoder_enable_json_gem_ext(VALUE klass);
99
+
100
+ void Init_yajl_ext();
@@ -37,6 +37,7 @@
37
37
  #include <stdlib.h>
38
38
  #include <string.h>
39
39
  #include <stdio.h>
40
+ #include <math.h>
40
41
 
41
42
  typedef enum {
42
43
  yajl_gen_start,
@@ -166,11 +167,19 @@ yajl_gen_integer(yajl_gen g, long int number)
166
167
  return yajl_gen_status_ok;
167
168
  }
168
169
 
170
+ #ifdef WIN32
171
+ #include <float.h>
172
+ #define isnan _isnan
173
+ #define isinf _finite
174
+ #endif
175
+
169
176
  yajl_gen_status
170
177
  yajl_gen_double(yajl_gen g, double number)
171
178
  {
172
179
  char i[32];
173
- ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
180
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY;
181
+ if (isnan(number) || isinf(number)) return yajl_gen_invalid_number;
182
+ INSERT_SEP; INSERT_WHITESPACE;
174
183
  sprintf(i, "%g", number);
175
184
  yajl_buf_append(g->buf, i, strlen(i));
176
185
  APPENDED_ATOM;
@@ -307,8 +307,8 @@ yajl_do_parse(yajl_handle hand, unsigned int * offset,
307
307
  {
308
308
  yajl_state s = yajl_bs_current(hand->stateStack);
309
309
  if (s == yajl_state_start) {
310
- // HACK: is this even safe to do?
311
- // yajl_bs_set(hand->stateStack, yajl_state_parse_complete);
310
+ /* HACK: is this even safe to do?
311
+ yajl_bs_set(hand->stateStack, yajl_state_parse_complete); */
312
312
  yajl_reset_parser(hand);
313
313
  } else if (s == yajl_state_map_need_val) {
314
314
  yajl_bs_set(hand->stateStack, yajl_state_map_got_val);
@@ -13,7 +13,17 @@ require 'yajl_ext'
13
13
  #
14
14
  # Ruby bindings to the excellent Yajl (Yet Another JSON Parser) ANSI C library.
15
15
  module Yajl
16
- VERSION = "0.6.3"
16
+ VERSION = "0.6.4"
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
17
27
 
18
28
  class Parser
19
29
  # A helper method for parse-and-forget use-cases
@@ -25,8 +35,8 @@ module Yajl
25
35
  # :allow_comments accepts a boolean will enable/disable checks for in-line comments in the JSON stream
26
36
  #
27
37
  # :check_utf8 accepts a boolean will enable/disable UTF8 validation for the JSON stream
28
- def self.parse(io, options={}, read_bufsize=nil, &block)
29
- new(options).parse(io, read_bufsize, &block)
38
+ def self.parse(str_or_io, options={}, read_bufsize=nil, &block)
39
+ new(options).parse(str_or_io, read_bufsize, &block)
30
40
  end
31
41
  end
32
42
 
@@ -52,6 +62,7 @@ module Yajl
52
62
  # If a block is passed, it will be used as (and work the same as) the +on_progress+ callback
53
63
  def self.encode(obj, *args, &block)
54
64
  # TODO: this code smells, any ideas?
65
+ args.flatten!
55
66
  options = {}
56
67
  io = nil
57
68
  args.each do |arg|
@@ -68,15 +79,15 @@ module Yajl
68
79
  # DEPRECATED - See Yajl::Parser and Yajl::Encoder
69
80
  module Stream
70
81
  # DEPRECATED - See Yajl::Parser
71
- def self.parse(io)
72
- STDERR.puts "WARNING: Yajl::Stream has be deprecated and will most likely be gone in the next release. Use the Yajl::Parser class instead."
73
- Parser.new.parse(io)
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)
74
85
  end
75
86
 
76
87
  # DEPRECATED - See Yajl::Encoder
77
- def self.encode(obj, io)
78
- STDERR.puts "WARNING: Yajl::Stream has be deprecated and will most likely be gone in the next release. Use the Yajl::Encoder class instead."
79
- Encoder.new.encode(obj, io)
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)
80
91
  end
81
92
  end
82
93
  end
@@ -13,6 +13,9 @@ class Object
13
13
  end
14
14
 
15
15
  module JSON
16
+ class JSONError < StandardError; end unless defined?(JSON::JSONError)
17
+ class GeneratorError < JSONError; end unless defined?(JSON::GeneratorError)
18
+
16
19
  def self.generate(obj, opts={})
17
20
  begin
18
21
  options_map = {}
@@ -21,8 +24,8 @@ module JSON
21
24
  options_map[:indent] = opts[:indent]
22
25
  end
23
26
  Yajl::Encoder.encode(obj, options_map)
24
- rescue Yajl::ParseError => e
25
- raise JSON::ParserError, e.message
27
+ rescue Yajl::EncodeError => e
28
+ raise JSON::GeneratorError, e.message
26
29
  end
27
30
  end
28
31
 
@@ -32,16 +35,16 @@ module JSON
32
35
  options_map[:pretty] = true
33
36
  options_map[:indent] = opts[:indent] if opts.has_key?(:indent)
34
37
  Yajl::Encoder.encode(obj, options_map)
35
- rescue Yajl::ParseError => e
36
- raise JSON::ParserError, e.message
38
+ rescue Yajl::EncodeError => e
39
+ raise JSON::GeneratorError, e.message
37
40
  end
38
41
  end
39
42
 
40
43
  def self.dump(obj, io=nil, *args)
41
44
  begin
42
45
  Yajl::Encoder.encode(obj, io)
43
- rescue Yajl::ParseError => e
44
- raise JSON::ParserError, e.message
46
+ rescue Yajl::EncodeError => e
47
+ raise JSON::GeneratorError, e.message
45
48
  end
46
49
  end
47
50
  end
@@ -2,7 +2,8 @@
2
2
  require 'yajl' unless defined?(Yajl::Parser)
3
3
 
4
4
  module JSON
5
- class ParserError < Yajl::ParseError; end
5
+ class JSONError < StandardError; end unless defined?(JSON::JSONError)
6
+ class ParserError < JSONError; end unless defined?(JSON::ParserError)
6
7
 
7
8
  def self.default_options
8
9
  @default_options ||= {:symbolize_keys => false}
@@ -11,62 +11,59 @@ describe "Yajl JSON encoder" do
11
11
  FILES = Dir[File.dirname(__FILE__)+'/../../benchmark/subjects/*.json']
12
12
 
13
13
  FILES.each do |file|
14
- it "should encode #{File.basename(file)} to an IO" do
15
- # we don't care about testing the stream subject as it has multiple JSON strings in it
16
- if File.basename(file) != 'twitter_stream.json'
17
- input = File.new(File.expand_path(file), 'r')
18
- io = StringIO.new
19
- encoder = Yajl::Encoder.new
20
- hash = Yajl::Parser.parse(input)
21
- encoder.encode(hash, io)
22
- io.rewind
23
- hash2 = Yajl::Parser.parse(io)
24
- io.close
25
- input.close
26
- hash.should == hash2
27
- end
28
- end
29
- end
30
-
31
- FILES.each do |file|
32
- it "should encode #{File.basename(file)} and return a String" do
33
- # we don't care about testing the stream subject as it has multiple JSON strings in it
34
- if File.basename(file) != 'twitter_stream.json'
35
- input = File.new(File.expand_path(file), 'r')
36
- encoder = Yajl::Encoder.new
37
- hash = Yajl::Parser.parse(input)
38
- output = encoder.encode(hash)
39
- hash2 = Yajl::Parser.parse(output)
40
- input.close
41
- hash.should == hash2
42
- end
43
- end
44
- end
45
-
46
- FILES.each do |file|
47
- it "should encode #{File.basename(file)} call the passed block, passing it a String" do
48
- # we don't care about testing the stream subject as it has multiple JSON strings in it
49
- if File.basename(file) != 'twitter_stream.json'
50
- input = File.new(File.expand_path(file), 'r')
51
- encoder = Yajl::Encoder.new
52
- hash = Yajl::Parser.parse(input)
53
- output = ''
54
- encoder.encode(hash) do |json_str|
55
- output << json_str
56
- end
57
- hash2 = Yajl::Parser.parse(output)
58
- input.close
59
- hash.should == hash2
60
- end
61
- end
62
- end
14
+ it "should encode #{File.basename(file)} to an IO" do
15
+ # we don't care about testing the stream subject as it has multiple JSON strings in it
16
+ if File.basename(file) != 'twitter_stream.json'
17
+ input = File.new(File.expand_path(file), 'r')
18
+ io = StringIO.new
19
+ encoder = Yajl::Encoder.new
20
+ hash = Yajl::Parser.parse(input)
21
+ encoder.encode(hash, io)
22
+ io.rewind
23
+ hash2 = Yajl::Parser.parse(io)
24
+ io.close
25
+ input.close
26
+ hash.should == hash2
27
+ end
28
+ end
29
+ end
30
+
31
+ FILES.each do |file|
32
+ it "should encode #{File.basename(file)} and return a String" do
33
+ # we don't care about testing the stream subject as it has multiple JSON strings in it
34
+ if File.basename(file) != 'twitter_stream.json'
35
+ input = File.new(File.expand_path(file), 'r')
36
+ encoder = Yajl::Encoder.new
37
+ hash = Yajl::Parser.parse(input)
38
+ output = encoder.encode(hash)
39
+ hash2 = Yajl::Parser.parse(output)
40
+ input.close
41
+ hash.should == hash2
42
+ end
43
+ end
44
+ end
45
+
46
+ FILES.each do |file|
47
+ it "should encode #{File.basename(file)} call the passed block, passing it a String" do
48
+ # we don't care about testing the stream subject as it has multiple JSON strings in it
49
+ if File.basename(file) != 'twitter_stream.json'
50
+ input = File.new(File.expand_path(file), 'r')
51
+ encoder = Yajl::Encoder.new
52
+ hash = Yajl::Parser.parse(input)
53
+ output = ''
54
+ encoder.encode(hash) do |json_str|
55
+ output << json_str
56
+ end
57
+ hash2 = Yajl::Parser.parse(output)
58
+ input.close
59
+ hash.should == hash2
60
+ end
61
+ end
62
+ end
63
63
 
64
64
  it "should encode with :pretty turned on and a single space indent, to an IO" do
65
- output = "{\n \"foo\": {\n \"name\": \"bar\",\n \"id\": 1234\n }\n}"
66
- if RUBY_VERSION.include?('1.9') # FIXME
67
- output = "{\n \"foo\": {\n \"id\": 1234,\n \"name\": \"bar\"\n }\n}"
68
- end
69
- obj = {:foo => {:id => 1234, :name => "bar"}}
65
+ output = "{\n \"foo\": 1234\n}"
66
+ obj = {:foo => 1234}
70
67
  io = StringIO.new
71
68
  encoder = Yajl::Encoder.new(:pretty => true, :indent => ' ')
72
69
  encoder.encode(obj, io)
@@ -75,22 +72,16 @@ describe "Yajl JSON encoder" do
75
72
  end
76
73
 
77
74
  it "should encode with :pretty turned on and a single space indent, and return a String" do
78
- output = "{\n \"foo\": {\n \"name\": \"bar\",\n \"id\": 1234\n }\n}"
79
- if RUBY_VERSION.include?('1.9') # FIXME
80
- output = "{\n \"foo\": {\n \"id\": 1234,\n \"name\": \"bar\"\n }\n}"
81
- end
82
- obj = {:foo => {:id => 1234, :name => "bar"}}
75
+ output = "{\n \"foo\": 1234\n}"
76
+ obj = {:foo => 1234}
83
77
  encoder = Yajl::Encoder.new(:pretty => true, :indent => ' ')
84
78
  output = encoder.encode(obj)
85
79
  output.should == output
86
80
  end
87
81
 
88
82
  it "should encode with :pretty turned on and a tab character indent, to an IO" do
89
- output = "{\n\t\"foo\": {\n\t\t\"name\": \"bar\",\n\t\t\"id\": 1234\n\t}\n}"
90
- if RUBY_VERSION.include?('1.9') # FIXME
91
- output = "{\n\t\"foo\": {\n\t\t\"id\": 1234,\n\t\t\"name\": \"bar\"\n\t}\n}"
92
- end
93
- obj = {:foo => {:id => 1234, :name => "bar"}}
83
+ output = "{\n\t\"foo\": 1234\n}"
84
+ obj = {:foo => 1234}
94
85
  io = StringIO.new
95
86
  encoder = Yajl::Encoder.new(:pretty => true, :indent => "\t")
96
87
  encoder.encode(obj, io)
@@ -99,22 +90,16 @@ describe "Yajl JSON encoder" do
99
90
  end
100
91
 
101
92
  it "should encode with :pretty turned on and a tab character indent, and return a String" do
102
- output = "{\n\t\"foo\": {\n\t\t\"name\": \"bar\",\n\t\t\"id\": 1234\n\t}\n}"
103
- if RUBY_VERSION.include?('1.9') # FIXME
104
- output = "{\n\t\"foo\": {\n\t\t\"id\": 1234,\n\t\t\"name\": \"bar\"\n\t}\n}"
105
- end
106
- obj = {:foo => {:id => 1234, :name => "bar"}}
93
+ output = "{\n\t\"foo\": 1234\n}"
94
+ obj = {:foo => 1234}
107
95
  encoder = Yajl::Encoder.new(:pretty => true, :indent => "\t")
108
96
  output = encoder.encode(obj)
109
97
  output.should == output
110
98
  end
111
99
 
112
100
  it "should encode with it's class method with :pretty and a tab character indent options set, to an IO" do
113
- output = "{\n\t\"foo\": {\n\t\t\"name\": \"bar\",\n\t\t\"id\": 1234\n\t}\n}"
114
- if RUBY_VERSION.include?('1.9') # FIXME
115
- output = "{\n\t\"foo\": {\n\t\t\"id\": 1234,\n\t\t\"name\": \"bar\"\n\t}\n}"
116
- end
117
- obj = {:foo => {:id => 1234, :name => "bar"}}
101
+ output = "{\n\t\"foo\": 1234\n}"
102
+ obj = {:foo => 1234}
118
103
  io = StringIO.new
119
104
  Yajl::Encoder.encode(obj, io, :pretty => true, :indent => "\t")
120
105
  io.rewind
@@ -122,21 +107,15 @@ describe "Yajl JSON encoder" do
122
107
  end
123
108
 
124
109
  it "should encode with it's class method with :pretty and a tab character indent options set, and return a String" do
125
- output = "{\n\t\"foo\": {\n\t\t\"name\": \"bar\",\n\t\t\"id\": 1234\n\t}\n}"
126
- if RUBY_VERSION.include?('1.9') # FIXME
127
- output = "{\n\t\"foo\": {\n\t\t\"id\": 1234,\n\t\t\"name\": \"bar\"\n\t}\n}"
128
- end
129
- obj = {:foo => {:id => 1234, :name => "bar"}}
110
+ output = "{\n\t\"foo\": 1234\n}"
111
+ obj = {:foo => 1234}
130
112
  output = Yajl::Encoder.encode(obj, :pretty => true, :indent => "\t")
131
113
  output.should == output
132
114
  end
133
115
 
134
116
  it "should encode with it's class method with :pretty and a tab character indent options set, to a block" do
135
- output = "{\n\t\"foo\": {\n\t\t\"name\": \"bar\",\n\t\t\"id\": 1234\n\t}\n}"
136
- if RUBY_VERSION.include?('1.9') # FIXME
137
- output = "{\n\t\"foo\": {\n\t\t\"id\": 1234,\n\t\t\"name\": \"bar\"\n\t}\n}"
138
- end
139
- obj = {:foo => {:id => 1234, :name => "bar"}}
117
+ output = "{\n\t\"foo\": 1234\n}"
118
+ obj = {:foo => 1234}
140
119
  output = ''
141
120
  Yajl::Encoder.encode(obj, :pretty => true, :indent => "\t") do |json_str|
142
121
  output = json_str
@@ -145,33 +124,25 @@ describe "Yajl JSON encoder" do
145
124
  end
146
125
 
147
126
  it "should encode multiple objects into a single stream, to an IO" do
148
- pending "Find a better way to compare order of hash keys in resulting string"
149
127
  io = StringIO.new
150
- obj = {:foo => "bar", :baz => 1234}
128
+ obj = {:foo => 1234}
151
129
  encoder = Yajl::Encoder.new
152
130
  5.times do
153
131
  encoder.encode(obj, io)
154
132
  end
155
133
  io.rewind
156
- output = "{\"baz\":1234,\"foo\":\"bar\"}{\"baz\":1234,\"foo\":\"bar\"}{\"baz\":1234,\"foo\":\"bar\"}{\"baz\":1234,\"foo\":\"bar\"}{\"baz\":1234,\"foo\":\"bar\"}"
157
- if RUBY_VERSION.include?('1.9') # FIXME
158
- output = "{\"foo\":\"bar\",\"baz\":1234}{\"foo\":\"bar\",\"baz\":1234}{\"foo\":\"bar\",\"baz\":1234}{\"foo\":\"bar\",\"baz\":1234}{\"foo\":\"bar\",\"baz\":1234}"
159
- end
134
+ output = "{\"foo\":1234}{\"foo\":1234}{\"foo\":1234}{\"foo\":1234}{\"foo\":1234}"
160
135
  io.read.should == output
161
136
  end
162
137
 
163
138
  it "should encode multiple objects into a single stream, and return a String" do
164
- pending "Find a better way to compare order of hash keys in resulting string"
165
- obj = {:foo => "bar", :baz => 1234}
139
+ obj = {:foo => 1234}
166
140
  encoder = Yajl::Encoder.new
167
141
  json_output = ''
168
142
  5.times do
169
143
  json_output << encoder.encode(obj)
170
144
  end
171
- output = "{\"baz\":1234,\"foo\":\"bar\"}\n{\"baz\":1234,\"foo\":\"bar\"}\n{\"baz\":1234,\"foo\":\"bar\"}\n{\"baz\":1234,\"foo\":\"bar\"}\n{\"baz\":1234,\"foo\":\"bar\"}\n"
172
- if RUBY_VERSION.include?('1.9') # FIXME
173
- output = "{\"foo\":\"bar\",\"baz\":1234}\n{\"foo\":\"bar\",\"baz\":1234}\n{\"foo\":\"bar\",\"baz\":1234}\n{\"foo\":\"bar\",\"baz\":1234}\n{\"foo\":\"bar\",\"baz\":1234}\n"
174
- end
145
+ output = "{\"foo\":1234}{\"foo\":1234}{\"foo\":1234}{\"foo\":1234}{\"foo\":1234}"
175
146
  json_output.should == output
176
147
  end
177
148
 
@@ -223,4 +194,19 @@ describe "Yajl JSON encoder" do
223
194
  s.rewind
224
195
  s.read.should eql("{\"foo\":\"bar\"}")
225
196
  end
197
+
198
+ it "should not encode NaN" do
199
+ lambda {
200
+ Yajl::Encoder.encode(0.0/0.0)
201
+ }.should raise_error(Yajl::EncodeError)
202
+ end
203
+
204
+ it "should not encode Infinity or -Infinity" do
205
+ lambda {
206
+ Yajl::Encoder.encode(1.0/0.0)
207
+ }.should raise_error(Yajl::EncodeError)
208
+ lambda {
209
+ Yajl::Encoder.encode(-1.0/0.0)
210
+ }.should raise_error(Yajl::EncodeError)
211
+ end
226
212
  end
@@ -0,0 +1,55 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+
4
+ describe "Yajl" do
5
+ context "dump" do
6
+ it "should exist as a class-method" do
7
+ Yajl.should respond_to(:dump)
8
+ end
9
+
10
+ it "should be able to encode to a string" do
11
+ Yajl.dump({:a => 1234}).should eql('{"a":1234}')
12
+ end
13
+
14
+ it "should be able to encode to an IO" do
15
+ io = StringIO.new
16
+ Yajl.dump({:a => 1234}, io)
17
+ io.rewind
18
+ io.read.should eql('{"a":1234}')
19
+ end
20
+
21
+ it "should be able to encode with a block supplied" do
22
+ Yajl.dump({:a => 1234}) do |chunk|
23
+ chunk.should eql('{"a":1234}')
24
+ end
25
+ end
26
+ end
27
+
28
+ context "load" do
29
+ it "should exist as a class-method" do
30
+ Yajl.should respond_to(:load)
31
+ end
32
+
33
+ it "should be able to parse from a string" do
34
+ Yajl.load('{"a":1234}').should eql({"a" => 1234})
35
+ end
36
+
37
+ it "should be able to parse from an IO" do
38
+ io = StringIO.new('{"a":1234}')
39
+ Yajl.load(io).should eql({"a" => 1234})
40
+ end
41
+
42
+ it "should be able to parse from a string with a block supplied" do
43
+ Yajl.load('{"a":1234}') do |h|
44
+ h.should eql({"a" => 1234})
45
+ end
46
+ end
47
+
48
+ it "should be able to parse from an IO with a block supplied" do
49
+ io = StringIO.new('{"a":1234}')
50
+ Yajl.load(io) do |h|
51
+ h.should eql({"a" => 1234})
52
+ end
53
+ end
54
+ end
55
+ end