public
Description: reimplementation of the ruby json gem for macruby using objc
Homepage:
Clone URL: git://github.com/mattetti/macruby-json.git
macruby-json / json.rb
100644 131 lines (117 sloc) 3.756 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# Check the ObjC source code available in src
# if you modify the source code, you will need to rebuild
# the dynlib and rename it BSJON.bundle
require File.join(File.dirname(__FILE__), 'lib', 'BSJSON')
 
ext_path = File.join(File.dirname(__FILE__), "core_ext")
require File.join(ext_path, 'array')
require File.join(ext_path, 'object')
require File.join(ext_path, 'range')
require File.join(ext_path, 'struct')
require File.join(ext_path, 'symbol')
require File.join(ext_path, 'date_and_time')
require File.join(ext_path, 'exception')
require File.join(ext_path, 'regexp')
require File.join(ext_path, 'enumerable')
 
module JSON
  
  # The base exception for JSON errors.
  class JSONError < StandardError; end
 
  # This exception is raised, if a parser error occurs.
  class ParserError < JSONError; end
 
  # This exception is raised, if the nesting of parsed datastructures is too
  # deep.
  class NestingError < ParserError; end
 
  # This exception is raised, if a generator or unparser error occurs.
  class GeneratorError < JSONError; end
  
  # Load a ruby data structure from a JSON _source_ and return it. A source can
  # either be a string-like object, an IO like object, or an object responding
  # to the read method. If _proc_ was given, it will be called with any nested
  # Ruby object as an argument recursively in depth first order.
  #
  # This method is part of the implementation of the load/dump interface of
  # Marshal and YAML.
  #
  # Example:
  #
  # JSON.load("[\"1\",\"2\",\"3\"]") # => ["1", "2", "3"]
  #
  # :api: public
  #
  def self.load(source, proc = nil)
    # only objects are supported at the moment
    #
    if source.respond_to? :to_str
      source = source.to_str
    elsif source.respond_to? :to_io
      source = source.to_io.read
    else
      source = source.read
    end
    
    begin
      result = Hash.dictionaryWithJSONString(source)
    rescue => e
      raise ParserError, e
    else
      recurse_proc(result, &proc) if proc
      ## TEMP LIMITED HACK
      if result.is_a?(Array)
        result.map do |obj|
          obj_d, obj_l = obj.doubleValue, obj.longValue
          obj_d == obj_l ? obj_l : obj_d
        end
      else
        result
      end
    ##
    end
    
  end
  
  def recurse_proc(result, &proc)
    case result
    when Array
      result.each { |x| recurse_proc x, &proc }
      proc.call result
    when Hash
      result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
      proc.call result
    else
      proc.call result
    end
  end
  private :recurse_proc
  module_function :recurse_proc
  
  # Convert an object into a json string
  #
  # Example:
  #
  # JSON.dump(["1", "2", "3"]) # => "[\"1\",\"2\",\"3\"]"
  #
  # :api: public
  #
  def self.dump(obj, anIO = nil, limit = nil)
    begin
      obj.to_json
    rescue => e
      raise GeneratorError, e
    end
  end
  
  def self.generate(obj, state = nil)
    puts "State not implemented yet" if state
    obj.to_json(state)
  end
  
  # Parse the JSON string _source_ into a Ruby data structure and return it.
  #
  # _opts_ can have the following
  # keys:
  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
  # structures. Disable depth checking with :max_nesting => false, it defaults
  # to 19.
  # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
  # defiance of RFC 4627 to be parsed by the Parser. This option defaults
  # to false.
  # * *create_additions*: If set to false, the Parser doesn't create
  # additions even if a matchin class and create_id was found. This option
  # defaults to true.
  def self.parse(source, opts = {})
    p "Options not supported yet" unless opts.empty?
    JSON.load(source)
  end
  
end