Class: CouchShell::JsonValue

Inherits:
BasicObject
Defined in:
lib/couch-shell/json_value.rb

Overview

Wraps a Ruby data structure that represents a json value. If the wrapped document is of type object, members can be accessed method call syntax. To avoid shadowing of object members, almost all JsonValue instance methods end in ! or ?.

j = JsonValue.wrap({"a" => 1})
j.a             # => #<JsonValue 1>
j.unwrapped!    # => {"a" => 1}

Attributes can also be accessed via []

j["a"]          # => #<JsonValue 1>

Arrays elements too

j = JsonValue.wrap(["a", "b"])
j[0]            # => #<JsonValue "a">

The wrapped data structure mustn’t be modified.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, ruby_value) ⇒ JsonValue

Returns a new instance of JsonValue.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/couch-shell/json_value.rb', line 66

def initialize(value, ruby_value)
  @value = value
  @ruby_value = ruby_value
  @type = case @value
          when ::Hash
            :object
          when ::Array
            :array
          when ::String
            :string
          when ::Numeric
            :number
          when ::TrueClass
            :boolean
          when ::FalseClass
            :boolean
          when nil
            :null
          else
            ::Kernel.raise "#{value} is not of a valid json type"
          end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(msg, *args) ⇒ Object



119
120
121
122
123
124
125
126
127
# File 'lib/couch-shell/json_value.rb', line 119

def method_missing(msg, *args)
  if args.empty? && @type == :object
    msg_str = msg.to_s
    if @value.has_key?(msg_str)
      return @value[msg_str]
    end
  end
  super
end

Class Method Details

.parse(str) ⇒ Object



47
48
49
50
51
52
53
54
55
56
# File 'lib/couch-shell/json_value.rb', line 47

def self.parse(str)
  if str.start_with?("[") || str.start_with?("{") # optimization
    wrap(::JSON.parse(str))
  else
    # JSON parses only JSON documents, i.e. an object or an array. Thus we
    # box the given json value in an array and unbox it after parsing to
    # allow parsing of any json value.
    wrap(::JSON.parse("[#{str}]")[0])
  end
end

.rval(obj) ⇒ Object



58
59
60
61
62
63
64
# File 'lib/couch-shell/json_value.rb', line 58

def self.rval(obj)
  if obj.respond_to?(:couch_shell_ruby_value!)
    obj.couch_shell_ruby_value!
  else
    obj
  end
end

.wrap(ruby_value) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/couch-shell/json_value.rb', line 28

def self.wrap(ruby_value)
  case ruby_value
  when ::Hash
    h = ::Hash.new
    ruby_value.each { |k, v|
      h[k] = wrap(v)
    }
    JsonValue.new(h, ruby_value)
  when ::Array
    a = ::Array.new(ruby_value.size)
    ruby_value.each_with_index { |v, i|
      a[i] = wrap(v)
    }
    JsonValue.new(a, ruby_value)
  else
    JsonValue.new(ruby_value, ruby_value)
  end
end

Instance Method Details

#[](i) ⇒ Object

Access object member (i must be a string) or array element (i must be an integer). Returns a JsonValue or nil if the object member or array index doesn’t exist.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/couch-shell/json_value.rb', line 132

def [](i)
  ri = JsonValue.rval(i)
  case ri
  when ::String
    unless @type == :object
      ::Kernel.raise ::TypeError,
        "string indexing only allowed for objects"
    end
    @value[ri]
  when ::Integer
    unless @type == :array
      ::Kernel.raise ::TypeError,
        "integer indexing only allowed for arrays"
    end
    @value[ri]
  else
    ::Kernel.raise ::TypeError,
      "index must be string or integer"
  end
end

#array?Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/couch-shell/json_value.rb', line 93

def array?
  @type == :array
end

#attr_or_nil!(name) ⇒ Object



195
196
197
198
# File 'lib/couch-shell/json_value.rb', line 195

def attr_or_nil!(name)
  return nil unless @type == :object
  @value[name]
end

#boolean?Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/couch-shell/json_value.rb', line 105

def boolean?
  @type == :boolean
end

#couch_shell_format_string!Object



168
169
170
# File 'lib/couch-shell/json_value.rb', line 168

def couch_shell_format_string!
  to_s true
end

#couch_shell_ruby_value!Object Also known as: unwrapped!



186
187
188
# File 'lib/couch-shell/json_value.rb', line 186

def couch_shell_ruby_value!
  @ruby_value
end

#delete_attr!(name) ⇒ Object



172
173
174
175
176
# File 'lib/couch-shell/json_value.rb', line 172

def delete_attr!(name)
  ::Kernel.raise ::TypeError unless @type == :object
  @ruby_value.delete(name)
  @value.delete(name)
end

#inspectObject



200
201
202
# File 'lib/couch-shell/json_value.rb', line 200

def inspect
  "#<JsonValue #{to_s}>"
end

#lengthObject

Raises:

  • (::TypeError)


204
205
206
207
# File 'lib/couch-shell/json_value.rb', line 204

def length
  raise ::TypeError, "length of #@type" unless array?
  @ruby_value.length
end

#nil?Boolean

Returns:

  • (Boolean)


191
192
193
# File 'lib/couch-shell/json_value.rb', line 191

def nil?
  false
end

#null?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/couch-shell/json_value.rb', line 109

def null?
  @type == :null
end

#number?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/couch-shell/json_value.rb', line 101

def number?
  @type == :number
end

#object?Boolean

Returns:

  • (Boolean)


89
90
91
# File 'lib/couch-shell/json_value.rb', line 89

def object?
  @type == :object
end

#respond_to?(msg) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
117
# File 'lib/couch-shell/json_value.rb', line 113

def respond_to?(msg)
  msg == :couch_shell_format_string! || msg == :to_s ||
    msg == :couch_shell_ruby_value! ||
    (@type == :object && @value.has_key?(msg.to_s))
end

#set_attr!(name, value) ⇒ Object



178
179
180
181
182
183
184
# File 'lib/couch-shell/json_value.rb', line 178

def set_attr!(name, value)
  ::Kernel.raise ::TypeError unless @type == :object
  v = value.respond_to?(:couch_shell_ruby_value!) ?
    value.couch_shell_ruby_value! : value
  @ruby_value[name] = v
  @value[name] = JsonValue.wrap(v)
end

#string?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'lib/couch-shell/json_value.rb', line 97

def string?
  @type == :string
end

#to_s(format = false) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/couch-shell/json_value.rb', line 153

def to_s(format = false)
  case @type
  when :object, :array
    if format
      ::JSON.pretty_generate(@ruby_value)
    else
      ::JSON.generate(@ruby_value)
    end
  when :null
    "null"
  else
    @ruby_value.to_s
  end
end