# This file is part of NIT ( http://www.nitlanguage.org ). # # Copyright 2014 Alexis Laferrière # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Dynamic interface to read Json strings. # # `String::to_json_value` returns a `JsonValue` which can be queried # to get the underlying Json data. It can also be used as any Json types. module dynamic private import static import standard class JsonValue var value: nullable Object # Is this value null? # # assert "null".to_json_value.is_null # assert not "123".to_json_value.is_null fun is_null: Bool do return value == null # Is this value an integer? # # assert "123".to_json_value.is_int # assert not "1.23".to_json_value.is_int # assert not "\"str\"".to_json_value.is_int fun is_int: Bool do return value isa Int # Get this value as a `Int` # # require: `self.is_int` # # assert "-10".to_json_value.to_i == -10 # assert "123".to_json_value.to_i == 123 fun to_i: Int do return value.as(Int) # Is this value a float? # # assert "0.0".to_json_value.is_float # assert "123.456".to_json_value.is_float # assert not "123".to_json_value.is_float fun is_float: Bool do return value isa Float # Get this value as a `Float` # # require: `self.is_float` # # assert "0.0".to_json_value.to_f == 0.0 # assert "123.456".to_json_value.to_f == 123.456 fun to_f: Float do return value.as(Float) # Is the value numeric? # # assert "1.234".to_json_value.is_numeric # assert "1234".to_json_value.is_numeric # assert not "\"str\"".to_json_value.is_numeric # assert not "1.2.3.4".to_json_value.is_numeric fun is_numeric: Bool do return is_int or is_float # Get this value as a `Numeric` # # require: `self.is_numeric` # # assert "1.234".to_json_value.to_numeric = 1.234 # assert "1234".to_json_value.to_numeric = 1234 fun to_numeric: Numeric do if is_int then return to_i return to_f end # Is this value a boolean? # # assert "true".to_json_value.is_bool # assert "false".to_json_value.is_bool fun is_bool: Bool do return value isa Bool # Get this value as a `Bool` # # require: `self.is_bool` # # assert "true".to_json_value.to_bool # assert not "false".to_json_value.to_bool fun to_bool: Bool do return value.as(Bool) # Is this value a string? # # assert "\"str\"".to_json_value.is_string # assert not "123".to_json_value.is_string fun is_string: Bool do return value isa String # Get this value as a `String` # # If value is null, return "null", otherwise returns `value.to_s`. It is practical # on most types, except maps which does not have a custom `to_s`. # # assert "\"str\"".to_json_value.to_s == "str" # assert "123".to_json_value.to_s == "123" # assert "true".to_json_value.to_s == "true" # assert "[1, 2, 3]".to_json_value.to_s == "123" redef fun to_s: String do if value == null then return "null" return value.to_s end ### Objects # Is this value a Json object (a map)? # # assert """{"a": 123}""".to_json_value.is_map # assert not "123".to_json_value.is_map fun is_map: Bool do return value isa HashMap[String, nullable Object] # Get this value as a `Map[String, JsonValue]` # # require: `self.is_map` fun to_map: Map[String, JsonValue] do var value = value assert value isa HashMap[String, nullable Object] var map = new HashMap[String, JsonValue] for k, v in value do map[k] = new JsonValue(v) return map end ### Arrays # Is this value an array? # # assert "[]".to_json_value.is_array # assert "[1, 2, 3, 4, 5]".to_json_value.is_array # assert "[null, true, false, 0.0, 1, \"str\"]".to_json_value.is_array # assert """["a", "b", "c"]""".to_json_value.is_array fun is_array: Bool do return value isa Array[nullable Object] # Get this value as an `Array[JsonValue]` # # require: `self.is_array` # # assert """["a", "b", "c"]""".to_json_value.to_a.join(", ") == "a, b, c" fun to_a: Array[JsonValue] do var value = value assert value isa Array[nullable Object] var a = new Array[JsonValue] for e in value do a.add(new JsonValue(e)) return a end # Iterator over the values of the array `self` # # require: `self.is_array` # # var a = new Array[String] # for e in """["a", "b", "c"]""".to_json_value do a.add(e.to_s) # assert a[0] == "a" # assert a[1] == "b" # assert a[2] == "c" fun iterator: Iterator[JsonValue] do return to_a.iterator # Get value at index `key` on the array or map `self` # # require: `self.is_array or self.is_map` # require: `self.is_array implies key isa Int` # # assert """{"a": 123}""".to_json_value["a"].to_i == 123 # assert """{"123": "a"}""".to_json_value[123].to_s == "a" # assert """{"John Smith": 1980}""".to_json_value[["John ", "Smith"]].to_i == 1980 # # assert """["a", "b", "c"]""".to_json_value[0].to_s == "a" fun [](key: Object): JsonValue do var value = value if value isa HashMap[String, nullable Object] then return new JsonValue(value[key.to_s]) else if value isa Array[nullable Object] then assert key isa Int return new JsonValue(value[key]) else abort end # Advanced query to get a value within the map `self` or it's children. # # A query is composed of the keys to each map seperated by '.'. # # require: `self.is_map` # # assert """{"a": {"t": true, "f": false}}""".to_json_value.get("a").is_map # assert """{"a": {"t": true, "f": false}}""".to_json_value.get("a.t").to_bool # assert not """{"a": {"t": true, "f": false}}""".to_json_value.get("a.f").to_bool # assert """{"a": {"b": {"c": {"d": 123}}}}""".to_json_value.get("a.b.c.d").to_i == 123 fun get(query: String): JsonValue do var keys = query.split(".") var value = value for key in keys do assert value isa HashMap[String, nullable Object] value = value[key] end return new JsonValue(value) end end redef class String # Parse `self` to obtain a `JsonValue` fun to_json_value: JsonValue do var value = json_to_nit_object return new JsonValue(value) end end