From 6b86fba5ef0ecc6afe64f4bf9c10428cb0f494b0 Mon Sep 17 00:00:00 2001 From: Jesse Beder Date: Sun, 29 Mar 2015 22:49:28 -0500 Subject: [PATCH] Copied Tutorial from Google Code wiki. --- Tutorial.md | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 Tutorial.md diff --git a/Tutorial.md b/Tutorial.md new file mode 100644 index 0000000..c83369a --- /dev/null +++ b/Tutorial.md @@ -0,0 +1,201 @@ +# Introduction # + +A typical example, loading a configuration file, might look like this: + +``` +YAML::Node config = YAML::LoadFile("config.yaml"); + +if (config["lastLogin"]) { + std::cout << "Last logged in: " << config["lastLogin"].as() << "\n"; +} + +const std::string username = config["username"].as(); +const std::string password = config["password"].as(); +login(username, password); +config["lastLogin"] = getCurrentDateTime(); + +std::ofstream fout("config.yaml"); +fout << config; +``` + +# Basic Parsing and Node Editing # + +All nodes in a YAML document (including the root) are represented by `YAML::Node`. You can check what kind it is: + +``` +YAML::Node node = YAML::Load("[1, 2, 3]"); +assert(node.Type() == YAML::NodeType::Sequence); +assert(node.IsSequence()); // a shortcut! +``` + +Collection nodes (sequences and maps) act somewhat like STL vectors and maps: + +``` +YAML::Node primes = YAML::Load("[2, 3, 5, 7, 11]"); +for (std::size_t i=0;i() << "\n"; +} +// or: +for (YAML::const_iterator it=primes.begin();it!=primes.end();++it) { + std::cout << it->as() << "\n"; +} + +primes.push_back(13); +assert(primes.size() == 6); +``` + +and + +``` +YAML::Node lineup = YAML::Load("{1B: Prince Fielder, 2B: Rickie Weeks, LF: Ryan Braun}"); +for(YAML::const_iterator it=lineup.begin();it!=lineup.end();++it) { + std::cout << "Playing at " << it->first.as() << " is " << it->second.as() << "\n"; +} + +lineup["RF"] = "Corey Hart"; +lineup["C"] = "Jonathan Lucroy"; +assert(lineup.size() == 5); +``` + +Querying for keys does **not** create them automatically (this makes handling optional map entries very easy) + +``` +YAML::Node node = YAML::Load("{name: Brewers, city: Milwaukee}"); +if (node["name"]) { + std::cout << node["name"].as() << "\n"; +} +if (node["mascot"]) { + std::cout << node["mascot"].as() << "\n"; +} +assert(node.size() == 2); // the previous call didn't create a node +``` + +If you're not sure what kind of data you're getting, you can query the type of a node: + +``` +switch (node.Type()) { + case Null: // ... + case Scalar: // ... + case Sequence: // ... + case Map: // ... + case Undefined: // ... +} +``` + +or ask directly whether it's a particular type, e.g.: + +``` +if (node.IsSequence()) { + // ... +} +``` + +# Building Nodes # + +You can build `YAML::Node` from scratch: + +``` +YAML::Node node; // starts out as null +node["key"] = "value"; // it now is a map node +node["seq"].push_back("first element"); // node["seq"] automatically becomes a sequence +node["seq"].push_back("second element"); + +node["mirror"] = node["seq"][0]; // this creates an alias +node["seq"][0] = "1st element"; // this also changes node["mirror"] +node["mirror"] = "element #1"; // and this changes node["seq"][0] - they're really the "same" node + +node["self"] = node; // you can even create self-aliases +node[node["mirror"]] = node["seq"]; // and strange loops :) +``` + +The above node is now: + +``` +&1 +key: value +&2 seq: [&3 "element #1", second element] +mirror: *3 +self: *1 +*3 : *2 +``` + +# How Sequences Turn Into Maps # + +Sequences can be turned into maps by asking for non-integer keys. For example, + +``` +YAML::Node node = YAML::Load("[1, 2, 3]"); +node[1] = 5; // still a sequence, [1, 5, 3] +node.push_back(-3) // still a sequence, [1, 5, 3, -3] +node["key"] = "value"; // now it's a map! {0: 1, 1: 5, 2: 3, 3: -3, key: value} +``` + +Indexing a sequence node by an index that's not in its range will _usually_ turn it into a map, but if the index is one past the end of the sequence, then the sequence will grow by one to accommodate it. (That's the **only** exception to this rule.) For example, + +``` +YAML::Node node = YAML::Load("[1, 2, 3]"); +node[3] = 4; // still a sequence, [1, 2, 3, 4] +node[10] = 10; // now it's a map! {0: 1, 1: 2, 2: 3, 3: 4, 10: 10} +``` + +# Converting To/From Native Data Types # + +Yaml-cpp has built-in conversion to and from most built-in data types, as well as `std::vector`, `std::list`, and `std::map`. The following examples demonstrate when those conversions are used: + +``` +YAML::Node node = YAML::Load("{pi: 3.14159, [0, 1]: integers}"); + +// this needs the conversion from Node to double +double pi = node["pi"].as(); + +// this needs the conversion from double to Node +node["e"] = 2.71828; + +// this needs the conversion from Node to std::vector (*not* the other way around!) +std::vector v; +v.push_back(0); +v.push_back(1); +std::string str = node[v].as(); +``` + +To use yaml-cpp with your own data types, you need to specialize the YAML::convert<> template class. For example, suppose you had a simple `Vec3` class: + +``` +struct Vec3 { double x, y, z; /* etc - make sure you have overloaded operator== */ }; +``` + +You could write + +``` +namespace YAML { +template<> +struct convert { + static Node encode(const Vec3& rhs) { + Node node; + node.push_back(rhs.x); + node.push_back(rhs.y); + node.push_back(rhs.z); + return node; + } + + static bool decode(const Node& node, Vec3& rhs) { + if(!node.IsSequence() || node.size() != 3) { + return false; + } + + rhs.x = node[0].as(); + rhs.y = node[1].as(); + rhs.z = node[2].as(); + return true; + } +}; +} +``` + +Then you could use `Vec3` wherever you could use any other type: + +``` +YAML::Node node = YAML::Load("start: [1, 3, 0]"); +Vec3 v = node["start"].as(); +node["end"] = Vec3(2, -1, 0); +``` \ No newline at end of file