json 0.4.0

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.

data/TODO ADDED
File without changes
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.0
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ $KCODE = 'U'
3
+ require 'json/editor'
4
+
5
+ filename, encoding = ARGV
6
+ JSON::Editor.start(encoding) do |window|
7
+ if filename and File.exist?(filename)
8
+ window.file_open(filename)
9
+ end
10
+ end
11
+ # vim: set et sw=2 ts=2:
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rbconfig'
4
+ require 'fileutils'
5
+ include FileUtils::Verbose
6
+
7
+ include Config
8
+
9
+ dest = CONFIG["bindir"]
10
+ cd 'bin' do
11
+ filename = 'edit_json.rb'
12
+ install(filename, dest)
13
+ end
14
+ dest = CONFIG["sitelibdir"]
15
+ cd 'lib' do
16
+ install('json.rb', dest)
17
+ mkdir_p File.join(dest,'json')
18
+ install(File.join('json', 'editor.rb'), File.join(dest,'json'))
19
+ install(File.join('json', 'json.xpm'), File.join(dest,'json'))
20
+ end
21
+ # vim: set et sw=2 ts=2:
@@ -0,0 +1,652 @@
1
+ # = json - JSON library for Ruby
2
+ #
3
+ # == Description
4
+ #
5
+ # == Author
6
+ #
7
+ # Florian Frank <mailto:flori@ping.de>
8
+ #
9
+ # == License
10
+ #
11
+ # This is free software; you can redistribute it and/or modify it under the
12
+ # terms of the GNU General Public License Version 2 as published by the Free
13
+ # Software Foundation: www.gnu.org/copyleft/gpl.html
14
+ #
15
+ # == Download
16
+ #
17
+ # The latest version of this library can be downloaded at
18
+ #
19
+ # * http://rubyforge.org/frs?group_id=953
20
+ #
21
+ # Online Documentation should be located at
22
+ #
23
+ # * http://json.rubyforge.org
24
+ #
25
+ # == Examples
26
+ #
27
+ # To create a JSON string from a ruby data structure, you
28
+ # can call JSON.unparse like that:
29
+ #
30
+ # json = JSON.unparse [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
31
+ # # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
32
+ #
33
+ # It's also possible to call the #to_json method directly.
34
+ #
35
+ # json = [1, 2, {"a"=>3.141}, false, true, nil, 4..10].to_json
36
+ # # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
37
+ #
38
+ # To get back a ruby data structure, you have to call
39
+ # JSON.parse on the JSON string:
40
+ #
41
+ # JSON.parse json
42
+ # # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
43
+ #
44
+ # Note, that the range from the original data structure is a simple
45
+ # string now. The reason for this is, that JSON doesn't support ranges
46
+ # or arbitrary classes. In this case the json library falls back to call
47
+ # Object#to_json, which is the same as #to_s.to_json.
48
+ #
49
+ # It's possible to extend JSON to support serialization of arbitray classes by
50
+ # simply implementing a more specialized version of the #to_json method, that
51
+ # should return a JSON object (a hash converted to JSON with #to_json)
52
+ # like this (don't forget the *a for all the arguments):
53
+ #
54
+ # class Range
55
+ # def to_json(*a)
56
+ # {
57
+ # 'json_class' => self.class.name,
58
+ # 'data' => [ first, last, exclude_end? ]
59
+ # }.to_json(*a)
60
+ # end
61
+ # end
62
+ #
63
+ # The hash key 'json_class' is the class, that will be asked to deserialize the
64
+ # JSON representation later. In this case it's 'Range', but any namespace of
65
+ # the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
66
+ # used to store the necessary data to configure the object to be deserialized.
67
+ #
68
+ # If a the key 'json_class' is found in a JSON object, the JSON parser checks
69
+ # if the given class responds to the json_create class method. If so, it is
70
+ # called with the JSON object converted to a Ruby hash. So a range can
71
+ # be deserialized by implementing Range.json_create like this:
72
+ #
73
+ # class Range
74
+ # def self.json_create(o)
75
+ # new(*o['data'])
76
+ # end
77
+ # end
78
+ #
79
+ # Now it possible to serialize/deserialize ranges as well:
80
+ #
81
+ # json = JSON.unparse [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
82
+ # # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
83
+ # JSON.parse json
84
+ # # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
85
+ #
86
+ # JSON.unparse always creates the shortes possible string representation of a
87
+ # ruby data structure in one line. This good for data storage or network
88
+ # protocols, but not so good for humans to read. Fortunately there's
89
+ # also JSON.pretty_unparse that creates a more readable output:
90
+ #
91
+ # puts JSON.pretty_unparse([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
92
+ # [
93
+ # 1,
94
+ # 2,
95
+ # {
96
+ # "a": 3.141
97
+ # },
98
+ # false,
99
+ # true,
100
+ # null,
101
+ # {
102
+ # "json_class": "Range",
103
+ # "data": [
104
+ # 4,
105
+ # 10,
106
+ # false
107
+ # ]
108
+ # }
109
+ # ]
110
+ #
111
+ # There are also the methods Kernel#j for unparse, and Kernel#jj for
112
+ # pretty_unparse output to the console, that work analogous to Kernel#p and
113
+ # Kernel#pp.
114
+ #
115
+
116
+ require 'strscan'
117
+
118
+ # This module is the namespace for all the JSON related classes. It also
119
+ # defines some module functions to expose a nicer API to users, instead
120
+ # of using the parser and other classes directly.
121
+ module JSON
122
+ # The base exception for JSON errors.
123
+ JSONError = Class.new StandardError
124
+
125
+ # This exception is raise, if a parser error occurs.
126
+ ParserError = Class.new JSONError
127
+
128
+ # This exception is raise, if a unparser error occurs.
129
+ UnparserError = Class.new JSONError
130
+
131
+ # If a circular data structure is encountered while unparsing
132
+ # this exception is raised.
133
+ CircularDatastructure = Class.new UnparserError
134
+
135
+ class << self
136
+ # Switches on Unicode support, if _enable_ is _true_. Otherwise switches
137
+ # Unicode support off.
138
+ def support_unicode=(enable)
139
+ @support_unicode = enable
140
+ end
141
+
142
+ # Returns _true_ if JSON supports unicode, otherwise _false_ is returned.
143
+ def support_unicode?
144
+ !!@support_unicode
145
+ end
146
+ end
147
+ JSON.support_unicode = true # default, hower it's possible to switch off full
148
+ # unicode support, if non-ascii bytes should be
149
+ # just passed through.
150
+
151
+ begin
152
+ require 'iconv'
153
+ # An iconv instance to convert from UTF8 to UTF16 Big Endian.
154
+ UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be')
155
+ # An iconv instance to convert from UTF16 Big Endian to UTF8.
156
+ UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8'); UTF8toUTF16.iconv('no bom')
157
+ rescue LoadError
158
+ JSON.support_unicode = false # enforce disabling of unicode support
159
+ end
160
+
161
+ # This class implements the JSON parser that is used to parse a JSON string
162
+ # into a Ruby data structure.
163
+ class Parser < StringScanner
164
+ STRING = /"((?:[^"\\]|\\.)*)"/
165
+ INTEGER = /-?\d+/
166
+ FLOAT = /-?\d+\.(\d*)(?i:e[+-]?\d+)?/
167
+ OBJECT_OPEN = /\{/
168
+ OBJECT_CLOSE = /\}/
169
+ ARRAY_OPEN = /\[/
170
+ ARRAY_CLOSE = /\]/
171
+ PAIR_DELIMITER = /:/
172
+ COLLECTION_DELIMITER = /,/
173
+ TRUE = /true/
174
+ FALSE = /false/
175
+ NULL = /null/
176
+ IGNORE = %r(
177
+ (?:
178
+ //[^\n\r]*[\n\r]| # line comments
179
+ /\* # c-style comments
180
+ (?:
181
+ [^*/]| # normal chars
182
+ /[^*]| # slashes that do not start a nested comment
183
+ \*[^/]| # asterisks that do not end this comment
184
+ /(?=\*/) # single slash before this comment's end
185
+ )*
186
+ \*/ # the end of this comment
187
+ |\s+ # whitespaces
188
+ )+
189
+ )mx
190
+
191
+ UNPARSED = Object.new
192
+
193
+ # Parses the current JSON string and returns the complete data structure
194
+ # as a result.
195
+ def parse
196
+ reset
197
+ until eos?
198
+ case
199
+ when scan(ARRAY_OPEN)
200
+ return parse_array
201
+ when scan(OBJECT_OPEN)
202
+ return parse_object
203
+ when skip(IGNORE)
204
+ ;
205
+ when !((value = parse_value).equal? UNPARSED)
206
+ return value
207
+ else
208
+ raise ParserError, "source '#{peek(20)}' not in JSON!"
209
+ end
210
+ end
211
+ end
212
+
213
+ private
214
+
215
+ def parse_string
216
+ if scan(STRING)
217
+ return '' if self[1].empty?
218
+ self[1].gsub(/\\(?:[\\bfnrt"]|u([A-Fa-f\d]{4}))/) do
219
+ case $~[0]
220
+ when '\\\\' then '\\'
221
+ when '\\b' then "\b"
222
+ when '\\f' then "\f"
223
+ when '\\n' then "\n"
224
+ when '\\r' then "\r"
225
+ when '\\t' then "\t"
226
+ when '\"' then '"'
227
+ else
228
+ if JSON.support_unicode? and $KCODE == 'UTF8'
229
+ JSON.utf16_to_utf8($~[1])
230
+ else
231
+ # if utf8 mode is switched off or unicode not supported, try to
232
+ # transform unicode \u-notation to bytes directly:
233
+ $~[1].to_i(16).chr
234
+ end
235
+ end
236
+ end
237
+ else
238
+ UNPARSED
239
+ end
240
+ end
241
+
242
+ def parse_value
243
+ case
244
+ when scan(FLOAT)
245
+ Float(self[0])
246
+ when scan(INTEGER)
247
+ Integer(self[0])
248
+ when scan(TRUE)
249
+ true
250
+ when scan(FALSE)
251
+ false
252
+ when scan(NULL)
253
+ nil
254
+ when (string = parse_string) != UNPARSED
255
+ string
256
+ when scan(ARRAY_OPEN)
257
+ parse_array
258
+ when scan(OBJECT_OPEN)
259
+ parse_object
260
+ else
261
+ UNPARSED
262
+ end
263
+ end
264
+
265
+ def parse_array
266
+ result = []
267
+ until eos?
268
+ case
269
+ when (value = parse_value) != UNPARSED
270
+ result << value
271
+ skip(IGNORE)
272
+ unless scan(COLLECTION_DELIMITER) or match?(ARRAY_CLOSE)
273
+ raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
274
+ end
275
+ when scan(ARRAY_CLOSE)
276
+ break
277
+ when skip(IGNORE)
278
+ ;
279
+ else
280
+ raise ParserError, "unexpected token in array at '#{peek(20)}'!"
281
+ end
282
+ end
283
+ result
284
+ end
285
+
286
+ def parse_object
287
+ result = {}
288
+ until eos?
289
+ case
290
+ when (string = parse_string) != UNPARSED
291
+ skip(IGNORE)
292
+ unless scan(PAIR_DELIMITER)
293
+ raise ParserError, "expected ':' in object at '#{peek(20)}'!"
294
+ end
295
+ skip(IGNORE)
296
+ unless (value = parse_value).equal? UNPARSED
297
+ result[string] = value
298
+ skip(IGNORE)
299
+ unless scan(COLLECTION_DELIMITER) or match?(OBJECT_CLOSE)
300
+ raise ParserError,
301
+ "expected ',' or '}' in object at '#{peek(20)}'!"
302
+ end
303
+ else
304
+ raise ParserError, "expected value in object at '#{peek(20)}'!"
305
+ end
306
+ when scan(OBJECT_CLOSE)
307
+ if klassname = result['json_class']
308
+ klass = klassname.sub(/^:+/, '').split(/::/).inject(Object) do |p,k|
309
+ p.const_get(k) rescue nil
310
+ end
311
+ break unless klass and klass.json_creatable?
312
+ result = klass.json_create(result)
313
+ end
314
+ break
315
+ when skip(IGNORE)
316
+ ;
317
+ else
318
+ raise ParserError, "unexpected token in object at '#{peek(20)}'!"
319
+ end
320
+ end
321
+ result
322
+ end
323
+ end
324
+
325
+ # This class is used to create State instances, that are use to hold data
326
+ # while unparsing a Ruby data structure into a JSON string.
327
+ class State
328
+ # Creates a State object from _opts_, which ought to be Hash to create a
329
+ # new State instance configured by opts, something else to create an
330
+ # unconfigured instance. If _opts_ is a State object, it is just returned.
331
+ def self.from_state(opts)
332
+ case opts
333
+ when self
334
+ opts
335
+ when Hash
336
+ new(opts)
337
+ else
338
+ new
339
+ end
340
+ end
341
+
342
+ # Instantiates a new State object, configured by _opts_.
343
+ def initialize(opts = {})
344
+ @indent = opts[:indent] || ''
345
+ @space = opts[:space] || ''
346
+ @object_nl = opts[:object_nl] || ''
347
+ @array_nl = opts[:array_nl] || ''
348
+ @seen = {}
349
+ end
350
+
351
+ # This string is used to indent levels in the JSON string.
352
+ attr_accessor :indent
353
+
354
+ # This string is used to include a space between the tokens in a JSON
355
+ # string.
356
+ attr_accessor :space
357
+
358
+ # This string is put at the end of a line that holds a JSON object (or
359
+ # Hash).
360
+ attr_accessor :object_nl
361
+
362
+ # This string is put at the end of a line that holds a JSON array.
363
+ attr_accessor :array_nl
364
+
365
+ # Returns _true_, if _object_ was already seen during this Unparsing run.
366
+ def seen?(object)
367
+ @seen.key?(object.__id__)
368
+ end
369
+
370
+ # Remember _object_, to find out if it was already encountered (to find out
371
+ # if a cyclic data structure is unparsed).
372
+ def remember(object)
373
+ @seen[object.__id__] = true
374
+ end
375
+
376
+ # Forget _object_ for this Unparsing run.
377
+ def forget(object)
378
+ @seen.delete object.__id__
379
+ end
380
+ end
381
+
382
+ module_function
383
+
384
+ # Convert _string_ from UTF8 encoding to UTF16 (big endian) encoding and
385
+ # return it.
386
+ def utf8_to_utf16(string)
387
+ JSON::UTF8toUTF16.iconv(string).unpack('H*')[0]
388
+ end
389
+
390
+ # Convert _string_ from UTF16 (big endian) encoding to UTF8 encoding and
391
+ # return it.
392
+ def utf16_to_utf8(string)
393
+ bytes = '' << string[0, 2].to_i(16) << string[2, 2].to_i(16)
394
+ JSON::UTF16toUTF8.iconv(bytes)
395
+ end
396
+
397
+ # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
398
+ # UTF16 big endian characters as \u????, and return it.
399
+ def utf8_to_json(string)
400
+ i, n, result = 0, string.size, ''
401
+ while i < n
402
+ char = string[i]
403
+ case
404
+ when char == ?\b then result << '\b'
405
+ when char == ?\t then result << '\t'
406
+ when char == ?\n then result << '\n'
407
+ when char == ?\f then result << '\f'
408
+ when char == ?\r then result << '\r'
409
+ when char == ?" then result << '\"'
410
+ when char == ?\\ then result << '\\'
411
+ when char.between?(0x0, 0x1f) then result << "\\u%04x" % char
412
+ when char.between?(0x20, 0x7f) then result << char
413
+ when !(JSON.support_unicode? && $KCODE == 'UTF8')
414
+ # if utf8 mode is switched off or unicode not supported, just pass
415
+ # bytes through:
416
+ result << char
417
+ when char & 0xe0 == 0xc0
418
+ result << '\u' << utf8_to_utf16(string[i, 2])
419
+ i += 1
420
+ when char & 0xf0 == 0xe0
421
+ result << '\u' << utf8_to_utf16(string[i, 3])
422
+ i += 2
423
+ when char & 0xf8 == 0xf0
424
+ result << '\u' << utf8_to_utf16(string[i, 4])
425
+ i += 3
426
+ when char & 0xfc == 0xf8
427
+ result << '\u' << utf8_to_utf16(string[i, 5])
428
+ i += 4
429
+ when char & 0xfe == 0xfc
430
+ result << '\u' << utf8_to_utf16(string[i, 6])
431
+ i += 5
432
+ else
433
+ raise JSON::UnparserError, "Encountered unknown UTF-8 byte: %x!" % char
434
+ end
435
+ i += 1
436
+ end
437
+ result
438
+ end
439
+
440
+ # Parse the JSON string _source_ into a Ruby data structure and return it.
441
+ def parse(source)
442
+ Parser.new(source).parse
443
+ end
444
+
445
+ # Unparse the Ruby data structure _obj_ into a single line JSON string and
446
+ # return it. _state_ is a JSON::State object, that can be used to configure
447
+ # the output further.
448
+ def unparse(obj, state = nil)
449
+ obj.to_json(JSON::State.from_state(state))
450
+ end
451
+
452
+ # Unparse the Ruby data structure _obj_ into a JSON string and return it.
453
+ # The returned string is a prettier form of the string returned by #unparse.
454
+ def pretty_unparse(obj)
455
+ state = JSON::State.new(
456
+ :indent => ' ',
457
+ :space => ' ',
458
+ :object_nl => "\n",
459
+ :array_nl => "\n"
460
+ )
461
+ obj.to_json(state)
462
+ end
463
+ end
464
+
465
+ class Object
466
+ # Converts this object to a string (calling #to_s), converts
467
+ # it to a JSON string, and returns the result. This is a fallback, if no
468
+ # special method #to_json was defined for some object.
469
+ # _state_ is a JSON::State object, that can also be used
470
+ # to configure the produced JSON string output further.
471
+
472
+ def to_json(*) to_s.to_json end
473
+ end
474
+
475
+ class Hash
476
+ # Returns a JSON string containing a JSON object, that is unparsed from
477
+ # this Hash instance.
478
+ # _state_ is a JSON::State object, that can also be used to configure the
479
+ # produced JSON string output further.
480
+ # _depth_ is used to find out nesting depth, to indent accordingly.
481
+ def to_json(state = nil, depth = 0)
482
+ state = JSON::State.from_state(state)
483
+ json_check_circular(state) { json_transform(state, depth) }
484
+ end
485
+
486
+ private
487
+
488
+ def json_check_circular(state)
489
+ if state
490
+ state.seen?(self) and raise JSON::CircularDatastructure,
491
+ "circular data structures not supported!"
492
+ state.remember self
493
+ end
494
+ yield
495
+ ensure
496
+ state and state.forget self
497
+ end
498
+
499
+ def json_shift(state, depth)
500
+ state and not state.object_nl.empty? or return ''
501
+ state.indent * depth
502
+ end
503
+
504
+ def json_transform(state, depth)
505
+ delim = ','
506
+ delim << state.object_nl if state
507
+ result = '{'
508
+ result << state.object_nl if state
509
+ result << map { |key,value|
510
+ json_shift(state, depth + 1) <<
511
+ key.to_s.to_json(state, depth + 1) <<
512
+ ':' << state.space << value.to_json(state, depth + 1)
513
+ }.join(delim)
514
+ result << state.object_nl if state
515
+ result << json_shift(state, depth)
516
+ result << '}'
517
+ result
518
+ end
519
+ end
520
+
521
+ class Array
522
+ # Returns a JSON string containing a JSON array, that is unparsed from
523
+ # this Array instance.
524
+ # _state_ is a JSON::State object, that can also be used to configure the
525
+ # produced JSON string output further.
526
+ # _depth_ is used to find out nesting depth, to indent accordingly.
527
+ def to_json(state = nil, depth = 0)
528
+ state = JSON::State.from_state(state)
529
+ json_check_circular(state) { json_transform(state, depth) }
530
+ end
531
+
532
+ private
533
+
534
+ def json_check_circular(state)
535
+ if state
536
+ state.seen?(self) and raise JSON::CircularDatastructure,
537
+ "circular data structures not supported!"
538
+ state.remember self
539
+ end
540
+ yield
541
+ ensure
542
+ state and state.forget self
543
+ end
544
+
545
+ def json_shift(state, depth)
546
+ state and not state.array_nl.empty? or return ''
547
+ state.indent * depth
548
+ end
549
+
550
+ def json_transform(state, depth)
551
+ delim = ','
552
+ delim << state.array_nl if state
553
+ result = '['
554
+ result << state.array_nl if state
555
+ result << map { |value|
556
+ json_shift(state, depth + 1) << value.to_json(state, depth + 1)
557
+ }.join(delim)
558
+ result << state.array_nl if state
559
+ result << json_shift(state, depth)
560
+ result << ']'
561
+ result
562
+ end
563
+ end
564
+
565
+ class Integer
566
+ # Returns a JSON string representation for this Integer number.
567
+ def to_json(*) to_s end
568
+ end
569
+
570
+ class Float
571
+ # Returns a JSON string representation for this Float number.
572
+ def to_json(*) to_s end
573
+ end
574
+
575
+ class String
576
+ # This string should be encoded with UTF-8 (if JSON unicode support is
577
+ # enabled). A call to this method returns a JSON string
578
+ # encoded with UTF16 big endian characters as \u????. If
579
+ # JSON.support_unicode? is false only control characters are encoded this
580
+ # way, all 8-bit bytes are just passed through.
581
+ def to_json(*)
582
+ '"' << JSON::utf8_to_json(self) << '"'
583
+ end
584
+
585
+ # Raw Strings are JSON Objects (the raw bytes are stored in an array for the
586
+ # key "raw"). The Ruby String can be created by this class method.
587
+ def self.json_create(o)
588
+ o['raw'].pack('C*')
589
+ end
590
+
591
+ # This method creates a raw object, that can be nested into other data
592
+ # structures and will be unparsed as a raw string.
593
+ def to_json_raw_object
594
+ {
595
+ 'json_class' => self.class.name,
596
+ 'raw' => self.unpack('C*'),
597
+ }
598
+ end
599
+
600
+ # This method should be used, if you want to convert raw strings to JSON
601
+ # instead of UTF-8 strings, e. g. binary data (and JSON Unicode support is
602
+ # enabled).
603
+ def to_json_raw(*args)
604
+ to_json_raw_object.to_json(*args)
605
+ end
606
+ end
607
+
608
+ class TrueClass
609
+ # Returns a JSON string for true: 'true'.
610
+ def to_json(*) to_s end
611
+ end
612
+
613
+ class FalseClass
614
+ # Returns a JSON string for false: 'false'.
615
+ def to_json(*) to_s end
616
+ end
617
+
618
+ class NilClass
619
+ # Returns a JSON string for nil: 'null'.
620
+ def to_json(*) 'null' end
621
+ end
622
+
623
+ module Kernel
624
+ # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
625
+ # one line.
626
+ def j(*objs)
627
+ objs.each do |obj|
628
+ puts JSON::unparse(obj)
629
+ end
630
+ nil
631
+ end
632
+
633
+ # Ouputs _objs_ to STDOUT as JSON strings in a pretty format, with
634
+ # indentation and over many lines.
635
+ def jj(*objs)
636
+ objs.each do |obj|
637
+ puts JSON::pretty_unparse(obj)
638
+ end
639
+ nil
640
+ end
641
+ end
642
+
643
+ class Class
644
+ # Returns true, if this class can be used to create an instance
645
+ # from a serialised JSON string. The class has to implement a class
646
+ # method _json_create_ that expects a hash as first parameter, which includes
647
+ # the required data.
648
+ def json_creatable?
649
+ respond_to?(:json_create)
650
+ end
651
+ end
652
+ # vim: set et sw=2 ts=2: