json 1.1.0 → 1.1.1

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

Potentially problematic release.


This version of json might be problematic. Click here for more details.

@@ -52,14 +52,12 @@ module JSON
52
52
  MessageDialog::ERROR,
53
53
  MessageDialog::BUTTONS_CLOSE, text)
54
54
  dialog.show_all
55
- window.focus = dialog
56
55
  dialog.run
57
56
  rescue TypeError
58
57
  dialog = MessageDialog.new(Editor.window, Dialog::MODAL,
59
58
  MessageDialog::ERROR,
60
59
  MessageDialog::BUTTONS_CLOSE, text)
61
60
  dialog.show_all
62
- window.focus = dialog
63
61
  dialog.run
64
62
  ensure
65
63
  dialog.destroy if dialog
@@ -73,7 +71,6 @@ module JSON
73
71
  MessageDialog::QUESTION,
74
72
  MessageDialog::BUTTONS_YES_NO, text)
75
73
  dialog.show_all
76
- window.focus = dialog
77
74
  dialog.run do |response|
78
75
  return Gtk::Dialog::RESPONSE_YES === response
79
76
  end
@@ -1102,9 +1099,11 @@ module JSON
1102
1099
  # Quit this editor, that is, leave this editor's main loop.
1103
1100
  def quit
1104
1101
  ask_save if @changed
1105
- destroy
1106
- Gtk.main_quit
1107
- true
1102
+ if Gtk.main_level > 0
1103
+ destroy
1104
+ Gtk.main_quit
1105
+ end
1106
+ nil
1108
1107
  end
1109
1108
 
1110
1109
  # Display the new title according to the editor's current state.
@@ -1185,20 +1184,21 @@ module JSON
1185
1184
  if filename
1186
1185
  if File.directory?(filename)
1187
1186
  Editor.error_dialog(self, "Try to select a JSON file!")
1188
- return
1187
+ nil
1189
1188
  else
1190
- data = read_data(filename)
1191
1189
  @filename = filename
1192
- toplevel.display_status("Loaded data from '#@filename'.")
1190
+ if data = read_data(filename)
1191
+ toplevel.display_status("Loaded data from '#@filename'.")
1192
+ end
1193
1193
  display_title
1194
- return data
1194
+ data
1195
1195
  end
1196
1196
  end
1197
1197
  end
1198
1198
 
1199
1199
  # Load the data at location _uri_ into the editor as a JSON document.
1200
1200
  def load_location(uri)
1201
- data = read_data(uri)
1201
+ data = read_data(uri) or return
1202
1202
  @filename = nil
1203
1203
  toplevel.display_status("Loaded data from '#{uri}'.")
1204
1204
  display_title
@@ -1217,11 +1217,9 @@ module JSON
1217
1217
  end
1218
1218
  return JSON::parse(json, :max_nesting => false)
1219
1219
  end
1220
- rescue JSON::JSONError => e
1220
+ rescue => e
1221
1221
  Editor.error_dialog(self, "Failed to parse JSON file: #{e}!")
1222
1222
  return
1223
- rescue SystemCallError => e
1224
- quit
1225
1223
  end
1226
1224
 
1227
1225
  # Open a file selecton dialog, displaying _message_, and return the
@@ -89,15 +89,22 @@ module JSON
89
89
  # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
90
90
  # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
91
91
  # * *check_circular*: true if checking for circular data structures
92
+ # should be done (the default), false otherwise.
93
+ # * *check_circular*: true if checking for circular data structures
92
94
  # should be done, false (the default) otherwise.
95
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
96
+ # generated, otherwise an exception is thrown, if these values are
97
+ # encountered. This options defaults to false.
93
98
  def initialize(opts = {})
94
- @indent = opts[:indent] || ''
95
- @space = opts[:space] || ''
96
- @space_before = opts[:space_before] || ''
97
- @object_nl = opts[:object_nl] || ''
98
- @array_nl = opts[:array_nl] || ''
99
- @check_circular = !!(opts[:check_circular] || false)
100
- @seen = {}
99
+ @seen = {}
100
+ @indent = ''
101
+ @space = ''
102
+ @space_before = ''
103
+ @object_nl = ''
104
+ @array_nl = ''
105
+ @check_circular = true
106
+ @allow_nan = false
107
+ configure opts
101
108
  end
102
109
 
103
110
  # This string is used to indent levels in the JSON text.
@@ -117,12 +124,29 @@ module JSON
117
124
  # This string is put at the end of a line that holds a JSON array.
118
125
  attr_accessor :array_nl
119
126
 
127
+ # This integer returns the maximum level of data structure nesting in
128
+ # the generated JSON, max_nesting = 0 if no maximum is checked.
129
+ attr_accessor :max_nesting
130
+
131
+ def check_max_nesting(depth) # :nodoc:
132
+ return if @max_nesting.zero?
133
+ current_nesting = depth + 1
134
+ current_nesting > @max_nesting and
135
+ raise NestingError, "nesting of #{current_nesting} is too deep"
136
+ end
137
+
120
138
  # Returns true, if circular data structures should be checked,
121
139
  # otherwise returns false.
122
140
  def check_circular?
123
141
  @check_circular
124
142
  end
125
143
 
144
+ # Returns true if NaN, Infinity, and -Infinity should be considered as
145
+ # valid JSON and output.
146
+ def allow_nan?
147
+ @allow_nan
148
+ end
149
+
126
150
  # Returns _true_, if _object_ was already seen during this generating
127
151
  # run.
128
152
  def seen?(object)
@@ -139,6 +163,36 @@ module JSON
139
163
  def forget(object)
140
164
  @seen.delete object.__id__
141
165
  end
166
+
167
+ # Configure this State instance with the Hash _opts_, and return
168
+ # itself.
169
+ def configure(opts)
170
+ @indent = opts[:indent] if opts.key?(:indent)
171
+ @space = opts[:space] if opts.key?(:space)
172
+ @space_before = opts[:space_before] if opts.key?(:space_before)
173
+ @object_nl = opts[:object_nl] if opts.key?(:object_nl)
174
+ @array_nl = opts[:array_nl] if opts.key?(:array_nl)
175
+ @check_circular = !!opts[:check_circular] if opts.key?(:check_circular)
176
+ @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
177
+ if !opts.key?(:max_nesting) # defaults to 19
178
+ @max_nesting = 19
179
+ elsif opts[:max_nesting]
180
+ @max_nesting = opts[:max_nesting]
181
+ else
182
+ @max_nesting = 0
183
+ end
184
+ self
185
+ end
186
+
187
+ # Returns the configuration instance variables as a hash, that can be
188
+ # passed to the configure method.
189
+ def to_h
190
+ result = {}
191
+ for iv in %w[indent space space_before object_nl array_nl check_circular allow_nan max_nesting]
192
+ result[iv.intern] = instance_variable_get("@#{iv}")
193
+ end
194
+ result
195
+ end
142
196
  end
143
197
 
144
198
  module GeneratorMethods
@@ -158,6 +212,7 @@ module JSON
158
212
  def to_json(state = nil, depth = 0, *)
159
213
  if state
160
214
  state = JSON.state.from_state(state)
215
+ state.check_max_nesting(depth)
161
216
  json_check_circular(state) { json_transform(state, depth) }
162
217
  else
163
218
  json_transform(state, depth)
@@ -167,7 +222,7 @@ module JSON
167
222
  private
168
223
 
169
224
  def json_check_circular(state)
170
- if state
225
+ if state and state.check_circular?
171
226
  state.seen?(self) and raise JSON::CircularDatastructure,
172
227
  "circular data structures not supported!"
173
228
  state.remember self
@@ -211,6 +266,7 @@ module JSON
211
266
  def to_json(state = nil, depth = 0, *)
212
267
  if state
213
268
  state = JSON.state.from_state(state)
269
+ state.check_max_nesting(depth)
214
270
  json_check_circular(state) { json_transform(state, depth) }
215
271
  else
216
272
  json_transform(state, depth)
@@ -220,7 +276,7 @@ module JSON
220
276
  private
221
277
 
222
278
  def json_check_circular(state)
223
- if state
279
+ if state and state.check_circular?
224
280
  state.seen?(self) and raise JSON::CircularDatastructure,
225
281
  "circular data structures not supported!"
226
282
  state.remember self
@@ -257,7 +313,24 @@ module JSON
257
313
 
258
314
  module Float
259
315
  # Returns a JSON string representation for this Float number.
260
- def to_json(*) to_s end
316
+ def to_json(state = nil, *)
317
+ case
318
+ when infinite?
319
+ if !state || state.allow_nan?
320
+ to_s
321
+ else
322
+ raise GeneratorError, "#{self} not allowed in JSON"
323
+ end
324
+ when nan?
325
+ if !state || state.allow_nan?
326
+ to_s
327
+ else
328
+ raise GeneratorError, "#{self} not allowed in JSON"
329
+ end
330
+ else
331
+ to_s
332
+ end
333
+ end
261
334
  end
262
335
 
263
336
  module String
@@ -19,6 +19,9 @@ module JSON
19
19
  (?i:e[+-]?\d+)
20
20
  )
21
21
  )/x
22
+ NAN = /NaN/
23
+ INFINITY = /Infinity/
24
+ MINUS_INFINITY = /-Infinity/
22
25
  OBJECT_OPEN = /\{/
23
26
  OBJECT_CLOSE = /\}/
24
27
  ARRAY_OPEN = /\[/
@@ -50,7 +53,11 @@ module JSON
50
53
  # It will be configured by the _opts_ hash. _opts_ can have the following
51
54
  # keys:
52
55
  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
53
- # structures. Disable depth checking with :max_nesting => false.
56
+ # structures. Disable depth checking with :max_nesting => false|nil|0,
57
+ # it defaults to 19.
58
+ # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
59
+ # defiance of RFC 4627 to be parsed by the Parser. This option defaults
60
+ # to false.
54
61
  def initialize(source, opts = {})
55
62
  super
56
63
  if !opts.key?(:max_nesting) # defaults to 19
@@ -60,6 +67,7 @@ module JSON
60
67
  else
61
68
  @max_nesting = 0
62
69
  end
70
+ @allow_nan = !!opts[:allow_nan]
63
71
  @create_id = JSON.create_id
64
72
  end
65
73
 
@@ -153,6 +161,12 @@ module JSON
153
161
  obj = parse_object
154
162
  @current_nesting -= 1
155
163
  obj
164
+ when @allow_nan && scan(NAN)
165
+ NaN
166
+ when @allow_nan && scan(INFINITY)
167
+ Infinity
168
+ when @allow_nan && scan(MINUS_INFINITY)
169
+ MinusInfinity
156
170
  else
157
171
  UNPARSED
158
172
  end
@@ -1,6 +1,6 @@
1
1
  module JSON
2
2
  # JSON version
3
- VERSION = '1.1.0'
3
+ VERSION = '1.1.1'
4
4
  VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -1 +1 @@
1
- [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] // No, we don't limit our depth: Moved to pass...
1
+ [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'test/unit'
4
4
  require 'json'
5
+ require 'stringio'
5
6
 
6
7
  class TC_JSON < Test::Unit::TestCase
7
8
  include JSON
@@ -61,6 +62,12 @@ class TC_JSON < Test::Unit::TestCase
61
62
  assert_equal_float [3.141], parse('[3141.0E-3]')
62
63
  assert_equal_float [-3.141], parse('[-3141.0e-3]')
63
64
  assert_equal_float [-3.141], parse('[-3141e-3]')
65
+ assert_raises(ParserError) { parse('[NaN]') }
66
+ assert parse('[NaN]', :allow_nan => true).first.nan?
67
+ assert_raises(ParserError) { parse('[Infinity]') }
68
+ assert_equal [1.0/0], parse('[Infinity]', :allow_nan => true)
69
+ assert_raises(ParserError) { parse('[-Infinity]') }
70
+ assert_equal [-1.0/0], parse('[-Infinity]', :allow_nan => true)
64
71
  assert_equal([""], parse('[""]'))
65
72
  assert_equal(["foobar"], parse('["foobar"]'))
66
73
  assert_equal([{}], parse('[{}]'))
@@ -238,18 +245,50 @@ EOT
238
245
  end
239
246
 
240
247
  def test_nesting
241
- to_deep = '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]'
242
- assert_raises(JSON::NestingError) { JSON.parse to_deep }
243
- assert_raises(JSON::NestingError) { JSON.parser.new(to_deep).parse }
244
- assert_raises(JSON::NestingError) { JSON.parse to_deep, :max_nesting => 19 }
245
- ok = JSON.parse to_deep, :max_nesting => 20
246
- assert_kind_of Array, ok
247
- ok = JSON.parse to_deep, :max_nesting => nil
248
- assert_kind_of Array, ok
249
- ok = JSON.parse to_deep, :max_nesting => false
250
- assert_kind_of Array, ok
251
- ok = JSON.parse to_deep, :max_nesting => 0
252
- assert_kind_of Array, ok
248
+ assert_raises(JSON::NestingError) { JSON.parse '[[]]', :max_nesting => 1 }
249
+ assert_raises(JSON::NestingError) { JSON.parser.new('[[]]', :max_nesting => 1).parse }
250
+ assert_equal [[]], JSON.parse('[[]]', :max_nesting => 2)
251
+ too_deep = '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]'
252
+ too_deep_ary = eval too_deep
253
+ assert_raises(JSON::NestingError) { JSON.parse too_deep }
254
+ assert_raises(JSON::NestingError) { JSON.parser.new(too_deep).parse }
255
+ assert_raises(JSON::NestingError) { JSON.parse too_deep, :max_nesting => 19 }
256
+ ok = JSON.parse too_deep, :max_nesting => 20
257
+ assert_equal too_deep_ary, ok
258
+ ok = JSON.parse too_deep, :max_nesting => nil
259
+ assert_equal too_deep_ary, ok
260
+ ok = JSON.parse too_deep, :max_nesting => false
261
+ assert_equal too_deep_ary, ok
262
+ ok = JSON.parse too_deep, :max_nesting => 0
263
+ assert_equal too_deep_ary, ok
264
+ assert_raises(JSON::NestingError) { JSON.generate [[]], :max_nesting => 1 }
265
+ assert_equal '[[]]', JSON.generate([[]], :max_nesting => 2)
266
+ assert_raises(JSON::NestingError) { JSON.generate too_deep_ary }
267
+ assert_raises(JSON::NestingError) { JSON.generate too_deep_ary, :max_nesting => 19 }
268
+ ok = JSON.generate too_deep_ary, :max_nesting => 20
269
+ assert_equal too_deep, ok
270
+ ok = JSON.generate too_deep_ary, :max_nesting => nil
271
+ assert_equal too_deep, ok
272
+ ok = JSON.generate too_deep_ary, :max_nesting => false
273
+ assert_equal too_deep, ok
274
+ ok = JSON.generate too_deep_ary, :max_nesting => 0
275
+ assert_equal too_deep, ok
276
+ end
277
+
278
+ def test_load_dump
279
+ too_deep = '[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]'
280
+ assert_equal too_deep, JSON.dump(eval(too_deep))
281
+ assert_kind_of String, Marshal.dump(eval(too_deep))
282
+ assert_raises(ArgumentError) { JSON.dump(eval(too_deep), 19) }
283
+ assert_raises(ArgumentError) { Marshal.dump(eval(too_deep), 19) }
284
+ assert_equal too_deep, JSON.dump(eval(too_deep), 20)
285
+ assert_kind_of String, Marshal.dump(eval(too_deep), 20)
286
+ output = StringIO.new
287
+ JSON.dump(eval(too_deep), output)
288
+ assert_equal too_deep, output.string
289
+ output = StringIO.new
290
+ JSON.dump(eval(too_deep), output, 20)
291
+ assert_equal too_deep, output.string
253
292
  end
254
293
  end
255
294
  # vim: set et sw=2 ts=2:
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'test/unit'
4
- require 'json'
4
+ require 'json/add/core'
5
+ require 'date'
5
6
 
6
7
  class TC_JSONAddition < Test::Unit::TestCase
7
8
  include JSON
@@ -23,7 +24,7 @@ class TC_JSONAddition < Test::Unit::TestCase
23
24
 
24
25
  def to_json(*args)
25
26
  {
26
- 'json_class' => self.class,
27
+ 'json_class' => self.class.name,
27
28
  'args' => [ @a ],
28
29
  }.to_json(*args)
29
30
  end
@@ -32,7 +33,7 @@ class TC_JSONAddition < Test::Unit::TestCase
32
33
  class B
33
34
  def to_json(*args)
34
35
  {
35
- 'json_class' => self.class,
36
+ 'json_class' => self.class.name,
36
37
  }.to_json(*args)
37
38
  end
38
39
  end
@@ -91,4 +92,34 @@ EOT
91
92
  raw_again = JSON.parse(json)
92
93
  assert_equal raw, raw_again
93
94
  end
95
+
96
+ def test_core
97
+ t = Time.now
98
+ assert_equal t, JSON(JSON(t))
99
+ d = Date.today
100
+ assert_equal d, JSON(JSON(d))
101
+ d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161)
102
+ assert_equal d, JSON(JSON(d))
103
+ assert_equal 1..10, JSON(JSON(1..10))
104
+ assert_equal 1...10, JSON(JSON(1...10))
105
+ assert_equal "a".."c", JSON(JSON("a".."c"))
106
+ assert_equal "a"..."c", JSON(JSON("a"..."c"))
107
+ struct = Struct.new 'MyStruct', :foo, :bar
108
+ s = struct.new 4711, 'foot'
109
+ assert_equal s, JSON(JSON(s))
110
+ struct = Struct.new :foo, :bar
111
+ s = struct.new 4711, 'foot'
112
+ assert_raises(JSONError) { JSON(s) }
113
+ begin
114
+ raise TypeError, "test me"
115
+ rescue TypeError => e
116
+ e_json = JSON.generate e
117
+ e_again = JSON e_json
118
+ assert_kind_of TypeError, e_again
119
+ assert_equal e.message, e_again.message
120
+ assert_equal e.backtrace, e_again.backtrace
121
+ end
122
+ assert_equal /foo/, JSON(JSON(/foo/))
123
+ assert_equal /foo/i, JSON(JSON(/foo/i))
124
+ end
94
125
  end
@@ -13,14 +13,14 @@ class TC_JSONFixtures < Test::Unit::TestCase
13
13
  end
14
14
 
15
15
  def test_passing
16
- for (name, source) in @passed
16
+ for name, source in @passed
17
17
  assert JSON.parse(source),
18
18
  "Did not pass for fixture '#{name}'"
19
19
  end
20
20
  end
21
21
 
22
22
  def test_failing
23
- for (name, source) in @failed
23
+ for name, source in @failed
24
24
  assert_raises(JSON::ParserError, JSON::NestingError,
25
25
  "Did not fail for fixture '#{name}'") do
26
26
  JSON.parse(source)
@@ -40,7 +40,7 @@ EOT
40
40
 
41
41
  def test_unparse
42
42
  json = unparse(@hash)
43
- assert_equal(@json2, json)
43
+ assert_equal(JSON.parse(@json2), JSON.parse(json))
44
44
  parsed_json = parse(json)
45
45
  assert_equal(@hash, parsed_json)
46
46
  json = generate({1=>2})
@@ -51,7 +51,7 @@ EOT
51
51
 
52
52
  def test_unparse_pretty
53
53
  json = pretty_unparse(@hash)
54
- assert_equal(@json3, json)
54
+ assert_equal(JSON.parse(@json3), JSON.parse(json))
55
55
  parsed_json = parse(json)
56
56
  assert_equal(@hash, parsed_json)
57
57
  json = pretty_generate({1=>2})
@@ -71,6 +71,7 @@ EOT
71
71
  #assert s.check_circular
72
72
  h = { 1=>2 }
73
73
  h[3] = h
74
+ assert_raises(JSON::CircularDatastructure) { generate(h) }
74
75
  assert_raises(JSON::CircularDatastructure) { generate(h, s) }
75
76
  s = JSON.state.new(:check_circular => true)
76
77
  #assert s.check_circular
@@ -78,4 +79,22 @@ EOT
78
79
  a << a
79
80
  assert_raises(JSON::CircularDatastructure) { generate(a, s) }
80
81
  end
82
+
83
+ def test_allow_nan
84
+ assert_raises(GeneratorError) { generate([JSON::NaN]) }
85
+ assert_equal '[NaN]', generate([JSON::NaN], :allow_nan => true)
86
+ assert_equal '[NaN]', fast_generate([JSON::NaN])
87
+ assert_raises(GeneratorError) { pretty_generate([JSON::NaN]) }
88
+ assert_equal "[\n NaN\n]", pretty_generate([JSON::NaN], :allow_nan => true)
89
+ assert_raises(GeneratorError) { generate([JSON::Infinity]) }
90
+ assert_equal '[Infinity]', generate([JSON::Infinity], :allow_nan => true)
91
+ assert_equal '[Infinity]', fast_generate([JSON::Infinity])
92
+ assert_raises(GeneratorError) { pretty_generate([JSON::Infinity]) }
93
+ assert_equal "[\n Infinity\n]", pretty_generate([JSON::Infinity], :allow_nan => true)
94
+ assert_raises(GeneratorError) { generate([JSON::MinusInfinity]) }
95
+ assert_equal '[-Infinity]', generate([JSON::MinusInfinity], :allow_nan => true)
96
+ assert_equal '[-Infinity]', fast_generate([JSON::MinusInfinity])
97
+ assert_raises(GeneratorError) { pretty_generate([JSON::MinusInfinity]) }
98
+ assert_equal "[\n -Infinity\n]", pretty_generate([JSON::MinusInfinity], :allow_nan => true)
99
+ end
81
100
  end