[json-glib/get-with-default: 2/2] Add with_default() variant for JsonObject getters



commit 5b816ff8df9e563c1e9c3ae05ee97d46924f9b40
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Tue Nov 14 17:16:40 2017 +0000

    Add with_default() variant for JsonObject getters
    
    When using the typed getters for JsonObject, the existing API will
    automatically fail if the member requested is not present. This is
    generally good practice, because JSON data typically does not have a
    schema, and thus is has to be validated "on the go"; a JSON object
    member that contains `null`, or `0`, or `false`, is indistinguishable
    from a JSON object member that does not exist, so we cannot simply
    return a scalar value and be done with it.
    
    We can provide an escape hatch, though, for the crowd writing parsers
    for JSON data; by using Python as the model, we can add methods that
    take a default value as a parameter, and return it as a fallback value
    if the requested object member does not exist, or if it's set to `null`.

 doc/json-glib-sections.txt |  12 ++-
 json-glib/json-object.c    | 205 +++++++++++++++++++++++++++++----------------
 json-glib/json-types.h     |  38 ++++++---
 json-glib/tests/object.c   |  20 +++++
 4 files changed, 186 insertions(+), 89 deletions(-)
---
diff --git a/doc/json-glib-sections.txt b/doc/json-glib-sections.txt
index 44942c4..ada0895 100644
--- a/doc/json-glib-sections.txt
+++ b/doc/json-glib-sections.txt
@@ -31,18 +31,22 @@ json_object_iter_next
 <SUBSECTION>
 json_object_set_array_member
 json_object_get_array_member
+json_object_set_object_member
+json_object_get_object_member
+json_object_set_null_member
+json_object_get_null_member
 json_object_set_boolean_member
 json_object_get_boolean_member
+json_object_get_boolean_member_with_default
 json_object_set_double_member
 json_object_get_double_member
+json_object_get_double_member_with_default
 json_object_set_int_member
 json_object_get_int_member
-json_object_set_null_member
-json_object_get_null_member
-json_object_set_object_member
-json_object_get_object_member
+json_object_get_int_member_with_default
 json_object_set_string_member
 json_object_get_string_member
+json_object_get_string_member_with_default
 
 <SUBSECTION Private>
 JSON_TYPE_OBJECT
diff --git a/json-glib/json-object.c b/json-glib/json-object.c
index 29b9401..bb33ec0 100644
--- a/json-glib/json-object.c
+++ b/json-glib/json-object.c
@@ -579,10 +579,50 @@ json_object_get_member (JsonObject  *object,
   return object_get_member_internal (object, member_name);
 }
 
+#define JSON_OBJECT_GET(ret_type,type_name) \
+ret_type \
+json_object_get_ ##type_name## _member (JsonObject *object, \
+                                        const char *member_name) \
+{ \
+  g_return_val_if_fail (object != NULL, (ret_type) 0); \
+  g_return_val_if_fail (member_name != NULL, (ret_type) 0); \
+\
+  JsonNode *node = object_get_member_internal (object, member_name); \
+  g_return_val_if_fail (node != NULL, (ret_type) 0); \
+\
+  if (JSON_NODE_HOLDS_NULL (node)) \
+    return (ret_type) 0; \
+\
+  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, (ret_type) 0); \
+\
+  return json_node_get_ ##type_name (node); \
+}
+
+#define JSON_OBJECT_GET_DEFAULT(ret_type,type_name) \
+ret_type \
+json_object_get_ ##type_name## _member_with_default (JsonObject *object, \
+                                                     const char *member_name, \
+                                                     ret_type    default_value) \
+{ \
+  g_return_val_if_fail (object != NULL, default_value); \
+  g_return_val_if_fail (member_name != NULL, default_value); \
+\
+  JsonNode *node = object_get_member_internal (object, member_name); \
+  if (node == NULL) \
+    return default_value; \
+\
+  if (JSON_NODE_HOLDS_NULL (node)) \
+    return default_value; \
+\
+  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, default_value); \
+\
+  return json_node_get_ ##type_name (node); \
+}
+
 /**
  * json_object_get_int_member:
  * @object: a #JsonObject
- * @member_name: the name of the member
+ * @member_name: the name of the @object member
  *
  * Convenience function that retrieves the integer value
  * stored in @member_name of @object
@@ -593,21 +633,26 @@ json_object_get_member (JsonObject  *object,
  *
  * Since: 0.8
  */
-gint64
-json_object_get_int_member (JsonObject  *object,
-                            const gchar *member_name)
-{
-  JsonNode *node;
-
-  g_return_val_if_fail (object != NULL, 0);
-  g_return_val_if_fail (member_name != NULL, 0);
+JSON_OBJECT_GET (gint64, int)
 
-  node = object_get_member_internal (object, member_name);
-  g_return_val_if_fail (node != NULL, 0);
-  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0);
-
-  return json_node_get_int (node);
-}
+/**
+ * json_object_get_int_member_with_default:
+ * @object: a #JsonObject
+ * @member_name: the name of the @object member
+ * @default_value: the value to return if @member_name is not valid
+ *
+ * Convenience function that retrieves the integer value
+ * stored in @member_name of @object.
+ *
+ * If @member_name does not exist, does not contain a scalar value,
+ * or contains `null`, then @default_value is returned instead.
+ *
+ * Returns: the integer value of the object's member, or the
+ *   given default
+ *
+ * Since: 1.6
+ */
+JSON_OBJECT_GET_DEFAULT (gint64, int)
 
 /**
  * json_object_get_double_member:
@@ -623,21 +668,26 @@ json_object_get_int_member (JsonObject  *object,
  *
  * Since: 0.8
  */
-gdouble
-json_object_get_double_member (JsonObject  *object,
-                               const gchar *member_name)
-{
-  JsonNode *node;
-
-  g_return_val_if_fail (object != NULL, 0.0);
-  g_return_val_if_fail (member_name != NULL, 0.0);
-
-  node = object_get_member_internal (object, member_name);
-  g_return_val_if_fail (node != NULL, 0.0);
-  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0.0);
+JSON_OBJECT_GET (gdouble, double)
 
-  return json_node_get_double (node);
-}
+/**
+ * json_object_get_double_member_with_default:
+ * @object: a #JsonObject
+ * @member_name: the name of the @object member
+ * @default_value: the value to return if @member_name is not valid
+ *
+ * Convenience function that retrieves the floating point value
+ * stored in @member_name of @object.
+ *
+ * If @member_name does not exist, does not contain a scalar value,
+ * or contains `null`, then @default_value is returned instead.
+ *
+ * Returns: the floating point value of the object's member, or the
+ *   given default
+ *
+ * Since: 1.6
+ */
+JSON_OBJECT_GET_DEFAULT (double, double)
 
 /**
  * json_object_get_boolean_member:
@@ -653,21 +703,61 @@ json_object_get_double_member (JsonObject  *object,
  *
  * Since: 0.8
  */
-gboolean
-json_object_get_boolean_member (JsonObject  *object,
-                                const gchar *member_name)
-{
-  JsonNode *node;
+JSON_OBJECT_GET (gboolean, boolean)
 
-  g_return_val_if_fail (object != NULL, FALSE);
-  g_return_val_if_fail (member_name != NULL, FALSE);
+/**
+ * json_object_get_boolean_member_with_default:
+ * @object: a #JsonObject
+ * @member_name: the name of the @object member
+ * @default_value: the value to return if @member_name is not valid
+ *
+ * Convenience function that retrieves the boolean value
+ * stored in @member_name of @object.
+ *
+ * If @member_name does not exist, does not contain a scalar value,
+ * or contains `null`, then @default_value is returned instead.
+ *
+ * Returns: the boolean value of the object's member, or the
+ *   given default
+ *
+ * Since: 1.6
+ */
+JSON_OBJECT_GET_DEFAULT (gboolean, boolean)
 
-  node = object_get_member_internal (object, member_name);
-  g_return_val_if_fail (node != NULL, FALSE);
-  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, FALSE);
+/**
+ * json_object_get_string_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function that retrieves the string value
+ * stored in @member_name of @object
+ *
+ * See also: json_object_get_member()
+ *
+ * Return value: the string value of the object's member
+ *
+ * Since: 0.8
+ */
+JSON_OBJECT_GET (const gchar *, string)
 
-  return json_node_get_boolean (node);
-}
+/**
+ * json_object_get_string_member_with_default:
+ * @object: a #JsonObject
+ * @member_name: the name of the @object member
+ * @default_value: the value to return if @member_name is not valid
+ *
+ * Convenience function that retrieves the string value
+ * stored in @member_name of @object.
+ *
+ * If @member_name does not exist, does not contain a scalar value,
+ * or contains `null`, then @default_value is returned instead.
+ *
+ * Returns: the string value of the object's member, or the
+ *   given default
+ *
+ * Since: 1.6
+ */
+JSON_OBJECT_GET_DEFAULT (const char *, string)
 
 /**
  * json_object_get_null_member:
@@ -708,39 +798,6 @@ json_object_get_null_member (JsonObject  *object,
 }
 
 /**
- * json_object_get_string_member:
- * @object: a #JsonObject
- * @member_name: the name of the member
- *
- * Convenience function that retrieves the string value
- * stored in @member_name of @object
- *
- * See also: json_object_get_member()
- *
- * Return value: the string value of the object's member
- *
- * Since: 0.8
- */
-const gchar *
-json_object_get_string_member (JsonObject  *object,
-                               const gchar *member_name)
-{
-  JsonNode *node;
-
-  g_return_val_if_fail (object != NULL, NULL);
-  g_return_val_if_fail (member_name != NULL, NULL);
-
-  node = object_get_member_internal (object, member_name);
-  g_return_val_if_fail (node != NULL, NULL);
-  g_return_val_if_fail (JSON_NODE_HOLDS_VALUE (node) || JSON_NODE_HOLDS_NULL (node), NULL);
-
-  if (JSON_NODE_HOLDS_NULL (node))
-    return NULL;
-
-  return json_node_get_string (node);
-}
-
-/**
  * json_object_get_array_member:
  * @object: a #JsonObject
  * @member_name: the name of the member
diff --git a/json-glib/json-types.h b/json-glib/json-types.h
index d845f94..220b706 100644
--- a/json-glib/json-types.h
+++ b/json-glib/json-types.h
@@ -358,17 +358,33 @@ JSON_AVAILABLE_IN_1_0
 JsonNode *            json_object_dup_member         (JsonObject  *object,
                                                       const gchar *member_name);
 JSON_AVAILABLE_IN_1_0
-gint64                json_object_get_int_member     (JsonObject  *object,
-                                                      const gchar *member_name);
-JSON_AVAILABLE_IN_1_0
-gdouble               json_object_get_double_member  (JsonObject  *object,
-                                                      const gchar *member_name);
-JSON_AVAILABLE_IN_1_0
-gboolean              json_object_get_boolean_member (JsonObject  *object,
-                                                      const gchar *member_name);
-JSON_AVAILABLE_IN_1_0
-const gchar *         json_object_get_string_member  (JsonObject  *object,
-                                                      const gchar *member_name);
+gint64                json_object_get_int_member                        (JsonObject  *object,
+                                                                         const gchar *member_name);
+JSON_AVAILABLE_IN_1_6
+gint64                json_object_get_int_member_with_default           (JsonObject  *object,
+                                                                         const char  *member_name,
+                                                                        gint64       default_value);
+JSON_AVAILABLE_IN_1_0
+gdouble               json_object_get_double_member                     (JsonObject  *object,
+                                                                         const gchar *member_name);
+JSON_AVAILABLE_IN_1_6
+double                json_object_get_double_member_with_default        (JsonObject  *object,
+                                                                         const char  *member_name,
+                                                                         double       default_value);
+JSON_AVAILABLE_IN_1_0
+gboolean              json_object_get_boolean_member                    (JsonObject  *object,
+                                                                         const gchar *member_name);
+JSON_AVAILABLE_IN_1_6
+gboolean              json_object_get_boolean_member_with_default       (JsonObject  *object,
+                                                                         const char  *member_name,
+                                                                         gboolean     default_value);
+JSON_AVAILABLE_IN_1_0
+const gchar *         json_object_get_string_member                     (JsonObject  *object,
+                                                                         const gchar *member_name);
+JSON_AVAILABLE_IN_1_6
+const char *          json_object_get_string_member_with_default        (JsonObject  *object,
+                                                                         const char  *member_name,
+                                                                         const char  *default_value);
 JSON_AVAILABLE_IN_1_0
 gboolean              json_object_get_null_member    (JsonObject  *object,
                                                       const gchar *member_name);
diff --git a/json-glib/tests/object.c b/json-glib/tests/object.c
index 03a478c..772265a 100644
--- a/json-glib/tests/object.c
+++ b/json-glib/tests/object.c
@@ -71,6 +71,25 @@ test_set_member (void)
 }
 
 static void
+test_get_member_default (void)
+{
+  JsonObject *object = json_object_new ();
+
+  json_object_set_int_member (object, "foo", 42);
+  json_object_set_boolean_member (object, "bar", TRUE);
+  json_object_set_string_member (object, "hello", "world");
+
+  g_assert_cmpint (json_object_get_int_member_with_default (object, "foo", 47), ==, 42);
+  g_assert_true (json_object_get_boolean_member_with_default (object, "bar", FALSE));
+  g_assert_cmpstr (json_object_get_string_member_with_default (object, "hello", "wisconsin"), ==, "world");
+
+  g_assert_cmpint (json_object_get_int_member_with_default (object, "no", 4), ==, 4);
+  g_assert_cmpstr (json_object_get_string_member_with_default (object, "doesNotExist", "indeed"), ==, 
"indeed");
+
+  json_object_unref (object);
+}
+
+static void
 test_remove_member (void)
 {
   JsonObject *object = json_object_new ();
@@ -204,6 +223,7 @@ main (int   argc,
   g_test_add_func ("/object/empty-object", test_empty_object);
   g_test_add_func ("/object/add-member", test_add_member);
   g_test_add_func ("/object/set-member", test_set_member);
+  g_test_add_func ("/object/get-member-default", test_get_member_default);
   g_test_add_func ("/object/remove-member", test_remove_member);
   g_test_add_func ("/object/foreach-member", test_foreach_member);
   g_test_add_func ("/object/iter", test_iter);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]