Code:

A Working Example of glib-utility.h

Previously: Using glib-utility.h

What follows is a sample of how I presently use glib-utility.h in my own code.

AnObject - The Root Class

For the purposes of my code, I define a class named AnObject, which serves as the sole ancestor for all other classes. You will see more of AnObject as we get into the code required to write a computer programming language.

Definition

Below is the definition of AnObject, contained within a file named base/classwork.h. You can see that I comment my code for documentation with Doxygen.

/** \file
    This file defines the base class, from which nearly all others are derived.
*/

#include "utility/glib-utility.h"

// AnObject ********************************************************************
/// The base class, from which nearly all others are derived
/** \struct AnObject
    This class adds only a little functionality to what is already provided
    by GObject.

    \extends GObject
*/

g_class(AnObject, GObject, AN_OBJECT, an_object,
  g_instance(
    /* <private> */
    /** \private Stores the display name of the class */
    gpointer DisplayName;
  ),
  /** \virtual Retrieve the name of the object */
  def(char *)(*name)(AnObject *Self);
)

/// Type identity of AnObject
#define AN_OBJECT_TYPE (an_object_get_type())

/// Construct a new instance of AnObject or one of its descendants \memberof AnObject
/** Construct a new instance of AnObject or one of its descendants.

    This method simply calls `g_object_new()` without any construction
    properties.  It is designed to be used on AnObject and its descendants, as
    these classes use specialized constructors rather than construction
    properties (or, indeed, ANY properties provided through GObject).

    \memberof AnObject
*/

#define an_object_new(objectType) \
  g_object_new(objectType, nil)


/// Free an instance of AnObject or one of its descendants \memberof AnObject
/** Free an instance of AnObject or one of its descendants.

    This method simply calls `g_object_unref()` on the specified
    \p Instance.  It is provided for the sake of symmetry and clearness of code.

    \memberof AnObject
*/

#define an_object_free(Instance) \
  g_object_unref(Instance)


// Properties ------------------------------------------------------------------
/** \properties{AnObject} @{ */
/// Return the class name of the class or instance \memberof AnObject
def(const char *) an_object_class_name(AnObject *Self);

/// Construct a display name for the class or instance \memberof AnObject
def(char *) an_object_display_name(AnObject *Self);

/// \virtual Retrieve the name of the class or instance \memberof AnObject
/** Retrieve the name of the object.

    This function is designed so that the name of any descendant of AnObject
    can easily be retrieved.  The value actually returned by this function will
    vary depending on the class; in the base implementation of AnObject, the
    value returned is simply the display name of the class.

    \see an_object_display_name() for details.

    \return The name of the object.  The value of this string will vary
    depending upon the class implementing it.  The caller should NOT free the
    string returned by this method.

    \memberof AnObject
*/

#define an_object_name(Self) \
  ( IS_AN_OBJECT(Self)? AN_OBJECT_GET_CLASS(Self)->name(Self): nil )

/// @}

Implementation

Here is the source file that actually implements AnObject: base/classwork.c. You can see that AnObject provides a method -- an_object_display_name() -- that is useful for debugging output. It also provides a method to retrieve the class name, which does not require the GObject macros and so makes code easier to read, in my opinion. Finally, you can see how g_class_init(), g_instance_init(), and g_instance_dispose() are used.

/** \file
    This file implements the base class, from which nearly all others are
    derived.
*/

#include <glib/gprintf.h>
#include "base/classwork.h"
#include "string/cstrings.h"

// AnObject ********************************************************************
/** Return the name of the class or instance.

    This method simply calls `G_OBJECT_CLASS_NAME()` to obtain the name
    of the class as it was defined during registration with the GType system.
    The calling routine should NOT attempt to free the string returned by this
    function.

    \memberof AnObject
*/

def(const char *) an_object_class_name(AnObject *Self)
{
  return G_OBJECT_CLASS_NAME(AN_OBJECT_GET_CLASS(Self));
}

/** Construct a display name for the class.

    The first time this method is called, it calculates the display name of the
    class using the class name specified when the given class was registered
    with the GType system and the following rules:

    - A space is inserted wherever a transition between ASCII case occurs.
    - All characters are converted to ASCII lower case.
    - If #HideSingularArticles is defined and the class name begins with 'a'
      or 'an', that word is removed.

    If this method was called on a class named "ABalloonAnimal", it would
    construct a display name that reads "a balloon animal".

    The resulting display name is stored in a private field, and subsequent
    calls to this method will return a reference to that string, since it is
    assumed that the name of the class -- and therefore its display name -- will
    never change.  This method is designed specifically for debugging or
    status output, and is used for that purpose by several classes.

    \return A string containing the calculated display name of the class, as
    described above.  This string should NOT be freed by the caller, as it is
    a private field belonging to the instance of AnObject and will be freed when
    the instance itself is freed.

    \memberof AnObject
*/

def(char *) an_object_display_name(AnObject *Self)
{
  // Stores the length of the class name
  gsize nameLength = 0;
  // Refers to a character retrieved from the class name
  gchar *character = nil;
  // Stores the previous character retrieved from the string
  gchar previousCharacter = 'A';
  // A loop counter
  guint32 i = 0;

  g_if_fail(IS_AN_OBJECT(Self),
      return nil;
  )

  if ( a_string_is_empty(Self->DisplayName) == false ) then
    return a_string_text(Self->DisplayName);

  if (Self->DisplayName == nil) then
    Self->DisplayName = an_object_new(A_STRING_TYPE);

  // Get the name of the class
  character = an_object_class_name(Self);
  nameLength = strlen(character);

  // Loop through each character in the string
  for (i = 0; i < nameLength; i++) {
    // Insert spaces into the output where needed
    if ( g_ascii_isupper(*character) ) then {
      /* When making a transition between upper- and lower-case characters,
         a space will be inserted before the upper-case character.  This
         allows classes with names such as 'AMySQLClass' to be rendered
         correctly ('a mysql class' instead of 'a my sqlclass').
      */

      if ( (i < nameLength) and
        (g_ascii_isupper(*(character + sizeof(char))) == false) ) then
        a_string_append_character(Self->DisplayName, ' ');

      /* When making a transition between lower- and upper-case characters,
        a space will be inserted before the upper-case character.
      */

      else if ( g_ascii_isupper(previousCharacter) == false ) then
        a_string_append_character(Self->DisplayName, ' ');
    }

  #ifdef HideSingularArticles
    // Remove singular articles from the string
    if ( (a_string_equals_constant(Self->DisplayName, " a")) or
      (a_string_equals_constant(Self->DisplayName, "a ")) or
      (a_string_equals_constant(Self->DisplayName, "n ")) ) then
      a_string_empty(Self->DisplayName);

  #else
    if ( (a_string_equals_constant(Self->DisplayName, " a")) ) then
    {
      a_string_empty(Self->DisplayName);
      a_string_set_text(Self->DisplayName, "a", sizeof(char));
    }
  #endif

    a_string_append_character(Self->DisplayName, g_ascii_tolower(*character));
    previousCharacter = *character;
    character++;
  }

  return a_string_text(Self->DisplayName);
}

// Class implementation --------------------------------------------------------
g_class_implement(AnObject, G_TYPE_OBJECT, AN_OBJECT, an_object,
  g_class_preamble(),
  g_class_typedef(),
  g_class_init(
    // Establish virtual methods
    Self->name = an_object_display_name;
  ),

  g_instance_init(
    // Establish private attributes
    Self->DisplayName = nil;
  ),

  g_instance_dispose(
    // Free the display name
    if ( Self->DisplayName != nil ) then {
      g_object_unref(Self->DisplayName);
      Self->DisplayName = nil;
    }
  ),

  g_instance_finalize()
)

Conclusion

This provides a general overview of the way in which I will be utilizing GLib and GObject to construct a parser for a programming language. More documentation will be forthcoming as I post examples and, eventually, the entire source code of the language parser; however, the source for glib-utility.h is available now, and it is well-documented with comments, if you'd like to peruse those.

Thanks for reading!