Here are some examples of simple cog graphs.
We’ll use the following symbology:
Cogs are flexible and mutable, so don’t have a fixed type or behavior. However, it is useful to classify nodes according to the type of data they contain, their connections with their child nodes, and how you expect to interact with them.
A “list-like branch node” is a cog node that acts more like a list of values. You can use it in other ways, but in general it is intended to be used like a list.
Similarly, an “association-like branch node” is a cog node that acts more like an association between names (keys) and values, like a Partner Naming or a java.util.Map.
A “structure-like branch node” is a cog node that acts more like an association between specific field names and values, like a database record, a C struct, or the properties in a Java class.
A “value-like leaf node” is a cog node that acts more like a single value; the value itself is generally held in the data portion of the cog node.
This cog graph represents a simple list of string values. They are in a specific order, but have no names, ids, or other information. The root node represents the list as a whole, and it contains one child node per entry. Those children are leaf nodes, and the entry values are stored in the leaf nodes’ data property.
Here is how you might build such a list in Java, using the cog builder method addObject():
// create days as a list
days = new Cog();
days.addObject("Sunday");
days.addObject("Monday");
days.addObject("Happy Days");
days.addObject("Tuesday");
days.addObject("Wednesday");
days.addObject("Happy Days");
days.addObject("Thursday");
days.addObject("Friday");
days.addObject("Happy Days");
days.addObject("Saturday");
days.addObject("What A Day");
Here’s how you might iterate through it using the child nodes:
// iterate through the child nodes as cogs
for (day in days) {
log.info(day.getData());
}
And this converts it to a list first, eliminating the need to deal with the child nodes at all:
// iterate through it as a normal List
for (day in days.toList()) {
log.info(day);
}
If you write it out to an XML file, it looks like this:
<?xml version='1.0' encoding='utf-8'?>
<cog>
<node>
<node>
Sunday
</node>
<node>
Monday
</node>
<node>
Happy Days
</node>
<node>
Tuesday
</node>
<node>
Wednesday
</node>
<node>
Happy Days
</node>
<node>
Thursday
</node>
<node>
Friday
</node>
<node>
Happy Days
</node>
<node>
Saturday
</node>
<node>
What A Day
</node>
</node>
</cog>
This cog graph represents an associative mapping of unique product names to prices. Note the oval leaf nodes; the top part of the label is the cog node’s name as returned by getName(), and the price is the cog node’s data object as returned by getData().
The names must be unique for lookups to work correctly, but values do not have to be unique.
Here is some builder code, storing prices as a Java double or as a string - either work:
// create prices as an association
prices = new Cog();
prices.putString("Burger", "3.95");
prices.putDouble("Fries", 1.95);
prices.putDouble("Shake", 2.95);
// iterate through the child nodes as cogs
for (price in prices) {
log.info(price.getName() + " = " + price.getData());
}
// iterate through it as a Naming
for (price in prices.toNaming().entrySet()) {
log.info(price.getKey() + " = " + price.getValue());
}
// get a specific value, type conversion from String is automatic
burgerPrice = prices.getDouble("Burger");
XML:
<?xml version='1.0' encoding='utf-8'?>
<cog>
<node>
<String name='Burger'>
3.95
</String>
<Number name='Fries'>
1.95
</Number>
<Number name='Shake'>
2.95
</Number>
</node>
</cog>
This cog graph represents a list of dogs. The dogs are represented by structure-like nodes. These work the same as association-type nodes, but presumably have a predefined and standard set of keys representing field names rather than a more arbitrary list of keys representing the names of the contained values.
If we were to define Dog as a Java class, it might look like this:
public class Dog {
public String name;
public String breed;
public String color;
public String disposition;
}
That’s a fairly primitive implementation, though - we greatly discourage public properties, for example. Here’s a more complete example, implementing the Coggable interface:
import com.partnersoft.v5.boots.cog.Coggable;
import com.partnersoft.v5.boots.cog.Cog;
public class Dog {
//-- properties --\\
private String name;
private String breed;
private String color;
private String disposition;
//-- constructors --\\
public Dog() {
}
public Dog(Cog state) {
name = state.getName();
breed = state.getString("breed");
color = state.getString("color");
disposition = state.getString("disposition");
}
//-- Coggable homework --\\
public Cog toCog() {
Cog state = new Cog();
state.setTypeName("Dog");
state.setName(name);
state.putString("breed", breed);
state.putString("color", color);
state.putString("disposition", disposition);
return state;
}
//-- Object homework --\\
public String toString() {
return name + " goggeh";
}
//-- accessors --\\
public String getName() {
return name;
}
public void setName(String newName) {
name = newName;
}
public String getBreed() {
return breed;
}
public void setBreed(String newBreed) {
breed = newBreed;
}
public String getColor() {
return color;
}
public void setColor(String newColor) {
color = newColor;
}
public String getDisposition() {
return disposition;
}
public void setColor(String newColor) {
color = newColor;
}
}
?and that might give you some idea of why we need Cog; that’s a lot of code just to properly represent something in Java.
The above example does illustrate some important things, however.
First, name is not a key for a value in a child node - it is the name of the parent node, the “dog” object. You access it, not with a getString() method, but with simply getName().
Second, this is a simple but complete example of implementing a Coggable Java class. This class can now be converted back and forth to Cog and can therefore be saved to and loaded from Cog .xml files. The constructor Dog(Cog state) and the toCog() method are usually boring and obvious like this, but they come into their own when you have to do something complicated, or have to deal with older data that needs manipulation to load into a new model.
There’s a variety of ways you can construct this cog graph. One is to create the objects (POJOs) using normal Java construction, then convert to a cog:
// create POJOs (plain ol' java objects)
lily = new Dog();
lily.setName("Lily");
lily.setBreed("Bulldog Mix");
lily.setColor("White with Spots");
lily.setDisposition("Calm");
della = new Dog();
della.setName("Della");
della.setBreed("Collie Mix");
della.setColor("Black and White");
della.setDisposition("Excitable");
// put them in a list
list = new ArrayList();
list.add(lily);
list.add(della);
// convert to a cog
cog = CogLib.convertToCog(list);
Another is to build the cog directly:
lily = new Cog();
lily.setName("Lily");
lily.putString("breed", "Bulldog Mix");
lily.putString("color", "White with Spots");
lily.putString("disposition", "Calm");
della = new Cog();
della.setName("Della");
della.putString("breed", "Collie Mix");
della.putString("color", "Black and White");
della.putString("color", "Excitable");
dogs = new Cog();
dogs.add(lily);
dogs.add(della);
For yet another, we’ll use paths to set the deeper nodes in the graph:
dogs = new Cog();
dogs.add("Dog", "Lily");
dogs.putString("Lily/breed", "Bulldog Mix");
dogs.putString("Lily/color", "White with Spots");
dogs.putString("Lily/disposition", "Calm");
dogs.add("Dog", "Della");
dogs.putString("Della/breed", "Collie Mix");
dogs.putString("Della/color", "Black and White");
dogs.putString("Della/color", "Excitable");
The add() method isn’t strictly necessary; the Dog nodes are created automatically if they aren’t available when you use a pathed putString(). However, this way you also set the type name of the nodes to “Dog”.
The add() method actually creates and returns a node, so you could use the result to then set individual properties, like this:
dogs = new Cog();
lily = dogs.add("Dog", "Lily");
lily.putString("breed", "Bulldog Mix");
lily.putString("color", "White with Spots");
lily.putString("disposition", "Calm");
della = dogs.add("Dog", "Della");
della.putString("breed", "Collie Mix");
della.putString("color", "Black and White");
della.putString("color", "Excitable");
Assuming you set the type names, your results should look something like this in XML:
<?xml version='1.0' encoding='utf-8'?>
<cog>
<node>
<Dog name='Lily'>
<String name='breed'>
Bulldog Mix
</String>
<String name='color'>
White with Spots
</String>
<String name='disposition'>
Calm
</String>
</Dog>
<Dog name='Della'>
<String name='breed'>
Collie Mix
</String>
<String name='color'>
Excitable
</String>
</Dog>
</node>
</cog>
Here is an example of the “Hello, World!” of dungeon maps:
Some code to create it - as with the Dogs example above, there are many ways to do it, but this is a reasonable approach:
room = new Cog();
room.setTypeName("Room");
info = room.add("Info", "info");
info.add("Dimensions", "dimensions");
info.putInt("dimensions/width", 10);
info.putInt("dimensions/length", 10);
info.putInt("dimensions/height", 10);
info.putString("smell", "Dank");
info.putString("description", "You've entered a 10x10 room. An orc guards a chest.");
monsters = room.add("List", "monsters");
monsters.add("Orc", null); // Nameless orc has no name.
treasure = room.add("List", "treasure");
treasure.add("Chest", null); // Chest is also nondescript.
And here’s the resulting XML:
<?xml version='1.0' encoding='utf-8'?>
<cog>
<Room>
<Info name='info'>
<Dimensions name='dimensions'>
<Integer name='width'>
10
</Integer>
<Integer name='length'>
10
</Integer>
<Integer name='height'>
10
</Integer>
</Dimensions>
<String name='smell'>
Dank
</String>
<String name='description'>
You've entered a 10x10 room. An orc guards a chest.
</String>
</Info>
<List name='monsters'>
<Orc>
</Orc>
</List>
<List name='treasure'>
<Chest>
</Chest>
</List>
</Room>
</cog>