fix up variables tutorial

This commit is contained in:
ThePhD 2018-11-09 14:36:27 -08:00
parent 091ca39438
commit a7048aea45
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
10 changed files with 187 additions and 232 deletions

8
docs/source/build.rst Normal file
View File

@ -0,0 +1,8 @@
Build
=====
sol2 comes with a CMake script in the top level. It is primarily made for building and running the examples and tests, but it includes exported and configured targets (``sol2``, ``sol2_single``) for your use.
sol2 also comes with a Meson Script. If things stop working, file a bug report.

View File

@ -1,61 +0,0 @@
CMake Script
============
sol2 comes with a CMake script in the top level. It is primarily made for building and running the examples and tests, but it includes exported and configured targets (``sol2``, ``sol2_single``) for your use. If you have any problems with it or its targets, please do file a report, or a pull request because CMake is not my forte.
.. warning::
The below is slightly outdated, but will probably still work for you!
Thanks to `Kevin Brightwell`_, you can drop this CMake Script into your CMake Projects to have Sol part of one of its builds:
.. code-block:: cmake
:caption: CMake Build Script
:name: cmake-build-script
# Needed for ExternalProject_Add()
include(ExternalProject)
# Needed for building single header for sol2
find_package(PythonInterp 3 REQUIRED)
# Configuration data for What sol2 version to use and where to put it
set(SOL2_TAG v2.5.6)
set(SOL2_HPP "${CMAKE_BINARY_DIR}/include/sol.hpp")
# Download and "install" sol2
ExternalProject_add(
sol2
PREFIX ${VENDOR_PATH} # Set this value yourself
GIT_REPOSITORY "https://github.com/ThePhD/sol2.git"
GIT_TAG ${SOL2_TAG}
# No CMake commands to run, so tell CMake not to configure
CONFIGURE_COMMAND ""
# Generate the single header and put it in ${SOL2_HPP}
BINARY_DIR ${VENDOR_PREFIX}/src/sol2
BUILD_COMMAND
${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include
COMMAND
${PYTHON_EXECUTABLE} ./single.py -o "${SOL2_HPP}"
# No install or test command for the library
INSTALL_COMMAND ""
TEST_COMMAND "")
# Conditionally turn on SOL_CHECK_ARGUMENTS if using Debug mode
if (CMAKE_BUILD_TYPE MATCHES "[Dd]ebug")
if (VERBOSE)
message(STATUS "Turning on SOL_CHECK_ARGUMENTS in Debug mode.")
endif()
add_definitions(-DSOL_CHECK_ARGUMENTS)
endif()
# Make sure sol2 is found as a system directory
include_directories(SYSTEM ${CMAKE_BINARY_DIR}/include)
.. _Kevin Brightwell: https://github.com/ThePhD/sol2/issues/89

View File

@ -57,7 +57,7 @@ author = 'ThePhD'
# The short X.Y version.
version = '2.20'
# The full version, including alpha/beta/rc tags.
release = '2.20.2'
release = '2.20.5'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -40,7 +40,7 @@ get going:
exceptions
rtti
codecvt
cmake
build
licenses
origin

View File

@ -6,7 +6,7 @@ Sol can register all kinds of functions. Many are shown in the :doc:`quick 'n' d
Setting a new function
----------------------
Given a C++ function, you can drop it into Sol in several equivalent ways, working similar to how :ref:`setting variables<writing-main-cpp>` works:
Given a C++ function, you can drop it into Sol in several equivalent ways, working similar to how :ref:`setting variables<writing-variables-demo>` works:
.. code-block:: cpp
:linenos:

View File

@ -1,112 +1,47 @@
variables
=========
Working with variables is easy with Sol, and behaves pretty much like any associative array / map structure you've dealt with previously. Given this lua file that gets loaded into Sol:
Working with variables is easy with sol, and behaves pretty much like any associative array / map structure you might have dealt with previously.
reading
-------
.. code-block:: lua
:caption: variables.lua
Given this lua file that gets loaded into sol:
config = {
fullscreen = false,
resolution = { x = 1024, y = 768 }
}
.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp
:linenos:
:lines: 15-18
.. code-block:: cpp
:caption: main.cpp
:name: variables-main-cpp
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
int main () {
sol::state lua;
lua.script_file( variables.lua );
return 0;
}
You can interact with the variables like this:
.. code-block:: cpp
:caption: main.cpp extended
:name: extended-variables-main-cpp
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <tuple>
#include <utility> // for std::pair
int main () {
sol::state lua;
lua.script_file( variables.lua );
// the type "state" behaves exactly like a table!
bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables
sol::table config = lua["config"];
// can also get it using the "get" member function
// auto replaces the unqualified type name
auto resolution = config.get<sol::table>( "resolution" );
// table and state can have multiple things pulled out of it too
std::pair<int, int> xyresolution = resolution.get<int, int>( "x", "y" );
// As an example, you can also pull out a tuple as well
std::tuple<int, int> xyresolutiontuple = resolution.get<int, int>( "x", "y" );
You can interact with the Lua Virtual Machine like so:
return 0;
}
.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp
:linenos:
:lines: 1-10, 12-12, 20-24, 70-
From this example, you can see that there's many ways to pull out the varaibles you want. For example, to determine if a nested variable exists or not, you can use ``auto`` to capture the value of a ``table[key]`` lookup, and then use the ``.valid()`` method:
.. code-block:: cpp
:caption: safe lookup
auto bark = lua["config"]["bark"];
if (bark.valid()) {
// branch not taken: config / bark is not a variable
}
else {
// Branch taken: config is a not a variable
}
.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp
:linenos:
:lines: 1-10, 12-12, 34-43, 70-
This comes in handy when you want to check if a nested variable exists. You can also check if a toplevel variable is present or not by using ``sol::optional``, which also checks if A) the keys you're going into exist and B) the type you're trying to get is of a specific type:
.. code-block:: cpp
.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp
:linenos:
:caption: optional lookup
:lines: 1-10, 12-12, 43-58, 70-
sol::optional<int> not_an_integer = lua["config"]["fullscreen"];
if (not_an_integer) {
// Branch not taken: value is not an integer
}
sol::optional<bool> is_a_boolean = lua["config"]["fullscreen"];
if (is_a_boolean) {
// Branch taken: the value is a boolean
}
sol::optional<double> does_not_exist = lua["not_a_variable"];
if (does_not_exist) {
// Branch not taken: that variable is not present
}
This can come in handy when, even in optimized or release modes, you still want the safety of checking. You can also use the `get_or` methods to, if a certain value may be present but you just want to default the value to something else:
.. code-block:: cpp
:caption: get_or lookup
.. literalinclude:: ../../../examples/tutorials/variables_demo.cpp
:linenos:
:caption: optional lookup
:lines: 1-10, 12-12, 60-
// this will result in a value of '24'
int is_defaulted = lua["config"]["fullscreen"].get_or( 24 );
// This will result in the value of the config, which is 'false'
bool is_not_defaulted = lua["config"]["fullscreen"];
That's all it takes to read variables!
@ -116,96 +51,20 @@ writing
Writing gets a lot simpler. Even without scripting a file or a string, you can read and write variables into lua as you please:
.. code-block:: cpp
:caption: main.cpp
:name: writing-main-cpp
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int main () {
sol::state lua;
// open those basic lua libraries again, like print() etc.
lua.open_libraries( sol::lib::base );
// value in the global table
lua["bark"] = 50;
// a table being created in the global table
lua["some_table"] = lua.create_table_with(
"key0", 24,
"key1", 25,
lua["bark"], "the key is 50 and this string is its value!"
);
// Run a plain ol' string of lua code
// Note you can interact with things set through Sol in C++ with lua!
// Using a "Raw String Literal" to have multi-line goodness: http://en.cppreference.com/w/cpp/language/string_literal
lua.script(R"(
print(some_table[50])
print(some_table["key0"])
print(some_table["key1"])
-- a lua comment: access a global in a lua script with the _G table
print(_G["bark"])
)");
return 0;
}
.. literalinclude:: ../../../examples/tutorials/write_variables_demo.cpp
:linenos:
:name: writing-variables-demo
This example pretty much sums up what can be done. Note that the syntax ``lua["non_existing_key_1"] = 1`` will make that variable, but if you tunnel too deep without first creating a table, the Lua API will panic (e.g., ``lua["does_not_exist"]["b"] = 20`` will trigger a panic). You can also be lazy with reading / writing values:
.. code-block:: cpp
:caption: main.cpp
:name: lazy-main-cpp
.. literalinclude:: ../../../examples/tutorials/lazy_demo.cpp
:linenos:
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int main () {
sol::state lua;
auto barkkey = lua["bark"];
if (barkkey.valid()) {
// Branch not taken: doesn't exist yet
std::cout << "How did you get in here, arf?!" << std::endl;
}
barkkey = 50;
if (barkkey.valid()) {
// Branch taken: value exists!
std::cout << "Bark Bjork Wan Wan Wan" << std::endl;
}
}
Finally, it's possible to erase a reference/variable by setting it to ``nil``, using the constant ``sol::nil`` in C++:
.. code-block:: cpp
:caption: main.cpp
:name: erase-main-cpp
.. literalinclude:: ../../../examples/tutorials/erase_demo.cpp
:linenos:
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
int main () {
sol::state lua;
lua["bark"] = 50;
sol::optional<int> x = lua["bark"];
// x will have a value
lua["bark"] = sol::nil;
sol::optional<int> y = lua["bark"];
// y will not have a value
}
It's easy to see that there's a lot of options to do what you want here. But, these are just traditional numbers and strings. What if we want more power, more capabilities than what these limited types can offer us? Let's throw some :doc:`functions in there<functions>` :doc:`C++ classes into the mix<cxx-in-lua>`!

View File

@ -0,0 +1,16 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
int main() {
sol::state lua;
lua["bark"] = 50;
sol::optional<int> x = lua["bark"];
// x will have a value
lua["bark"] = sol::nil;
sol::optional<int> y = lua["bark"];
// y will not have a value
return 0;
}

View File

@ -0,0 +1,23 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int main() {
sol::state lua;
auto barkkey = lua["bark"];
if (barkkey.valid()) {
// Branch not taken: doesn't exist yet
std::cout << "How did you get in here, arf?!" << std::endl;
}
barkkey = 50;
if (barkkey.valid()) {
// Branch taken: value exists!
std::cout << "Bark Bjork Wan Wan Wan" << std::endl;
}
return 0;
}

View File

@ -0,0 +1,71 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <tuple>
#include "../assert.hpp"
#include <utility> // for std::pair
int main() {
sol::state lua;
/*
lua.script_file("variables.lua");
*/
lua.script(R"(
config = {
fullscreen = false,
resolution = { x = 1024, y = 768 }
}
)");
// the type "sol::state" behaves
// exactly like a table!
bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables
sol::table config = lua["config"];
c_assert(isfullscreen);
// can also get it using the "get" member function
// auto replaces the unqualified type name
auto resolution = config.get<sol::table>("resolution");
// table and state can have multiple things pulled out of it too
std::tuple<int, int> xyresolutiontuple = resolution.get<int, int>("x", "y");
c_assert(std::get<0>(xyresolutiontuple) == 1024);
c_assert(std::get<1>(xyresolutiontuple) == 768);
// test variable
auto bark = lua["config"]["bark"];
if (bark.valid()) {
// branch not taken: config and/or bark are not variables
}
else {
// Branch taken: config and bark are existing variables
}
// can also use optional
sol::optional<int> not_an_integer = lua["config"]["fullscreen"];
if (not_an_integer) {
// Branch not taken: value is not an integer
}
sol::optional<bool> is_a_boolean = lua["config"]["fullscreen"];
if (is_a_boolean) {
// Branch taken: the value is a boolean
}
sol::optional<double> does_not_exist = lua["not_a_variable"];
if (does_not_exist) {
// Branch not taken: that variable is not present
}
// this will result in a value of '24'
// (it tries to get a number, and fullscreen is
// not a number
int is_defaulted = lua["config"]["fullscreen"].get_or(24);
c_assert(is_defaulted == 24);
// This will result in the value of the config, which is 'false'
bool is_not_defaulted = lua["config"]["fullscreen"];
c_assert(!is_not_defaulted);
return 0;
}

View File

@ -0,0 +1,39 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int main() {
sol::state lua;
// open those basic lua libraries
// again, for print() and other basic utilities
lua.open_libraries(sol::lib::base);
// value in the global table
lua["bark"] = 50;
// a table being created in the global table
lua["some_table"] = lua.create_table_with(
"key0", 24,
"key1", 25,
lua["bark"], "the key is 50 and this string is its value!");
// Run a plain ol' string of lua code
// Note you can interact with things set through Sol in C++ with lua!
// Using a "Raw String Literal" to have multi-line goodness:
// http://en.cppreference.com/w/cpp/language/string_literal
lua.script(R"(
print(some_table[50])
print(some_table["key0"])
print(some_table["key1"])
-- a lua comment: access a global in a lua script with the _G table
print(_G["bark"])
)");
return 0;
}