json_pure 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/json/editor.rb CHANGED
@@ -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
data/lib/json/version.rb CHANGED
@@ -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"]]]]]]]]]]]]]]]]]]]]
data/tests/test_json.rb CHANGED
@@ -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)